How can we store JWT token in Http only cookies? - node.js

I am creating login module.
User will enter Username and Password.
If user validate successfully then Server will return JWT token.
I will use the JWT token to validate the different API call in React js.
Now my concern is that I found some article regarding this then I found that We can use http only cookie. How can we implement httponly cookie method to store JWT ? Is it safe?

HttpOnly cookies are safe in that they are protected from browser access via the Document.cookie API, and therefore are protected from things like XSS attacks.
When your user is successfully validated, the server should generate a jwt token and return it as a cookie to your client like so:
return res.cookie('token', token, {
expires: new Date(Date.now() + expiration), // time until expiration
secure: false, // set to true if you're using https
httpOnly: true,
});
The cookie will be accessible via incoming http requests from your client. You can check the jwt value of the cookie with an authorizing middleware function to protect your API endpoints:
const verifyToken = async (req, res, next) => {
const token = req.cookies.token || '';
try {
if (!token) {
return res.status(401).json('You need to Login')
}
const decrypt = await jwt.verify(token, process.env.JWT_SECRET);
req.user = {
id: decrypt.id,
firstname: decrypt.firstname,
};
next();
} catch (err) {
return res.status(500).json(err.toString());
}
};
Reference for more details: https://dev.to/mr_cea/remaining-stateless-jwt-cookies-in-node-js-3lle

Related

How to save and send JWT token from frontend

I am using JWT in my node.js app. Everything with token works fine. I can get a token when I have logged in.
Here's how I check user auth.:
const jwt = require('jsonwebtoken')
try{
const token = req.headers.authorization
const decoded = jwt.verify(token, 'secret')
req.userData = decoded
next()
}
catch(err){
return res.send("Auth error")
}
I can access protected routes if I change token value with that token I've got after log in.
But I want to save the token (on user's side???), and each time when the user tries to access protected routes (from frontend), send token as req.headers.authorization, so that the token can be verified, and the user can access the route.
So, how to save and later send the token, that has been generated after user's log in each time when protected routes are linked to?
Thank you.
(I am not using any javascript frontend frameworks)
If it's a token for authentication, you can use a httpOnly cookie to prevent XSS attacks, which is a risk with local storage.
To save a JWT in a cookie in express:
const accessToken = jwt.sign();
return res
.status(201)
.cookie("accessToken", accessToken, {
httpOnly: true,
maxAge: (1000*60*5), // 5m
secure: true,
signed: true
})
.end();
When getting from requests:
const { accessToken } = req.signedCookies;
Inside your app.js:
const express = require("express");
const cookieParser = require("cookie-parser");
const app = express();
app.use(cookieParser("secret"));
With httpOnly cookies your requests automatically send the cookie along with the request (only if the cookie belongs to the same domain). Just make sure your CORS and http client are properly configured to handle the cookie
Common approach to save it to a local storage. Just keep in mind local storage size and other limitations in different browsers.

Express creates different session when auth header is changed

I am new to express and I am trying to create session when user logs in to my app.I am using passport for authentication. To login user I am creating basic strategy and on success of basic strategy I am creating a JWT token which I am storing at client side in cookie and I use JWT strategy for subsequent requests.
But I notice that express-session is creating one session when I am logging in which has Basic header and another session for subsequent calls which has JWT header.
Here is my code where I am saving session on login
signin = function(req, res, next) {
passport.authenticate('basic', function(err, user, info) {
if (err) { return next(err) }
if (!user) {
return res.status(401).json({ error: 'message' });
}
var token = jwt.encode({ user: user}, config.db.secret);
res.cookie('token', token, { maxAge: 900000, httpOnly: true, path: '\/', Secure: true });
res.status(200).json({ success: true, firstName: user.firstName });
delete user.password;
req.session.user = user;
req.session.save();
})(req, res, next);
};
But when I debug this code it shows one sessionID in req.sessionID and it show different sessionID in req.sessionID in the following code which as JWT authentication
listProducts = function(req, res) {
debugger;
//here req.session.user is undefined which I have saved at login. and sessionID is also different
res.json({ demo: 'response' });
};
I am expecting it to be same sessionID throughout the life cycle till user logs out of my app.
Why is this exactly happening? What is the solution to it?
You are sending the response before saving the session.
Try saving the session, then sending the response instead.
express-session modifies res.end to make it perform express-session specific tasks introducing the sequential coupling you were victim of: https://github.com/expressjs/session/blob/master/index.js#L249

Once I have generated a JSON Web Token how do I use it? (Node.js)

I'm building an app with Node.js + Express, and I'm trying to use JSON Web Tokens for authentication. Right now I am at the point where once a valid username/password is entered, the server responds by sending the client a JWT.
This is where I get lost.
How do I send that token along with further requests to the server?
How can I send it as a header?
How do I send that token along with further requests to the server?
You can append in your req URL as query parameter.
Eg:
http://localhost:8080/api/users?token=tokenValue
You can save it in cookies and when you req a URL, it will fetch up this cookie containing your token. Use document.cookie to save token in your cookie
How can I send it as a header?
Using JQuery
$.ajax({
type:"POST",
beforeSend: function (request)
{
request.setRequestHeader("Authority", authorizationToken);
},
url: "entities",
data: "",
success: function(msg) {
}
});
At Server Side, you can do:
var token = req.body.token || req.query.token || req.headers['x-access-token'];
For Cookie Parsing, you can use: Cookie-Parser
var app = express()
app.use(cookieParser())
app.get('/', function(req, res) {
console.log("Cookies: ", req.cookies)
})
Further Reading:
https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
client can set the access token either as header or query parameter or in request body. Following is a way to send via header:
$.ajax({
url: 'foo/bar',
headers: { 'x-access-token': 'some value' },
data: {}
}).done(function(result){
//do something
});
Best practice is to save the access-token in browser local storage rather than in cookie. Once you obtain the token once logged it.
Server, best way to include a authentication middleware above all secured routes, where token is required.
auth.middleware:
'use strict';
module.exports = function(req,res,next){
const jwt = require('jsonwebtoken');
const config = require('../config/config');
// 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, config.secret, function(err, decoded) {
if (err) {
return res.status(401).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.'
});
}
};
routes:
//no token required
app.post('/signup',users.create);
app.post('/login',users.authenticate);
const auth = require('../middleware/auth.middleware');
//token required for below routes
app.use(auth);
app.get('/info',index.getInfo);
first you need to set the json token in client by using http cookie (res.cookie("token","yourtoken")) or using session
when user sends a request you need to send the token to server.you can read cookie by using req.cookie.token and verify it in middleware or use session

