JsonWebTokenError: Can't verify jwt - node.js

I make the token here:
var token = jwt.sign(user, new_secret, {expiresIn: 10000});
Then I attempt to verify it here
var token = req.headers.authorization;
jwt.verify(token, new_secret, function(err, decoded) {
console.log(err);
if (err) {
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();
}
});
I can't figure out where I'm going wrong here. I'm new to jwt.

I was able to get it to work by changing the prefix on the client side using angular-jwt.
It was once 'Bearer'; I found evidence that it should be 'JWT'...it only worked by removing it entirely:
jwtInterceptorProvider.authPrefix = '';
I'm not sure if this is best practice or not.

Related

Node.js JWT refresh token in express middleware

I'm trying to configure a token refresh method in my express middleware in wich the token is validate at every request to the api. I will check if the token expired and if so, I will sign a new token with new exp date. The problem is that I have to send the token again, but doing thatI lose the original request to send the token with the response and the api not continue to the destination endpoint.
How I can send back the new refreshed token and continue with the request?
My express middleware to check the token:
apiRouter.use(function(req, res, next) {
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
//Here I can check if the received token in the request expired
if(err.name == "TokenExpiredError"){
var refreshedToken = jwt.sign({
success: true,
}, app.get('superSecret'), {
expiresIn: '5m'
});
//Here need to send the new token back to the client and continue with the request
//but if I use return res.... the request don't continue to next()
next();
}else if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
}
} else {
//If no error with the token, continue
next();
};
});
} else {
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
I dont' know if its the best aproach to this.
Thanks you.
You can not send a response to the client two times for single request, so better way will be sent an access token with the actual API response.
apiRouter.use(function(req, res, next) {
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
//Here I can check if the received token in the request expired
if(err.name == "TokenExpiredError"){
var refreshedToken = jwt.sign({
success: true,
}, app.get('superSecret'), {
expiresIn: '5m'
});
request.apiToken = refreshedToken;
next();
}else if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
}
} else {
//If no error with the token, continue
request.apiToken = token;
next();
};
});
} else {
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
then when you send a response then send a response with the token, that you can get with request.apiToken.
but a better strategy is to provide a client refresh token and let the client make a request to get refreshed token.
You can read more about that here

JWT gives JsonWebTokenError "invalid token"

I have used jsonwebtoken for token verification in my Node Application .
Here jwt.sign works perfectly . But when jwt.verify gives following error
"auth": false,
"message": {
"name": "JsonWebTokenError",
"message": "invalid token"
}
}
Here is my Post and Get Router
router.post('/signup',(req,res)=>{
const body = _.pick(req.body,['username','email_id','name','college','password','dob','gender','city','joinedOn','bio']);
User.findOne({'username':body.username},function(err,user){
if(err){
res.status(404).send(err)
}else if(user){
res.status(404).send('User with Username Exists')
}else{
var user = new User(body);
user.save().then((user) => {
var token = jwt.sign({ username: user.username},'secret', {
"algorithm": "HS256",
expiresIn: 86400 // expires in 24 hours
});
res.status(200).send({ auth: true, token: token });
}, (e) => {
res.status(400).send(e)
})
}
})
});
router.get('/me', VerifyToken, function(req, res) {
User.findOne({username:req.username}, function (err, user) {
if (err) return res.status(500).send(err);
if (!user) return res.status(404).send("No user found.");
res.status(200).send(user);
});
});
Below is verifyToken Function
function verifyToken(req, res, next) {
var token = req.headers['x-access-token'];
if (!token)
return res.status(403).send({ auth: false, message: 'No token provided.' });
console.log(token)
jwt.verify(token,'secret', function(err, decoded) {
if (err)
return res.status(500).send({ auth: false, message: err });
//req.username = decoded.username;
console.log(decoded)
next();
});
}
I can't figure out what's wrong in my program .Any suggestions would be appreciated .
Thanks
If you are passing in a token to your jwt.verify function like so Bearer *************...., ensure to split the token first before passing it in to jwt by doing
const token = req.headers.authorization.split(' ')[1];
jwt.verify(token)
Hope this helps someone.
My Code is true . The mistake I was doing that I was giving access token with double quote("token") in Postman. That's why postman was giving me following error
"auth": false, "message": { "name": "JsonWebTokenError", "message": "invalid token" } }
I had the same issue. Basically the token should not have brearer information. When I stripped it out it started working as expected.
For instance:
Failed when I used brearer *************....
Worked when I used *************....
I had a similar error because I persisted the token in localStorage with JSON.stringify, which adds two double quotes to the token, hence resulting in an invalid token when verifying it.
// What caused the error
localStorage.setItem('jwt', JSON.stringify(token));
Solution, either omit JSON.stringify, or parse the token when verifying:
localStorage.setItem('jwt', token);
// or
const token = JSON.parse(localStorage.getItem('jwt'));
const token = req.header('token');
try {
const decoded = jwt.verify(JSON.parse(token), privateKey);
console.log(decoded)
} catch(err) {
console.log('err', err)
}
when you pass token from service convert into JSON.parse(token) from local storage then pass to verify

How to exclude a router/api url from jsonwebtoken

I am using node.js express app. jsonwebtoken for authentication. I want to exlude some api url from the jsonwebtoken verification. below is what I have tried and my code
router.use('/authentication', mountAllRoutes(authenticationModule));
// route middleware to verify a token
router.use((req, res, next) => {
const r = req;
const token = req.body.token || req.query.token || req.headers.authorization;
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, (req.app.get('superSecret')), (err, decoded) => {
if (err) {
// res.json({ success: false, message: 'Failed to authenticate token.' });
res.status(401).send({
success: false,
message: 'Failed to authenticate token.'
});
} else {
// if everything is good, save to request for use in other routes
r.decoded = decoded;
next();
// console.log(decoded);
}
return {};
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
return {};
});
router.use('/test', mountAllRoutes(testModule));
router.use('/other', mountAllRoutes(otherModule));
router.use('/data', mountAllRoutes(dataModule));
Here I have placed routes above middleware which I dont want to protect. and I have placed after middleware which I want to protect. But it is protected which I placed above middleware. In authenticationModule, login and user registration api comes. so for user registration it gives response no token provided
Note: I have refrerred this link How-to-ignore-some-request-type-in-Jsonwebtoken
create separate route file for the API you want to exclued.
//Routes
var users = require('./routes/users');
var api = require('./routes/publicApi');
App.js:
// route middleware to verify a token
router.use((req, res, next) => {
const r = req;
const token = req.body.token || req.query.token || req.headers.authorization;
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, (req.app.get('superSecret')), (err, decoded) => {
if (err) {
// res.json({ success: false, message: 'Failed to authenticate token.' });
res.status(401).send({
success: false,
message: 'Failed to authenticate token.'
});
} else {
// if everything is good, save to request for use in other routes
r.decoded = decoded;
next();
// console.log(decoded);
}
return {};
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
return {};
});
app.use('/users', router);//will use Token Authentican
app.use('/publicApi', router);//Dont do this.

Node.js JWT, get user_id from token

strong textI am building node.js + mongodb rest api. I use jwt user auth and I have a problem. I need to get details of authenticated user (user_id, name), think they can be obtained from token, but I dont know how to do this. How is it possible to do ?
UPDATED
I am doing a post request
router.route('/articles')
.post(function (req, res) {
var article= new Article();
article.user_id = ???; // here needs user_id
article.imdb_id = req.body.imdb_id;
article.title = req.body.title;
article.thumb = req.body.thumb;
article.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Added' });
});
});
I need to insert into articles collection authors id (user_id), but I dont know how to get the authenticated user_id.
Tried to do this:
var token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
req.decoded = decoded;
console.log(decoded);
next();
}
});
decoded returns all info about user (name, password, _id). Is it possible to get only user_id and name from here?
When you sign a JSON web token you can pass it a user object. Here you can store whatever user data you need. This object is then signed and encoded and set as the token. When you send a request to your API passing the JWT in the auth header your validation function should return this user object back to you if the JWT is valid.
I like to use the Hapi framework for creating my Restful APIs so I will give an example using Hapi.
In your server.js file you need to register the hapi-auth-jwt2 package:
server.register(require('hapi-auth-jwt2'), (err) => {
if (err) {
throw err;
}
server.auth.strategy('jwt', 'jwt', {
key: config.jwt.secret,
validateFunc: auth.validate,
verifyOptions: { algorithms: ['HS256'] }
});
server.auth.default('jwt');
});
Your validation function:
export default {
validate: (tokenObject, req, callback) => {
validateToken(tokenObject.user_id, (err, user) => {
if (err) {
callback(Boom.unauthorized('User is unauthorized.'), false);
} else {
req.user = user;
callback(null, true);
}
});
}
};
The validateToken function should take the user id that you got from the token and query for the user. If a user is found then you know the token is valid and you can return and store the rest of the user information.
To create a token I use "jsonwebtoken" package:
generateToken: (user_id, name, callback) => {
'use strict';
callback(null, JWT.sign({
user_id: user_id,
name: name
}, config.JWT.SECRET, {
expiresIn: 86400
}));
}
Let's say you need to verify if the token sent from user In the headers already In your Database or not (we're going to call it protect)
const {promisify} = require('util');
const jwt = require('jsonwebtoken');
const User = require('./../models/userModel');
...
exports.protect = catchAsync(async(req, res, next) => {
// 1) Getting token and check if it's there in headers
let token;
//authorization is the name of the header token
if (req.headers.authorization) {
token = req.headers.authorization;
}
if (!token) {
return next(new AppError('You are not logged in! Please Login To get Access.', 401));
}
// 2) Verification Token is a valid token
const decoded = await promisify(jwt.verify)(token, process.env.JWT_SECRET);
// WE CAN GET THE USER ID FROM DECODED
// 3) Check if user still exists not deleted
const currentUser = await User.findById(decoded.id);
if (!currentUser) {
return next(new AppError('the user does not exist.', 401));
}else{
// WHAT EVER YOU WANT TO DO AFTER CHECKING USER FOUND IN DATABASE
})

Express Middleware jsonwebtoken authentication

My server has a registration api that provides a token after registration, and a middleware that authenticates a user's token. I need to register an account to get the token to do something else with my server. However, the middleware blocks my network request because I don't have a token yet.
So how can I create my account and token in this case? Get pass the middleware with some tricks?
Middleware:
// Middleware to verify token, it will be called everytime a request is sent to API
api.use((req, res, next)=> {
var token = req.headers.token
if (token) {
jwt.verify(token, secret, (err, decoded)=> {
if (err) {
res.status(403).send({ success: false, message: "Failed to authenticate user." })
} else {
req.decoded = decoded
next()
}
})
} else {
res.status(403).send({ success: false, message: "No Token Provided." })
}
})
Signin:
// Sign In with email API
api.post('/signInWithEmail', (req, res)=> {
User.findOne({
email: req.body.email
}).select(userFields).exec((err, user)=> {
if(err) {
throw err
}
if (!user) {
res.send({ message: "User doesn't exist"});
} else if (user) {
var validPassword = user.comparePassword(req.body.password);
if (!validPassword) {
res.send({ message: "Invalid Password"});
} else {
var token = createToken(user);
res.json({
success: true,
message: "Login Successfully!",
token: token
})
}
}
})
})
Make a function to check tokens and expose your routes such that whenever you need to call an authenticated route then you'll be checking the token first and then you'll expose the route.
Sample Code
Let's say this is my check token function
function checkToken(req, res, next) {
var x = req.token; //This is just an example, please send token via header
if (x === token)
{
next();
}
else
{
res.redirect(/unauthorized); //here do whatever you want to do
}
}
Now let's use the function for routes.
app.post('/protectedroute', checkToken, routename.functionname);
app.post('/notprotected', routename.functionname);
It's your call if you'd like to have separate routes for different codes or else you can just call specific code block via keeping them in function etc. on the main file i.e. app.js or server.js, whatever you have chosen.
What actually we are doing here is - we are making a middleware of our own to expose our routes through a channel of code blocks or functions.

Resources