Node.js JWT refresh token in express middleware - node.js

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

Related

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.

checking Jwt token on every request?

I am developing a android aplication with nodejs and postgreSQL, at the moment i just have the login and the register.
When i do a login and everything is fine the server send me a token, that token is stored on the device SharedPreference, now my confusion is, do i need to decode this token on every request, or do i need to do it just 1 time?
in this tutorial at the end, he decodes on every route the token, but i don't need to do that when i do for example a request to register.
What is the best way to implement this?
here is my server code:
//****************************************************Begin of login request **********************************/
router.post('/login', function (req, res, next) {
if (JSON.stringify(req.body) == "{}") {
return res.status(400).json({ Error: "Login request body is empty" });
}
if (!req.body.username || !req.body.password) {
return res.status(400).json({ Error: "Missing fields for login" });
}
// search a user to login
User.findOne({ where: { username: req.body.username } }) // searching a user with the same username and password sended in req.body
.then(function (user) {
if (user && user.validPassword(req.body.password)) {
//return res.status(200).json({ message: "loged in!" }); // username and password match
var payload = { user: user };
// create a token
var token = jwt.sign(payload, 'superSecret', {
expiresIn: 60 * 60 * 24
});
// return the information including token as JSON
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
else {
return res.status(401).json({ message: "Unauthorized" }); // if there is no user with specific fields send
}
}).catch(function (err) {
console.error(err.stack)
return res.status(500).json({ message: "server issues when trying to login!" }); // server problems
});
});
//****************************************************End of Login request **********************************/
//****************************************************Begin of register request******************************/
router.post('/register', function (req, res, next) {
if (JSON.stringify(req.body) == "{}") {
return res.status(400).json({ Error: "Register request body is empty" });
}
if (!req.body.email || !req.body.username || !req.body.password) {
return res.status(400).json({ Error: "Missing fields for registration" });
}
var password = User.generateHash(req.body.password);
User.create({
username: req.body.username,
email: req.body.email,
password: password
}).then(function () {
return res.status(200).json({ message: "user created" });
}).catch(function (err) {
return res.status(400).send({ message: err.message }); //
}).catch(function (err) {
return res.status(400).json({ message: "issues trying to connect to database" });
})
});
//****************************************************End of register request **********************************/
module.exports = router;
If you don't want to use JWT token check for all routes, you can skip those routes.
const url = require('url');
apiRoutes.use((req, res, next) => {
const path = url.parse(req.url).pathname;
console.log(path);
//No JWT token check
if (/^\/register/.test(path)) {
return next();
}
return jwtTokenValidate();
});
function jwtTokenValidate() {
// check header or url parameters or post parameters for token
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) {
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
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
}

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.

How Pass Token in every Request

I'm using jsonwebtoken And I want to pass this token in every Request.
Have I set my Token in Session and pass the session with token app.use?
or I have to Store it in Cookie?
Can I Retrieve the logged user by JWT?
I create my Token with
var token = jwt.sign(user, app.get('superSecret'), {
expiresIn: 1440 // expires in 24 hours
});
and Check The Token With
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
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();
}
});

Save and get express.js token from local storage

I am using Node with Express.js and trying to make an authentication with JWT, after the user logs in generate a token, and save it to localstorage, but then I don't know how to get the token for authentication.
This is the code I am using:
Login view:
$.ajax({
type: 'POST',
url: base_url + "login",
data: postData,
dataType: 'json',
success: function(data){
// console.log(data1);
// alert(data);
_(data);
if(data.success === false){
showError(data.msg);
}else{
showError(data.msg);
window.localStorage.setItem("authToken", data.token);
var token = window.localStorage.getItem('authToken');
if (token) {
$.ajaxSetup({
headers: {
'x-access-token': token
}
});
}
}
}
});
And this is the route authentication I am using to check before any of the routes is accessed:
router.use(function(req, res, next){
var token = req.headers['x-access-token'];
console.log(token);
if (token) {
// verifies secret and checks exp
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
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();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
In console.log(token) I get an Undefined variable , it seems like I don't know how to access the token from route.
Thanks a lot.
"x-access-token" must be registered as an allowed header
response.setHeader("Access-Control-Allow-Headers", "x-access-token, mytoken");
Check this post :
How do CORS and Access-Control-Allow-Headers work?

Resources