Logging users in via Express / Auth0 back-end

Auth0 documentation describes how to set up express-jwt middleware to protect endpoints. The trouble is that the documentation doesn't seem to cover how you get a valid JWT in the first place.
On the angular side, there's documentation on using angular plugins to implement a login page, that's fine. How would one implement a route using express that would take a username/password and return to the client the appropriate JWT such that subsequent requests would be authorized?
I think I may be missing a basic concept about JWT here; via Auth0, when using Username-Password-Authentication, my guess is that Auth0 acts as the repo for those credentials. There's documentation out there about wiring passport to auth0 and JWT, the problem with those is that this documentation assumes that the username/password database is some MongoDB instance locally...I want to avoid that type of setup which was an initial attraction with auth0.
Are there sample projects that cover this, showing how to get a valid JWT on a back-end, without some separate front-end angular app requesting it first?
I use passport.js built in local strategy for authentication and store user information in a JWT that I read on routes that require authorization.
User id's can be serialized/deserialized into and out of the express sessionto obtain the user identifier using the auth token (JWT) in the request. This is in my opinion the best approach since it limits the amount of data stored on the client and provides better security than storing any user information. Here's an example of this in express:
//Set a session secret
var secrets = { sessionSecret: process.env.secret || 'my secret string'};
//Require express-jwt and set a secret for the cookie
var expressJwt = require('express-jwt');
var validateJwt = expressJwt({ secret: secrets.sessionSecret });
//Returns a jwt token signed by the app secret
var signToken = function(id) {
return jwt.sign({
id: id
}, secrets.sessionSecret, {
expiresInMinutes: 60 * 24 // 24 hours
});
};
//Set token cookie directly
var setTokenCookie = function(req, res) {
if (!req.user) {
return res.status(404).json({
message: 'Error during user validation'
});
}
var token = signToken(req.user.id, req.user.role);
res.cookie('token', JSON.stringify(token));
};
//Check to see if user is authenticated (call this when a route is requested)
var isAuthenticated = function(req, res, next) {
// allow access_token to be passed through query parameter as well
if (req.body && req.body.hasOwnProperty('access_token')) {
req.headers.authorization = 'Bearer ' + req.body.access_token;
}
// Validate jwt token
return validateJwt(req, res, next);
};
You can use these methods as middleware in express. Say the above code was token.js, you can force it to execute on each request to a route like this:
app.get('/employee', token.isAuthenticated, employeeController.getEmployees);
I haven't worked with angular but it works great on the backbone projects i've worked on and this process should work with any browser based client that can supply a X-auth cookie on each request. You can do this by using the ajax setup:
$(document).ajaxSend(function(event, request) {
var token = readCookie('token');
if (token) {
request.setRequestHeader('authorization', 'Bearer ' + token);
}
});
Here is an example of middleware that validates a users login and returns a token to the client that can be used on subsequent requests:
var validateLogin = function (req, res, next) {
var username = req.params.username;
// Authenticate using local strategy
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(404).json({
info: [{
msg: info.message
}]
});
}
// Send user and authentication token
var token = token.signToken(user.id, user.role);
res.cookie('token', token);
res.render('index', {token: token, user: user});
})(req, res, next);
};
#FrobberOfBits
This is to answer the follow-up Q posted by FrobberOfBits on Feb 6, 2016 at 3:04
I use auth0 for local + social media authentication.
The way auth0 works is, you hand over the approach to authenticate to auth0 ...either it be local with db or social media.
It is a bundled approach where local db and social media authentication is all bundled and provided as a service to you by auth0.
Hope this helps.

How to set authorization headers with nodejs and express

I am setting up a site with nodejs, express, mongoose and swig template following this tutorial :
Authenticate a Node.js API with JSON Web Tokens
In this tutorial the author uses Postman to set the token in the header.
I have googled for days to find out how I can set the jwt token in the header of my site, but it is not working for me.
If you want the client to include the token in it's request headers, you can use a cookie parser with express. (HTML5 Web Storage is another option). About Cookies:
Express can set the response headers to tell the client "add the token to a cookie".
Once the client sets the cookie with the token, the token will be in the client's request headers for each request. Let's get to baking with a little
npm install cookie-parser
Sprinkle on some
var cookieParser = require('cookie-parser')
app.use(cookieParser())
Access and set a cookie:
app.use(function (req, res, next) {
var cookie = req.cookies.jwtToken;
if (!cookie) {
res.cookie('jwtToken', theJwtTokenValue, { maxAge: 900000, httpOnly: true });
} else {
console.log('let's check that this is a valid cookie');
// send cookie along to the validation functions...
}
next();
});
You will probably want to do these things with the cookies (or whatever method you go with in the end):
set the cookie to hold the token when a user is authenticated.
check the cookie header value before allowing access to protected
routes.
send back an unauthorized status if a user doesn't have their token
when they are trying to access api routes that require a token.
May help someone in future...
Storing token in cookie with httpOnly:true flag is pretty secure from XSS attack but it can be vulnerable to CSRF attack.
Adding custom request headers for all routes in express using a middleware might be a feasible solution like that:
var token;
//asign 'accessToken' to 'token' in app.post('/login')
token=accessToken;
app.all('*' , (req, res, next) => {
if (!token) {
console.log('token: undefined');
} else {
req.headers.authorization = 'Bearer ' + token;
}
next();
});
this will add authorization=Bearer <token> header in each and every get request coming from browser. Now verify token in each secure route by adding this middleware:
let in app.get('/dashboard')
const authenticateToken=(req, res, next)=>{
var authHeader=req.headers['authorization'];
var token=authHeader && authHeader.split(' ')[1];
if(token==null){
return res.sendStatus(401);
}
jwt.verify(token, process.env.JWT_ACCESS_TOKEN, (err, user)=>{
if(err){
return res.sendStatus(403);
}
req.user=user;
next();
})
}
//in app.get(...)
app.get('/dashboard', authenticateToken ,()=>{
//stuff for authorized user
})
In case if you defined app.post('/login') in another file then,
export addHeader middleware as under:
//var to access token outside app.post('/login') route
var token;
app.post('/login' , (req , res)=>{
//authenticate the user
//create token
const accessToken=jwt.sign(user, secretKey);
//assign 'accessToken' to 'token' var
token=accessToken
//redirect to secure route
res.redirect('dashboard');
}
//middleware to add in your 'index.js' or 'app.js' file.
//export it only if you define app.post('/login') in another file
exports.addHeader = (req, res, next) => {
if (!token) {
console.log('token: undefined');
} else {
req.headers.authorization = 'Bearer ' + token;
}
next();
}
In index.js or app.js
//import file in which app.post('/login') is defined. let it is defined in controller/auth
const authController=require('./controller/auth');
//to add custom header in all routes
app.all('*', authController.addHeader);

Resources