Monday, August 27, 2018

Passport JWT authentication extract token

Leave a Comment

I am using express & jwt-simple to handle login/register & authenticated requests as a middleware api. I'm trying to create a .well-known endpoint so other api's can authenticate request based on token send in.

Here's my strategy:

module.exports = function() {     const opts = {};     opts.jwtFromRequest = ExtractJwt.fromAuthHeader();     opts.secretOrKey = securityConfig.jwtSecret;     passport.use(new JwtStrategy(opts, function(jwt_payload, done) {         // User.where('id', jwt_payload.id).fetch({withRelated: 'roles'})         console.log('jwt_payload', jwt_payload)             User.where('id', jwt_payload.id).fetch()             .then(user => user ? done(null, user) : done(null, false))             .catch(err => done(err, false));     })); }; 

Here's my login route:

router.post('/login', function(req, res) {     const {username, password} = req.body;     Promise.coroutine(function* () {         const user = yield User.where('username', username).fetch();      if(user) {         const isValidPassword = yield user.validPassword(password);         if (isValidPassword) {             let expires = (Date.now() / 1000) + 60 * 30             let nbf = Date.now() / 1000             const validatedUser = user.omit('password');              // TODO: Verify that the encoding is legit..             // const token = jwt.encode(user.omit('password'), securityConfig.jwtSecret);             const token = jwt.encode({ nbf: nbf, exp: expires, id: validatedUser.id, orgId: validatedUser.orgId }, securityConfig.jwtSecret)             res.json({success: true, token: `JWT ${token}`, expires_in: expires});         } else {             res.status(401);             res.json({success: false, msg: 'Authentication failed'});         }     } else {         res.status(401);         res.json({success: false, msg: 'Authentication failed'});     }     })().catch(err => console.log(err)); }); 

Here's my .well-known route:

router.get('/.well-known', jwtAuth, function(req, res) {     // TODO: look over res.req.user. Don't seem to be the way to get those parameters.     // We dont take those parameters from the decrypted JWT, we seem to grab it from the user in DB.     const { id, orgId } = res.req.user.attributes;     console.log("DEBUG: userId", id)     console.log("DEBUG: USER", res.req.user)     res.json({         success: true,         userId: id,         orgId     }); }); 

here's my jwtAuth() function:

const passport = require('passport'); module.exports = passport.authenticate('jwt', { session: false }); 

How would I actually get the token in the route function & decrypt it? All this does right now which works is that it authenticates if true however I need to be able to decrypt the token to send back the stored values. I'm not sure what res.req.user.attributes comes from, is this the token?

1 Answers

Answers 1

Take a look at passport-jwt and in your passport-config (or wherever you initialize passport) setup JWT Strategy:

const JwtStrategy = require('passport-jwt').Strategy; const ExtractJwt = require('passport-jwt').ExtractJwt;  const jwtAuth = (payload, done) => {  const user = //....find User in DB, fetch roles, additional data or whatever  // do whatever with decoded payload and call done  // if everything is OK, call  done(null, user);  //whatever you pass back as "user" object will be available in route handler as req.user   //if your user does not authenticate or anything call  done(null, false); }  const apiJwtOptions: any = {}; apiJwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); apiJwtOptions.algorithms = [your.jwt.alg]; apiJwtOptions.secretOrKey = your.jwt.secret; //apiJwtOptions.issuer = ???; //apiJwtOptions.audience = ???; passport.use('jwt-api', new JwtStrategy(apiJwtOptions, jwtAuth)); 

If you want just decoded token, call done(null, payload) in jwtAuth.

Then in your route files when you want to protect endpoints and have info about user, use as:

const router = express.Router(); router.use(passport.authenticate('jwt-api', {session: false})); 

And in handler you should have req.user available. It is configurable to what property of req you store data from auth, req.user is just default.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment