Closed mmchougule closed 5 years ago
Probably a silly question but what <type>
do you have set in your Authorization
header? Your header should look like:
Authorization: JWT <token>
My header values look like this: authorization:jwt eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkpSY080bnhzNWpnYzhZZE43STJoTE80...........
@mmchougule It may not be the same situation but my Authorization header type was case sensitive. You are receiving lower case, I am having to use upper case, therefore my request looks like this:
Authorization: JWT <token>
Today I tried to use passport-jwt(version: 2.2.1), passport(version:0.1.3) and jsonwebtoken(version:7.4.1) to config the jwt authorization. When I sent the GET request, the response was always Unauthorized. I followed all the instructions and spent about two hours on this problem, it wasn't resolved. So I tried another jwt passport middleware called passport-http-jwt-bearer, it works fine. I don't know the reason. Maybe it has some compatibility issues with the latest packages. Here is my demo
Me too, parse from body is fine.
@AlexQianjin can you provide a succinct demo that demonstrates the issue - something thatI could just curl a single endpoint and debug?
@themikenicholson I forgot how I met that problem. So I tried to reproduce it following the tutorial link mentioned by @mmchougule. It works fine and here is my succinct demo. Thanks for your reply!
If I follow the code from that tutorial then it works fine. We are generating JWT token ourselves with the username and password in that. My case is that I have the RS256 signed JWT token from an OpenID Connect provider and when I send it over to my express code, the JwtStrategy code doesn't get triggered in this case. I just wrote similar middleware code without using the passport strategy and it works now.
i face with the same issue, the callback for jwt not reach. It's look like it can not read the header. Here is the code:
const jwtOptions = {
jwtFromRequest: ExtractJwt.fromHeader('authorization'),
secretOrKey: process.env.APP_KEY || DEFAULT_SECRECT
}
const jwtLogin = new JwtStrategy(jwtOptions, function(payload, done) {
console.log(payload);
User.findById(payload._id, function(err, _user) {
if (err) return done(err, false);
if (_user) {
done(null, _user);
} else {
done(null, false);
}
});
});
passport.use(jwtLogin);
passport.use(localLogin);
and in route:
var express = require('express'),
passport = require('passport');
require('../config/passport');
var user_controller = require('../controllers/userController');
const authMiddware = passport.authenticate('jwt', { session: false });
const router = express.Router();
router.use(authMiddware);
router.get('/users', function(req, res, next) {
console.log(req.get('Authorization'));
res.send('huh?');
});
module.exports = router;
here my full code https://github.com/HaiDang666/express2017
After many hours of trying finally I've managed to fix the problem by using the ExtractJwt.fromAuthHeaderWithScheme('Bearer') method. For some reason the extractor wasn't able to get the token with the other methods.
https://stackoverflow.com/questions/45897044/passport-jwt-401-unauthorized
Hello everyone. I still have this issue. Tried using bearer strategy too. Here is the link to my repo https://github.com/soumodips/JWT-passport-OAuth
I will be glad if any one can help.
Screenshots from Postman:
Thanks a ton in advance!
ISSUE SOLVED: Be sure to use all key names as expected by the modules. I had used 'exp' for expiry time in the payload instead of 'expiresIn'. Enjoy!!
Ok, if you follow the tutorial to the letter there are some things changed in the meantime it seems.
What I needed to do in order to get my token accepted on my local machine.
Used the following extractor in the options object:
ExtractJwt.fromAuthHeaderAsBearerToken()
And used the following Authentication header contents;
bearer eyJhbGciOiJIUzI1Ni-restofthetoken...
But the most important part was to not use the following options given in the example:
opts.issuer = 'accounts.examplesoft.com';
opts.audience = 'yoursite.net';
And to be exact, I'm currently using:
passport@0.3.2
passport-jwt@3.0.1
Hello, I am having the same issue with my authentication. Here is my configuration :
const JwtStrategy = require('passport-jwt').Strategy
const ExtractJwt = require('passport-jwt').ExtractJwt
const User = require('../models/user')
module.exports = function (passport) {
var opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme('JWT')
opts.secretOrKey = 'secret'
passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
User.getUserById(jwt_payload.sub, (err, user) => {
if (err) {
return done(err, false)
}
if (user) {
return done(null, user);
} else {
return done(null, false);
}
})
}))
passport.serializeUser(function (user, done) {
done(null, user.id);
})
}
router.post('/login', (req, res) => {
const username = req.body.username
const password = req.body.password
User.getUserByUsername(username, (err, user) => {
if (err) {
throw err
}
if (!user) {
return res.json({
success: false,
msg: 'User not found.'
})
}
User.comparePassword(password, user.password, (err, isMatch) => {
if (err) {
throw err
}
if (isMatch) {
const token = jwt.sign({ data: user }, 'secret', {
expiresIn: 604800 // 1 week
})
res.json({
success: true,
token: 'JWT ' + token,
user: {
id: user._id,
name: user.name,
username: user.username,
email: user.email
}
})
}
else {
res.json({
success: false,
msg: 'Wrong Password'
})
}
})
})
})
So when I try to fetch a user's profile by the generated token through :
router.get('/profile', passport.authenticate('jwt', { session: false }), (req, res) => {
res.json({
user: req.user
})
})
It always shows Unauthorized
I'm currently using :
"passport": "^0.4.0",
"passport-jwt": "^3.0.1"
Can anyone please tell me what I'm missing ?
Hi everyone, make sure that you guys are using the same secret to .sign()
and .verify()
token
Having the same issue as theakshaygupta. This happens when tokens have expired.
router.get('/profile', passport.authenticate('jwt', { session: false }), (req, res) => {
res.json({
user: req.user
})
})
passport.authenticate does not pass off the error. If I do this.
passport.authenticate('jwt', { session: false }, (error, user, info) => {
console.log('error = ', error, ' info = ', info, ' user = ', user);
});
Then info shows the expired error message. The question is why does it not pass off this to my first method ?
@theakshaygupta
Are you sure that jwt_payload.sub holds the data you think it does?
You sign your token with the payload {data: user}, so to my eyes it looks like you should be looking for jwt_payload.data.user._id in your passport.js file and not jwt_payload.sub.
just as a note to everyone facing that problem. For me it was a missmatch in the parameter naming. Reading the code of the jsonwebtoken
package was helping me:
verify.js
...
if (options.issuer) {
var invalid_issuer =
(typeof options.issuer === 'string' && payload.iss !== options.issuer) ||
(Array.isArray(options.issuer) && options.issuer.indexOf(payload.iss) === -1);
if (invalid_issuer) {
return done(new JsonWebTokenError('jwt issuer invalid. expected: ' + options.issuer));
}
}
...
there you can see that the jwt-payload itself needs to have the iss
key not the issuer
key. Same with the aud
vs. audience
key.
so changing it to iss
and aud
during. the jwt-creating was solving it for me on the verification.
@theakshaygupta I'm having this same issue, did you find a solution?!
+1 the same issue as @theakshaygupta and still looking for answer
@arnasledev @henrybarnacle
As mentioned above, you've got to ensure that your token is not expired If you want further insight on what could be the possible issue please refer to issue #153
:)
@theakshaygupta yeah thats what I though before about expired token but its all good and valid for one month. I just kept stuck on the same problem as this guy mentioned on this comment and it has nothing to do with my token expire time.
My issue was indeed not setting an expiry on the token when signing it.
const token = jwt.sign(user, config.secrets.jwt, { expiresIn: 86400 * 7 });
Here's the relevant parts of code for anyone who requires it in future:
// auth/controller.js
const jwt = require('jsonwebtoken');
const passport = require('passport');
const config = require('../config/config');
function verifyUser(req, res /*, next*/) {
passport.authenticate('local', { session: false }, (err, user, info) => {
if (err || !user) {
return res.status(400).json({
message: info.message
});
}
req.login(user, { session: false }, (error) => {
if (error) {
res.send(error);
}
// generate a signed son web token with the contents of user object and return it in the response
const token = jwt.sign(user, config.secrets.jwt, { expiresIn: 86400 * 30 }); // Expiry!!!!
// Use to ensure token is valid and debug non-working bearer
// jwt.verify(token, config.secrets.jwt, (errs, data) => {
// console.log(errs, data);
// });
res.json({
user: {
'firstName': user.firstName,
'lastName': user.lastName,
'email': user.email
},
message: info.message,
token
});
});
})(req, res);
}
module.exports = {
verifyUser
};
// user/route.js
const router = require('express').Router();
const controller = require('./controller');
const passport = require('passport');
router.route('/:id')
.get(passport.authenticate('jwt', { session: false }), controller.getUser);
module.exports = router;
// auth/passport.js - only showing JWTStrategy
passport.use(new JWTStrategy({
jwtFromRequest: ExtractJWT.fromAuthHeaderWithScheme('Bearer'),
secretOrKey: config.secrets.jwt
},
(jwtPayload, cb) => {
// Use the JWT token to find the user in the db if required
return User.findOne({ where: { email: jwtPayload.email }, raw: true })
.then((user) => {
return cb(null, user);
})
.catch((err) => {
return cb(err);
});
}
));
use the token as JWT asndbcsdgfqmnsdbswfv..... like that...give a space between JWT and other characters.
https://github.com/themikenicholson/passport-jwt/issues/117#issuecomment-369544889
This did it for me. I did not manually set the headers, I had to go to the Authorization tab of Postman, and select Bearer token, and in the input field for the token i had to REMOVE the "JWT" prepended on there by the generator function. The token would not work with JWT at the beginning.
Using lower case is simple solution. Express converts Http Header paprameters name to lower case. So try like this
passport.use(new JWTstrategy({
secretOrKey: 'top_secret',
jwtFromRequest: ExtractJWT.fromHeader('YOUR-HEADER-PARAM'.toLowerCase())
}, async (token, done) => {
try {
return done(null, token.user)
} catch (error) {
done(error)
}
}))
watch out if you are using a variable from process.env
for expiresIn
... make sure you convert to Number when defining you sign your token
what worked for me was selecting token bearer in the authorization section of post man , before sending the get request. just like @Vizzyy
Token is not getting expired. Please help!!
// route middleware to verify a token app.use('/api/*',function(req, res, next) {
// check header or url parameters or post parameters for token console.log("Middleware"); var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token if (token) {
// verifies secret and checks exp
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
console.log("Token Error!!!!!");
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
console.log("Token Error!!!!!");
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
//Token Creation part:
const payload = {
user: req.user["username"] ,
iat:Date.now()
};
var token = jwt.sign(payload, 'iLoveMyLaptop', {
expiresIn : 60
//token gets expired in 60 seconds.
});
Closing as this has become a general "I need help" thread, primarily with a tutorial I didn't author or review and it likely not up to date with the current API of this module.
If you have a specific issue with the module, please provide a succinct and self-contained code example to illustrate the issue - A failing unit test is preferred.
For me, replacing the ExtractJWT.fromAuthHeaderAsBearerToken()
with ExtractJWT.fromHeader('authorization')
worked.
in Version 0.4.0, Authorization header for jwt is changed from 'JWT ' + [some token] to 'bearer ' + [some token]
As of version 4.0.0
, this is what you need to do:
Do not use the following fields from the tutorial. Just comment them out or delete them.
issuer: <>,
audience: <>
Your JWT strategy options should look like the following:
const opts = {
jwtFromRequest: extractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: jwtSecret
}
In Postman, under "Authorization" tab, select "Bearer Token" and populated the Token
field with your token (without any JWT
or Bearer
prefixes)
I wasted more than half an hour, in finding the solution, finally Replacing 'JWT' with 'Bearer' in token key of res.json worked for me. res.json({ success: true, token: "Bearer " + token, .............. hopefully people will save their time by reading this comment.
As of version
4.0.0
, this is what you need to do:
- Do not use the following fields from the tutorial. Just comment them out or delete them.
issuer: <>, audience: <>
- Your JWT strategy options should look like the following:
const opts = { jwtFromRequest: extractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: jwtSecret }
- In Postman, under "Authorization" tab, select "Bearer Token" and populated the
Token
field with your token (without anyJWT
orBearer
prefixes)
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. 💩
I had 401 error for last several hours. For those, who are successfully extracting jwt token but still are getting the 401 error, most likely the problem is in options object. Here's how my code looks like.
passport.use( new JWTStrategy( { ...opts, //<-------MAKE SURE TO DECONSTRUCT THE OPTIONS OBJECT WHICH YOU USED TO GENERATE TOKEN. for me, that was the problem. jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(), secretOrKey: "secret_key" // the private key, used in your algorithm to generate token. }, function(jwtPayload, done) { done(null, jwtPayload); } ) );
Also
Bearer ${token}
. Ok, if you follow the tutorial to the letter there are some things changed in the meantime it seems.
What I needed to do in order to get my token accepted on my local machine.
Used the following extractor in the options object:
ExtractJwt.fromAuthHeaderAsBearerToken()
And used the following Authentication header contents;
bearer eyJhbGciOiJIUzI1Ni-restofthetoken...
But the most important part was to not use the following options given in the example:
opts.issuer = 'accounts.examplesoft.com'; opts.audience = 'yoursite.net';
And to be exact, I'm currently using:
passport@0.3.2 passport-jwt@3.0.1
Yeap, I figured all of that too late unfortunately for me. I wish I found your answer before all this work.
watch out if you are using a variable from
process.env
forexpiresIn
... make sure you convert to Number when defining you sign your token
Thanks a lot @lablancas ! That was my issue 😄
goto the postman authorization section and select the "Bearer Token" paste your token in the input filed and also remove the prepend "Bearer || JWT" from the token
passport-jwt@4.0.0 passport@0.4.0
Hope this Helps
Ok, if you follow the tutorial to the letter there are some things changed in the meantime it seems.
What I needed to do in order to get my token accepted on my local machine.
Used the following extractor in the options object:
ExtractJwt.fromAuthHeaderAsBearerToken()
And used the following Authentication header contents;
bearer eyJhbGciOiJIUzI1Ni-restofthetoken...
But the most important part was to not use the following options given in the example:
opts.issuer = 'accounts.examplesoft.com'; opts.audience = 'yoursite.net';
And to be exact, I'm currently using:
passport@0.3.2 passport-jwt@3.0.1
Removing the opts.issuer
and opts.audience
keys worked wonders - thank you!
I do not want to use postman to pass token in auth header ,how can i do it , i am getting unauthorized when as output, please answer below is the link to my question. https://stackoverflow.com/questions/63102730/i-am-having-trouble-passing-jwt-token-in-post-authentication-routes
I was consistently getting the 401 Error "Unauthorized" when sending my requests to protected routes in Postman. I remembered to set a Bearer token followed by my JWT as an HTTP header "Bearer
Eventually, I figured out that the problems I was having were caused by my token being expired, so be sure to double-check that your tokens aren't expired by pasting your token into jwt.io.
These were the opts that I used.
const opts: JwtStrategyOptions = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: keys.jwt.secret,
};
Just wanted to leave this here for anyone still having issues with this: (Aug 14 - 2020)
IF you are using Postman to test (which I was) follow the steps along with the { data : user } fixes mentioned above:
1) Go to "Authorization" and select "Inherit Auth from parent" 2) Go to "Header" and manually type into a "key" field "Authorization" (it will be one of the auto-complete options also). Then in the "Value" field - post your key (jwt prepended and all) as is.
The problem is that "Bearer" token preset in Postman Authentication selection automatically prepends your key with "Bearer" as it is meant to be a "template" option. You're meant to add your own "token" manually as described above.
Hope this helps someone.
I just want to thank you, there is no solution here, but you pointed me in the right direction and I fixed the problem. Thank you and best regards. ;-)
After days of trying to solve this, I found out that my public key was wrong. fixed that and that solved my problem.
I am still having issues with this. Everything is set up properly, Authorization header, ExtractJwt.fromAuthHeaderAsBearerToken(), and Expiry times are converted to numbers. I can manage to make GET requests work, but POST requests refuse to work on routes requiring authorization. However, in POSTMAN, POST requests work just fine with the same Token that was declined in the previously mentioned POST requests from my client side app. Help!
Hello, I'm just commenting because it can help someone, I was having trouble authenticating, because I was using the wrong token... in my case, when I log in, I get a token object with 3 different tokens, 1 of them the idToken": { "jwtToken", another refreshToken": { "token": and another accessToken": { "jwtToken, I believe I was using accessToken when I should have been using idToken, hope it helps someone, or even myself in the future
Hello, it might be helpful.
It helped me to manually create the files and copy the generated keys there.
Because in the public key, when outputting to the console for the test, the first characters were displayed "��-----BEGIN RSA PUBLIC KEY-----" which I could not remove in the code.
.replace('��','') and other things didn't work
Is there any way by which my payload should not be visible when i will be putting my token into jwt.io
Is there any way by which my payload should not be visible when i will be putting my token into jwt.io
Nope. It's all readable. If you want encrypted payload, look into PASETO. If not, just make sure to not include any sensitive info in there.
I am following this tutorial to enable jwt authentication in my express API. https://jonathanmh.com/express-passport-json-web-token-jwt-authentication-beginners/
If I use a standard username/password authentication, I am able to use JwtStrategy to authenticate the JWT Token that I receive in the request header. jwt.sign() happens on the user id and secret. All of this works fine.
When I try to modify this code to verify the id_token (JWT Token signed using RS256) from OpenID Connect, then I get 401 Unauthorized no matter what. I tried to debug in the JwtStrategy method and it looks like the request doesn't even go inside that function. This id_token appears to be a lot longer than the one signed with HS256 algorithm.
A simple passport.authenticate call app.get('/callback', passport.authenticate('jwt', { session: false }), function(req, res, next) { });
Can someone please explain why it doesn't even recognize my token?