Im currently working with NodeJS Express in typescript and I am stuck with my rest api where im trying to implement passport-ldap and passport-jwt. (ldap for the login and after that i only want to authorize with jwt tokens) The problem is i have no idea how to set up the authorizationChecker with passport.authenticate().
So my question would be is it even possible, if yes then how?
Just mount passport.authenticate() as the normal global midddleware (or per controller/action with @UseBefore) and check the action.request.user property (equivalent of req.user in express) inside authorizationChecker with your auth&roles logic.
Passport.js is designed to work well in traditional express apps, however in routing-controllers we have features like authorizationChecker built-in so you might not need this at all 馃槈
Thank you, @Usebefore works perfectly with it
@Funnybanny Hi, could you give an example on the middleware for passport authentication? Thanks very much.
@Yaojian - I had the same question, here's how I did it. Note that I'm using jwt authentication but you can just replace that with whatever your strategy is.
import * as express from 'express';
import * as passport from 'passport';
import { ExpressMiddlewareInterface, UnauthorizedError } from 'routing-controllers';
import { Logger, ILoggerInterface } from '../../decorators/logger';
export class JWTMiddleware implements ExpressMiddlewareInterface {
constructor(
@Logger(__filename) private log: ILoggerInterface
) { }
// tslint:disable-next-line
authenticate = (callback) => passport.authenticate('jwt', { session: false }, callback);
use(req: express.Request, res: express.Response, next: express.NextFunction): Promise<passport.Authenticator> {
return this.authenticate((err, user, info) => {
if (err || !user) {
this.log.info('Unauthorized access');
this.log.info(info);
return next(new UnauthorizedError(info));
}
req.user = user;
return next();
})(req, res, next);
}
}
The reason why I wrapped passport.authenticate was so I could easily mock it in my unit test:
it('should assign user if token is valid', () => {
middleware.authenticate = jest.fn((callback) => {
return () => {
const err = undefined;
const user = 'user';
const info = undefined;
return callback(err, user, info);
};
});
const req = new MockExpressRequest({
headers: {
Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJuYy5zZXJ2aWNlIiwiaWF0IjoxNTIwOTY1ODQ1LCJleHAiOjE1MjA5NjY0NDUsInR5cGUiOiJJTlRFUk5BTCIsInVzZXIiOnsic3ViIjoiZGV2LnVzZXIifSwiaWQiOiIxNTJDNjZBMS1EOTRBLTQ5QjItQUVGQi03QjE3QTlEQkFERjUifQ.yRJLtPWJVXLCNcG33hstp_5lMFFyscOSDEZIEKuLD38'
}
});
const next = (err) => {
expect(err).toBeUndefined();
expect(req.user).toEqual('user');
};
middleware.use(req, res, next);
});
Just mount
passport.authenticate()as the normal global midddleware (or per controller/action with@UseBefore) and check theaction.request.userproperty (equivalent ofreq.userin express) insideauthorizationCheckerwith your auth&roles logic.Passport.js is designed to work well in traditional express apps, however in
routing-controllerswe have features like authorizationChecker built-in so you might not need this at all 馃槈
Hi @19majkel94, thank you for the information. What about support for OAuth providers, like facebook / google?
@gruckion Hi. OAuth using google
export class Authenticate implements ExpressMiddlewareInterface {
use(req: Request, res: Response, next?: (err?: any) => any): any {
passport.authenticate("google", { scope: ["https://www.googleapis.com/auth/userinfo.email"] })(req, res, next);
}
}
export class GoogleAuthentication implements ExpressMiddlewareInterface {
authenticate = (callback) => passport.authenticate("google", { failureRedirect: "/login", session: false }, callback);
use(req: Request, res: Response, next?: (err?: any) => any): any {
return this.authenticate((err, user, info) => {
if (err || !user) {
return next(new UnauthorizedError(info));
}
req.user = user;
return next();
})(req, res, next);
}
}
@Controller("/auth")
export class AuthController {
@Get("/google")
@UseBefore(Authenticate)
// eslint-disable-next-line @typescript-eslint/no-empty-function
login() {}
@Get("/google/redirect")
@UseBefore(GoogleAuthentication)
authenticate(@Req() req: Request, @Res() res: Response) {
const token = "asda123sasd";
res.redirect(`/?token=${token}`);
}
}
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
@Yaojian - I had the same question, here's how I did it. Note that I'm using jwt authentication but you can just replace that with whatever your strategy is.
The reason why I wrapped
passport.authenticatewas so I could easily mock it in my unit test: