Closed akshaydotsh closed 6 years ago
Hi @theakshaygupta , have you ever been able to resolve this? I'm running to exactly same issue :(
Hi @kittrCZ ,
It didn't work for the dummy project I was practicing but then in the main project, all I did was changed the
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
to:
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('JWT');
Also if you're logging in the user, you must be using jwt.sign()
to generate the token. After this step you're probably either storing the token somewhere or you're sending the token in response. Make sure that you're sending as such
token: 'JWT ' + token
I think using lowercase jwt
causes problems sometimes.
I don't know if this will work but that's all the change I could see in my previous code and earlier code. So it boils down to three things :
Check the extractor you are using. Sometimes weird discrepancies occur there
Check if you're appending the token with 'JWT' and not 'jwt'
There could also be a version issue. Check the version of passport-jwt, passport and jsonwebtoken for any changes or incompatibility
Let's discuss if you're still running into the same problem.
Thanks
This is pretty frustrating. I'm sure that I overlooked something, but I can't digest that the documented way is not working. Totally agree with your suggestions and have it implemented similarly, I have following:
passport.js
const passport = require('passport');
const passportJWT = require('passport-jwt');
const models = require('../models');
const LocalStrategy = require('passport-local').Strategy;
const ExtractJWT = require('passport-jwt').ExtractJwt;
const JWTStrategy = require('passport-jwt').Strategy;
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true,
}, async (req, username, password, done) => {
// this one is typically a DB call.
// Assume that the returned user object is pre-formatted and ready for storing in JWT
try {
const errMessage = { message: 'Incorrect email or password' };
const user = await models.user.findOne({
where: {
email: username,
},
});
if (!user) {
return done(null, false, errMessage);
}
const pwdValidation = await user.validPassword(password, user.password);
if (!pwdValidation) {
done(null, false, errMessage);
} else {
done(null, user, { message: 'Logged In Successfully' });
}
} catch (err) {
console.log(err);
done(err);
}
}));
const opts = {};
opts.jwtFromRequest = ExtractJWT.fromAuthHeaderWithScheme('JWT');
opts.secretOrKey = process.env.API_JWT_SECRET;
passport.use(new JWTStrategy(opts, async (jwtPayload, done) => {
console.log(jwtPayload);
try {
const user = await models.user.findOne({
where: {
email: jwtPayload.email,
},
});
if (user) {
return done(null, user);
}
return done(null, false);
} catch (e) {
console.log(e);
done(e);
}
}));
// In order to help keep authentication state across HTTP requests,
// Sequelize needs to serialize and deserialize the user
// Just consider this part boilerplate needed to make it all work
passport.serializeUser((user, cb) => {
cb(null, user.id);
});
passport.deserializeUser((id, cb) => {
models.user.findOne(id, (err, user) => {
cb(err, user);
});
});
route.js
router.get('/test', passport.authenticate('jwt', { session: false }), (req, res) =>{
const response = {
success: true,
};
return res.status(200).json(response);
});
package.json
"dependencies": {
"bcrypt": "^2.0.1",
"body-parser": "^1.18.2",
"connect-timeout": "^1.9.0",
"cors": "^2.8.4",
"express": "^4.16.3",
"express-rate-limit": "^2.11.0",
"jsonwebtoken": "^8.2.1",
"lodash": "^4.17.10",
"moment": "^2.22.1",
"nodemon": "^1.17.2",
"passport": "^0.4.0",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"response-time": "^2.3.2",
"sequelize": "^4.37.7",
"slugify": "^1.3.0",
"validator": "^10.2.0"
}
and this command does not work.
curl
$ curl -v -XGET -H 'Authorization:JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRAMi5jb20iLCJpYXQiOjE1MjcxNDk5NDEsImV4cCI6MTUyNzE0OTk0NH0.Y_6K15LpWycwJg_TZXjKh7JVUACYciuLqxR3VaI2xUw' 'http://localhost:4000/users/test'
Note: Unnecessary use of -X or --request, GET is already inferred.
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 4000 (#0)
> GET /users/test HTTP/1.1
> Host: localhost:4000
> User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
> Accept: */*
> Referer:
> Authorization:JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRAMi5jb20iLCJpYXQiOjE1MjcxNDk5NDEsImV4cCI6MTUyNzE0OTk0NH0.Y_6K15LpWycwJg_TZXjKh7JVUACYciuLqxR3VaI2xUw
>
< HTTP/1.1 401 Unauthorized
< Vary: Origin
< X-RateLimit-Limit: 100
< X-RateLimit-Remaining: 95
< X-Response-Time: 1008.037ms
< Date: Thu, 24 May 2018 08:20:44 GMT
< Connection: keep-alive
< Content-Length: 12
<
* Connection #0 to host localhost left intact
Unauthorized%
any clue @theakshaygupta , I stop believing that this package even works ^^
I assume your console.log(jwtPayload)
is not printing anything ?
@theakshaygupta no totally nothing. Everything gets instant 401 response
@kittrCZ Sorry, I am unable to figure out what is going wrong here. The only problem I can see here is that your token is expired. You could try to re create the token and provide it in the header. If it doesn't work, I hope someone more familiar to passport-jwt responds to this issue .
Cheers
so I figured out yesterday. The token was truly expired. I highly recommend to everyone to create a
testing endpoint with jwt.verify()
.
This issue ca be closed
@kittrCZ was your token testing endpoint included just after it was created? I'm facing the same issue but I'm not sure if I'm using it properly. Mine looks like this and it stands just before generating res.send
const token = jwt.sign(user, '4waNdqInzkWHwTs4BXXp9ZAsolK0EV75', {expiresIn: 86400 * 30});
jwt.verify(token, '4waNdqInzkWHwTs4BXXp9ZAsolK0EV75', function(err, data){
console.log(err, data);
})
return res.send({
message: 'Logged In Successfully!',
redirect: '/dashboard',
jwtToken: 'JWT ' + token,
success: true,
user: {
id: user.id,
name: user.user_name
}
});
Hi all, i'm still having this challenge after verification using jwt.verify(), token was successfully verified. Strangely, it didnt work let opts = {} opts.jwtFromRequest = req.headers.authorization.split(' ')[1]; opts.secretOrKey = process.env.JWT_TOKEN; opts.ignoreExpiration = true;
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
console.log('Now in middleware' ); //Not logging
User.findOne({_id: jwt_payload._id}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
}));
First, i have to fetch the token using a different method. Also, could someone tell me why i can't console.log in passport.use(...{...}).
Digging further, i did let pass = passport.use(...... console.log(pass); and i got this
{"_key":"passport","_strategies":{"session":{"name":"session"},"jwt":{"name":"jwt","_jwtFromRequest":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YjFkNmQwMWI5N2YxMTAxZDU4MDY1MmQiLCJmaXJzdE5hbWUiOiJoZWxvbyIsInJvbGUiOlsiUGF0aWVudCJdLCJleHAiOjE1Mjk0MDYxMjIsInNlY3JldE9yS2V5IjoiUkVTVEZVTEFQSXMiLCJpYXQiOjE1Mjg4MDEzMjJ9.KTminBQ8Mzi7IuKsjKjtWPSvYWevqHRW","_verifOpts":{"ignoreExpiration":true}}},"_serializers":[null],"_deserializers":[],"_infoTransformers":[],"_framework":{},"_userProperty":"user","_sm":{"_key":"passport"},"strategies":{}}
It actually got the data. Not really sure what is going on at this point again.
Any updates on this? It seems like the original poster had an expiration issue, but others like @arnasledev and @holumyn haven't found solutions.
Here's an update of my own: I wasn't setting issuer and audience claims correctly.
Mine problem was different secret keys on passport and verification of the login.
hey guys, i had the same problem and solved the problem by writing a little middleware
// passport.js
passport.use(new JWTStrategy({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.SERVERSECRET
}, (token, done) => {
return done(null, token);
}));
// router/index.js
/**
* middleware for checking authorization with jwt
*/
function authorized(request, response, next) {
passport.authenticate('jwt', { session: false, }, async (error, token) => {
if (error || !token) {
response.status(401).json({ message: 'Unauthorized' });
}
try {
const user = await User.findOne({
where: { id: token.id },
});
request.user = user;
} catch (error) {
next(error);
}
next();
})(request, response, next);
}
router.use('/user', authorized, userRouter);
// router/user.js
router.get('/', (request, response, next) => {
response.send(request.user);
});
and in my request i had to set Authorization: bearer
I had the same issue , it turned out when using ExtractJwt.fromAuthHeaderAsBearerToken() we have to send send the authorization header as bearer + token , although in the authentication for the route we write : passport.authenticate('jwt', { session: false, }, function()...etc.
this applies to the new version of passport where the original function ExtractJwt.fromAuthHeader() is not available anymore.
In case you are still stuck, follow the following link for resolution.
https://github.com/themikenicholson/passport-jwt/issues/117#issuecomment-464479145
I had the same issue . The imported model reference in one of the method in passport js file was not correct.After i correct that the problem solved
I am currently experiencing this issue SUDDENLY. I have been working on my app for two years and never had an issue and now suddenly I start getting an issue. All my routes that use passport.authenticate now no longer work.
I had the same issue , it turned out when using ExtractJwt.fromAuthHeaderAsBearerToken() we have to send send the authorization header as bearer + token , although in the authentication for the route we write : passport.authenticate('jwt', { session: false, }, function()...etc.
this applies to the new version of passport where the original function ExtractJwt.fromAuthHeader() is not available anymore.
This worked for me. Turns out that when using
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken()
You have to return "Bearer + token" and not "JWT + token". I did that and it worked for me. Deep sigh. Finally!
I am currently experiencing this issue SUDDENLY. I have been working on my app for two years and never had an issue and now suddenly I start getting an issue. All my routes that use passport.authenticate now no longer work.
Things have changed. For example, you can no longer use ExtractJwt.fromAuthHeader() function anymore. It is deprecated. Just compare your code with the latest examples, and you will have your app working again.
@EmmyMay Thanks EmmyMay. It would appear that I am experiencing a different issue and have raised it as such. https://github.com/mikenicholson/passport-jwt/issues/188
I had the same issue , it turned out when using ExtractJwt.fromAuthHeaderAsBearerToken() we have to send send the authorization header as bearer + token , although in the authentication for the route we write : passport.authenticate('jwt', { session: false, }, function()...etc. this applies to the new version of passport where the original function ExtractJwt.fromAuthHeader() is not available anymore.
This worked for me. Turns out that when using
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken()
You have to return "Bearer + token" and not "JWT + token". I did that and it worked for me. Deep sigh. Finally!
How do you set the header with the token then? Do you use res.set or something like it?
hey guys, i had the same problem and solved the problem by writing a little middleware
// passport.js passport.use(new JWTStrategy({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: process.env.SERVERSECRET }, (token, done) => { return done(null, token); }));
// router/index.js /** * middleware for checking authorization with jwt */ function authorized(request, response, next) { passport.authenticate('jwt', { session: false, }, async (error, token) => { if (error || !token) { response.status(401).json({ message: 'Unauthorized' }); } try { const user = await User.findOne({ where: { id: token.id }, }); request.user = user; } catch (error) { next(error); } next(); })(request, response, next); } router.use('/user', authorized, userRouter);
// router/user.js router.get('/', (request, response, next) => { response.send(request.user); });
and in my request i had to set Authorization: bearer
Please can you show how did you set your request with this "Authorization:bearer"?
Make sure the value you are using on the jwt.sign() is a number or if you are using process.env parse it to a number.
You have to return "Bearer + token" and not "JWT + token". Add bearer "token" in Authorization value
You have to return "Bearer + token" and not "JWT + token". Add bearer "token" in Authorization value
Yes... Look I have been struggling with it for more than three days... There is any code example on how to do the request to a protected route and send the header with these values? I have been able to do it on postman but not in my application. I would be really glad if I had an example on how to do it properly. The issue is adressed here https://github.com/mikenicholson/passport-jwt/issues/190
Having same issue. Just tried to test it and doesn't work
You have to return "Bearer + token" and not "JWT + token". Add bearer "token" in Authorization value
Wow, that worked surprisingly. How did you come to figure that out? I am just confused about how you came to have that information? Why was it changed from JWT to Bearer and was not mentioned in the documentation?
Why was it changed from JWT to Bearer and was not mentioned in the documentation?
It's mentioned here: https://github.com/mikenicholson/passport-jwt/blob/master/docs/migrating.md#migrating-from-2xx-to-3xx
Well after much investigation I believe I have found the source of my problem as well as a better understanding of how JWT works. The JWT seems to have gotten too large. My functioning user accounts have 6500 or fewer characters whilst my user accounts that no longer work are in the area of 8500. Now it's onto trying to figure out how to configure passport-jwt to only store a much smaller amount of data.
For me it was this code when logging in:
const token = jwt.sign(user.toJSON(), config.secret, { expiresIn: 604800 //1 week });
The problem was "user". I was saving the ENTIRE user document from mongodb which had quite a bit of data in it. Data that was completely unnecessary. So I created a new object with the data that I actually needed and created the JWT with that.
const userJWT = { user_id: user._id, full_name: user.full_name, username: user.username, email_address: user.email_address }; const token = jwt.sign(userJWT, config.secret, { expiresIn: 604800 //1 week });
I included images as the formatting of the code was not working as I wanted it to in the Github comment editor.
Well after much investigation I believe I have found the source of my problem as well as a better understanding of how JWT works. The JWT seems to have gotten too large. My functioning user accounts have 6500 or fewer characters whilst my user accounts that no longer work are in the area of 8500. Now it's onto trying to figure out how to configure passport-jwt to only store a much smaller amount of data.
For me it was this code when logging in:
const token = jwt.sign(user.toJSON(), config.secret, { expiresIn: 604800 //1 week });
The problem was "user". I was saving the ENTIRE user document from mongodb which had quite a bit of data in it. Data that was completely unnecessary. So I created a new object with the data that I actually needed and created the JWT with that.
const userJWT = { user_id: user._id, full_name: user.full_name, username: user.username, email_address: user.email_address }; const token = jwt.sign(userJWT, config.secret, { expiresIn: 604800 //1 week });
I included images as the formatting of the code was not working as I wanted it to in the Github comment editor.
a little off topic but JWT should not store all your information like names, email address etc as JWT can be decoded by anybody. You wouldn't want anybody to know the ownership of the token, it's a security risk.
You should just store non-sensitive information e.g. userid.
The userid can then be used to retrieve information from your DB without again verifying that userid and password matches.
@daveteu Thanks!
If you are following the documentation for NestJS, something seems to have been left out. Kindly make sure that you are also passing the secret during signing. I have mine in my .env file, thus the code snippet below:
return { access_token: this.jwtService.sign(payload, {secret:
${process.env.SECRET}}), };
Hi all, I have been facing the same issue lately . Here's a detailed description of my issue. Someone, please help me out ..https://stackoverflow.com/questions/66091341/jwt-authentication-failed?noredirect=1#comment117182238_66091341
hey guys, i had the same problem and solved the problem by writing a little middleware
// passport.js passport.use(new JWTStrategy({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: process.env.SERVERSECRET }, (token, done) => { return done(null, token); }));
// router/index.js /** * middleware for checking authorization with jwt */ function authorized(request, response, next) { passport.authenticate('jwt', { session: false, }, async (error, token) => { if (error || !token) { response.status(401).json({ message: 'Unauthorized' }); } try { const user = await User.findOne({ where: { id: token.id }, }); request.user = user; } catch (error) { next(error); } next(); })(request, response, next); } router.use('/user', authorized, userRouter);
// router/user.js router.get('/', (request, response, next) => { response.send(request.user); });
and in my request i had to set Authorization: bearer
Thx you
hi my jwt is not getting called even my console.log({ jwt_payload }); is not getting called i have spent lot of time to correct it but cant find the error somebody pls
const express = require('express'); const server = express(); const mongoose = require('mongoose'); const cors = require('cors'); const session = require('express-session'); const passport = require('passport'); const LocalStrategy = require('passport-local').Strategy; const crypto = require('crypto'); const jwt = require('jsonwebtoken'); const JwtStrategy = require('passport-jwt').Strategy; const ExtractJwt = require('passport-jwt').ExtractJwt; const { createProduct } = require('./controller/Product'); const productsRouter = require('./routes/Products'); const categoriesRouter = require('./routes/Category'); const brandsRouter = require('./routes/Brands'); const usersRouter = require('./routes/User'); const authRouter = require('./routes/Auth'); const cartRouter = require('./routes/Cart'); const ordersRouter = require('./routes/Order'); const { User } = require('./model/user'); const { isAuth, sanitizeUser } = require('./services/common'); const port=8080;
const SECRET_KEY = 'SECRET_KEY'; // JWT options const opts = {}; opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); opts.secretOrKey = SECRET_KEY; // TODO: should not be in code;
//middlewares
server.use( session({ secret: 'keyboard cat', resave: false, // don't save session if unmodified saveUninitialized: false, // don't create session until something stored }) ); server.use(passport.authenticate('session')); server.use( cors({ exposedHeaders: ['X-Total-Count'], }) ); server.use(express.json()); // to parse req.body server.use('/products', isAuth(), productsRouter.router); // we can also use JWT token for client-only auth server.use('/categories', isAuth(), categoriesRouter.router); server.use('/brands', isAuth(), brandsRouter.router); server.use('/users', isAuth(), usersRouter.router); server.use('/auth', authRouter.router); server.use('/cart', isAuth(), cartRouter.router); server.use('/orders', isAuth(), ordersRouter.router);
// Passport Strategies passport.use( 'local', new LocalStrategy(async function (username, password, done) { // by default passport uses username try { const user = await User.findOne({ email: username }); console.log(username, password, user); if (!user) { return done(null, false, { message: 'invalid credentials' }); // for safety } crypto.pbkdf2( password, user.salt, 310000, 32, 'sha256', async function (err, hashedPassword) { if (!crypto.timingSafeEqual(user.password, hashedPassword)) { return done(null, false, { message: 'invalid credentials' }); } const token = jwt.sign(sanitizeUser(user), SECRET_KEY); done(null, token); // this lines sends to serializer } ); } catch (err) { done(err); } }) );
passport.use( 'jwt', new JwtStrategy(opts, async function (jwt_payload, done) { console.log({ jwt_payload }); try { const user = await User.findOne({ id: jwt_payload.sub }); if (user) { return done(null, sanitizeUser(user)); // this calls serializer } else { return done(null, false); } } catch (err) { return done(err, false); } }) );
// this creates session variable req.user on being called from callbacks passport.serializeUser(function (user, cb) { console.log('serialize', user); process.nextTick(function () { return cb(null, { id: user.id, role: user.role }); }); });
// this changes session variable req.user when called from authorized request
passport.deserializeUser(function (user, cb) { console.log('de-serialize', user); process.nextTick(function () { return cb(null, user); }); });
const mongoURI="mongodb://0.0.0.0/ecommerce"
mongoose.connect(mongoURI)
const conn=mongoose.connection
conn.once('open',()=>{
console.log('successfullly connected to database')
})
conn.once('error',(error)=>{
console.log(failed to connected to database${error.message}
)
})
server.listen(port, () => {
console.log(Ecommerce backend listening at http://localhost:${port}
)
})
as @roshen1234 wrote it seems like i have a similar problem -> https://stackoverflow.com/questions/77963421/express-routing-not-working-anymore-after-update#comment137445464_77963421
Hello, I was trying to authenticate with passport JWTStrategy
passport-oauth.js :
If you see my two console.log() functions, the control never comes to passport.use(new JWTStrategy...
I am authenticating here :
I used postman to send my request :
As you can see I provided the authentication header too , and I am getting this error Could not get a response . If anyone could please tell me what's wrong, I've been at it since hours.
Thanks.