I am using JWT to do authentication with a user in my express app. One of the routes needs to be authenticated before continuing so I am doing so like this per following the documentation and a tutorial:
router.post('/current/update', passport.authenticate('jwt', { session: false }),(res, req) => {
console.log(req.body) //undefined
}
passport.js
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const mongoose = require('mongoose');
const Account = mongoose.model('accounts')
const keys = require('./keys');
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;
module.exports = passport => {
passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
Account.findById(jwt_payload.id)
.then(account => {
if(account){
return done(null, account)
}
return done(null, false)
}).catch(err => {
console.log(err)
return done(err)
})
})
);
};
Not knowing how to get access to the body of the request is troubling because that means I don't know how to get access to the req.params and req.query. I have tried numerous methods, including passing the req along with the strategy:
new JwtStrategy(opts, (req, jwt_payload, done) => ...
So question is, if not gotten from above, is how do I get access to the req object, other than just req.userso that I am able to handle parameterized URLs and queries?
You need to tell the JwtStrategy to pass the req object to your callback. You can do this via the options object you supply to the strategy. Your code will look something like this:
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;
opts.passReqToCallback = true; // New option!
Then in your callback function you'll need to also accept the req field which comes in as the first argument to the function. So your callback initialisation goes from
new JwtStrategy(opts, (jwt_payload, done)
and becomes
new JwtStrategy(opts, (req, jwt_payload, done)
You can then access the full express request object via req. As noted in the comments, you'll also need something like body-parser to ensure it's decoded properly.
Related
I am currently learning to make API, so the last part I need to learn is JWT token verification to authorise routes.
My authentication is working fine, but I need to pass the response user's data with it.
The code which I have tried has some bug that I cannot understand, but I think I messed up with async await part.
When I am calling User.findById(jwt_payload.user._id) I must get the user's data, currently I am getting null. I am stuck on that part with no clue to solve it.
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const { User } = require('../models/user');
const config = require('../config/database');
module.exports = async function(passport){
let opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('jwt');
opts.secretOrKey = config.secret;
passport.use(new JwtStrategy(opts, async function(jwt_payload, done){
//console.log(jwt_payload.user._id);
const user = await User.findById(jwt_payload.user._id);
//console.log(user);
if(user){
return done(null,user);
}
else{
return done(null,false);
}
}));
}
I would appreciate if someone helps me understand the part of error I have made
I've been trying to test the protected routes by using passport and passport-jwt.
I've got it to the point where the token is being generated when a user tries to log in and tested it in Postman.
I've created a route and passed in as an argument passport.authenticate with the jwt strategy and am getting errors all over the place.
In my main server.js, I require passport:
passport = require('passport');
app.use(passport.initialize());
// passport config
require('./config/passport')(passport);
My folder structure is this:
in my passport config file, i have this:
const jwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const mongoose = require('mongoose');
const User = mongoose.model('users')
const keys = require('../config/keys');
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;
module.export = passport => {
passport.use(
new jwtStrategy(opts, (jwt_payload, done) => {
console.log(jwt_payload);
}));
};
And my route is this:
// #route get to /users/current
// #desc: return the current user (who the jwt token belongs to)
// #access: should be public
router.get('/current',
passport.authenticate('jwt', { session: false }),
(req, res) => {
res.json({msg: "Success"})
}
);
The first error I can't seem to get passed is this in the console:
require('./config/passport')(passport);
^
TypeError: require(...) is not a function
In postman, when I try to go to /users/current and pass in a confirmed bearer token, I get this:
Error: Unknown authentication strategy "jwt" at attempt
in passport config file
you have typo module.export actualy its module.exports
thats why after require it does not recongnizing it as function
change the module.export to
module.exports = passport => {
passport.use(
new jwtStrategy(opts, (jwt_payload, done) => {
console.log(jwt_payload);
}));
};
its module.exports and not module.export.
The module.exports property can be assigned a new value (such as a function or object).
module.exports = class Square {
constructor(width) {
this.width = width;
}
area() {
return this.width ** 2;
}
};
nodejs modules documentation reference
I'm having trouble authenticating with passportjs and jwt. I'm sending an authorization header in a get request and reciveve an Unauthorized response. My first thought was that I'm probably messing up something with the token, so I'm trying to log the jwt_payload.
It seems to me like passport.authenticate() does not even run any of the code in my passport.js file, as console.log(jwt_payload) below never logs anything
/config/passport.js
module.exports = function(passport) {
let opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secret;
passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
console.log(jwt_payload);
User.getUserById(jwt_payload._id, (err, user) => {
if(err){
return done(err,false);
}
if(user){
return done(null,user);
} else {
return done(null, false);
}
});
}));
}
The passport.use(...) clause above must however be doing something, if i remove it i get an error of Unknown authentication strategy "jwt"
Below is the code for my passport setup and passport.authenticate() call.
/routes/users.js
const passport = require('passport');
const jwt = require('jsonwebtoken');
const config = require('../config/database');
router.get('/profile', passport.authenticate('jwt', {session:false}), (req, res, next) => {
res.json({user: req.user});
});
app.js
const passport = require('passport');
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
I'm New to node js. I'm using passport jwt for authentication. When i tried to authenticate, its always showing "unauthorized".
my passport.js file
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const User = require('../models/user');
const config = require('../config/database');
module.exports = function(passport){
let opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secret;
passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
User.getUserById(jwt_payload._doc._id, (err, user) => {
if(err){
return done(err, false);
}
if(user){
return done(null, user);
} else {
return done(null, false);
}
});
}));
}
user model user.js
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
routes
router.get('/profile', passport.authenticate('jwt', {session:false}), (req, res, next) => {
res.json({user: req.user});
});
When I google it many suggested to change this line in passport.js
User.getUserById(jwt_payload._doc._id, (err, user) => {
I tried with
User.getUserById(jwt_payload._id, (err, user) => {
User.findById(jwt_payload._id, (err, user) => {
still now i'm getting this same error.
I found out the issue,
In new passport-jwt updates, we have to use
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('jwt');
if you are using opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); as your jwtFromRequest then your Authorization header is like
bearer xxxxx.yyyyy.zzzzz
you can check the BEARER_AUTH_SCHEME specified in the extract_jwt.js located in the passport-jwt/lib folder
if you are using opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('jwt') as your jwtFromRequest then your Authorization header is like
JWT xxxxx.yyyyy.zzzzz
you can check the LEGACY_AUTH_SCHEME specified in the extract_jwt.js located in the passport-jwt/lib folder
I'm getting a warning message in my console everytime I'm hitting a route that requires authentication.
(node:940) Warning: a promise was created in a handler at xxxxxx\app\config\passport.js:15:19 but was not returned from it, see http://bluebirdjs.com/docs/warning-explanations.html#warning-a-promise-was-created-in-a-handler-but-was-not-returned-from-it
at .fetch (xxxxxx\node_modules\bluebird\js\release\method.js:13:13)
I've configured passport like this:
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const secret = process.env.SECRET;
var opts = {}
function passportConfig(db, passport) {
opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
opts.secretOrKey = secret;
passport.use(new JwtStrategy(opts, payloadCallback.bind(null, db)));
}
function payloadCallback(db, payload, done) {
new db.User({id: payload}).fetch()
.then(response => response.toJSON())
.then(user => done(null, user))
.catch(err => console.log(err));
}
module.exports = passportConfig;
Any help would be appreciated.
I fixed this warning by replacing the second then and catch with .asCallback(done).
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const secret = process.env.SECRET;
var opts = {}
function passportConfig(db, passport) {
opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
opts.secretOrKey = secret;
passport.use(new JwtStrategy(opts, payloadCallback.bind(null, db)));
}
function payloadCallback(db, payload, done) {
new db.User({id: payload}).fetch()
.then(response => response.toJSON())
.asCallback(done);
}
module.exports = passportConfig;