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.
0 comments:
Post a Comment