Closed viglucci closed 6 years ago
Many others have had this question. See here: https://github.com/nestjs/nest/issues?q=is%3Aissue+passport+is%3Aclosed
There's also a passport example in this repository.
Hi @wbhob thanks for getting back to me, I'll take a look closer look at the existing issues that you linked to see if I can find what I'm looking for.
In reference to the existing passport example, I called that out in my OP and found it helpful for some parts of the integration, but it didn't cover my use case of needing to initialize passport
and session
with express.
...the current passport recipe and example only cover JWT, which is likely not a common passport use case, and does not cover some of the more complex implementation details such as how to interact with the underlying express object.
My advice would be to put your initialization in its own middleware, and pass that in before your main passport middleware.
In this context, are you referencing a middleware as it is defined by nest?
Creating the below nest middleware that returns passport.initialize()
that would normally be passed to app.use(passport.initialize())
, we can see that in the below screenshot that the middleware is initialized after the AuthModule, and I believe that is why I receive a passport.initialize() middleware is not in use
error.
How can I ensure that the passport.initialize()
is middleware applied before the modules passed to the @Module
decorator?
import { Middleware, NestMiddleware, ExpressMiddleware } from "@nestjs/common";
import * as passport from "passport";
@Middleware()
export class PassportInitializationMiddleware implements NestMiddleware {
resolve(...args: any[]): ExpressMiddleware {
console.log("PassportInitializationMiddleware");
return passport.initialize();
}
}
import { Module, NestModule, MiddlewaresConsumer, RequestMethod } from "@nestjs/common";
import { AppController } from "./app.controller";
import { AuthModule } from "./auth/auth.module";
import { OAuthModule } from "./oauth/oauth.module";
import { RequestLoggerMiddleware } from "../middleware/RequestLogger.middleware";
import { PassportInitializationMiddleware } from "../middleware/PassportInitialization.middleware";
import * as passport from "passport";
@Module({
modules: [AuthModule, OAuthModule],
controllers: [AppController],
components: [],
})
export class ApplicationModule implements NestModule {
configure(consumer: MiddlewaresConsumer): void {
consumer.apply(PassportInitializationMiddleware).forRoutes({ path: "*", method: RequestMethod.ALL });
consumer.apply(RequestLoggerMiddleware).forRoutes({ path: "*", method: RequestMethod.ALL });
}
}
Error: passport.initialize() middleware not in use
at SessionStrategy.authenticate (E:\dev\nestjs-poc\node_modules\passport\lib\strategies\session.js:45:43)
at attempt (E:\dev\nestjs-poc\node_modules\passport\lib\middleware\authenticate.js:361:16)
at authenticate (E:\dev\nestjs-poc\node_modules\passport\lib\middleware\authenticate.js:362:7)
at Layer.handle [as handle_request] (E:\dev\nestjs-poc\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (E:\dev\nestjs-poc\node_modules\express\lib\router\index.js:317:13)
at E:\dev\nestjs-poc\node_modules\express\lib\router\index.js:284:7
at Function.process_params (E:\dev\nestjs-poc\node_modules\express\lib\router\index.js:335:12)
at next (E:\dev\nestjs-poc\node_modules\express\lib\router\index.js:275:10)
at session (E:\dev\nestjs-poc\node_modules\express-session\index.js:454:7)
at Layer.handle [as handle_request] (E:\dev\nestjs-poc\node_modules\express\lib\router\layer.js:95:5)
Again, thanks for your time.
Thanks for your help @wbhob. Based on your last suggestions about using middleware, I was able to get this working by moving all of the required middlewares to auth.module.ts
and registering newly created middlewares for each express middleware that is required.
import * as passport from "passport";
import {
Module,
NestModule,
MiddlewaresConsumer,
RequestMethod,
} from "@nestjs/common";
import { BattlenetStrategy } from "./passport/strategy/battlenet.strategy";
import { AuthController } from "./auth.controller";
import { PassportInitializationMiddleware } from "../../middleware/PassportInitialization.middleware";
import { SessionInitializationMiddleware } from "../../middleware/SessionInitialization.middleware";
import { PassportSessionInitializationMiddleware } from "../../middleware/PassportSessionInitialization.middleware";
@Module({
components: [BattlenetStrategy],
controllers: [AuthController],
})
export class AuthModule implements NestModule {
public configure(consumer: MiddlewaresConsumer) {
consumer.apply(SessionInitializationMiddleware).forRoutes({ path: "*", method: RequestMethod.ALL });
consumer.apply(PassportInitializationMiddleware).forRoutes({ path: "*", method: RequestMethod.ALL });
consumer.apply(PassportSessionInitializationMiddleware).forRoutes({ path: "*", method: RequestMethod.ALL });
}
}
import { Middleware, NestMiddleware, ExpressMiddleware } from "@nestjs/common";
import * as passport from "passport";
@Middleware()
export class PassportInitializationMiddleware implements NestMiddleware {
resolve(...args: any[]): ExpressMiddleware {
console.log("PassportInitializationMiddleware initialized");
return passport.initialize();
}
}
import { Middleware, NestMiddleware, ExpressMiddleware } from "@nestjs/common";
import * as passport from "passport";
import * as session from "express-session";
@Middleware()
export class PassportSessionInitializationMiddleware implements NestMiddleware {
resolve(...args: any[]): ExpressMiddleware {
console.log("PassportSessionInitializationMiddleware initialized");
return passport.session();
}
}
import { Middleware, NestMiddleware, ExpressMiddleware } from "@nestjs/common";
import * as passport from "passport";
import * as session from "express-session";
@Middleware()
export class SessionInitializationMiddleware implements NestMiddleware {
resolve(...args: any[]): ExpressMiddleware {
console.log("SessionInitializationMiddleware initialized");
return session({
secret: "12345",
saveUninitialized: false,
resave: true
});
}
}
import { NestFactory } from "@nestjs/core";
import { ApplicationModule } from "./modules/app.module";
import * as express from "express";
import * as cookieParser from "cookie-parser";
function expressFactory () {
const app = express();
// TODO: move cookieParser() to middleware
app.use(cookieParser());
return app;
}
async function bootstrap() {
const server = await NestFactory.create(ApplicationModule, expressFactory());
await server.listen(3000);
}
bootstrap();
Glad it worked out!
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
I'm submitting a question / documentation / education request...
Current behavior
When integrating with authentication libraries such as passport there are setup middlewares that must first be initialized and registered with the underlying express instance, however, there doesn't seem to be a clean way to access the express instance once
NestFactory.create(ApplicationModule, ...)
is called. To overcome this, you are able to pass an instance ofexpress
toNestFactory.create(ApplicationModule, app)
, but from a code structure perspective, this is not ideal as your application configuration logic is now distributed between inside and outside of the nestjs application context.Expected behavior
I would expect to be able to register a module or configuration component that would be able to access the underlying express application so that I can apply additional middlewares, such as
passport.initialize()
.Environment
Additional Information
If this is already possible I would love to know what the best way to accomplish this is. I would also be happy to submit a PR against the examples to include an application that uses passport to integrate with social platforms such as Facebook, Github, and or Blizzard Battlenet, as the current passport recipe and example only cover JWT, which is likely not a common passport use case, and does not cover some of the more complex implementation details such as how to interact with the underlying
express
object.Thanks for your time!