When the browser send cookies not received from the express server - node.js

I'm Developing a full-stack web application with Node js and express js as the backend and using Next Js for the front end and JWT for the authentication, I'm setting the JWT token with the cookie in the browser. The cookie is set successfully in the browser, but whenever I try to get the cookie from the Express server to check whether the user is valid or not, the cookie does not receive from the browser. I tried several ways to get the cookie from the browser but it doesn't respond. but it is receiving the cookie token from the Postman/thunder client.
note: The frontend port is 3000 and the backend port is 5000.
You can suggest another way for the user authentication with next js with external express server.
res.cookie("userToken", token, {
expires: new Date(Date.now() + 9000000000),
})
and the JWT verify code is here
const jwt = require("jsonwebtoken");
const jwtToken = (req, res, next) => {
try {
const userToken = req.cookies?.userToken;
if (userToken) {
const verify = jwt.verify(userToken, process.env.JWT_SECRET);
req.user = verify;
}
next(); // for getting the api result back to client
} catch (error) {
next(error);
}
};
module.exports = jwtToken;

Related

Not able to get cookie from Node to React

I created a simple login system where after certain user logs in the backend I set profile cookie with jwt token value
res.cookie('profile',jwt_token,{
secure : false,
httpOnly : true
});
In React frontend I am sending a get request to Node backend where I expect to get that jwt token
const { data } = await axios.get('http://localhost:2000/users/test', {withCredentials:true});
This is my controller for getting a cookie
export const test = async (req,res) =>{
try {
const cookie = req.cookies.profile || "no cookie";
res.json(cookie);
} catch (error) {
console.log(error.message);
res.status(406).json({success:false});
}
};
When I try to get a cookie after logging in with Postman I get cookie value but when I try to get the cookie from React through axios i am getting 'no cookie'. I've also set app.use(cors()) in Node
Apparently a known Axios bug exists that can be solved like this. Just add this line of code and try again.
axios.defaults.withCredentials = true;
const { data } = await axios.get('http://localhost:2000/users/test', {withCredentials:true});
You might need to install the cookie-parser middleware http://expressjs.com/en/resources/middleware/cookie-parser.html and then add it to your app:
const cookieParser = require('cookie-parser');
//...
app.use(cookieParser())

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.

How can we store JWT token in Http only cookies?

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

NextJS - Sending cookies to API server from getInitialProps

I'm using NextJS as a client side repository to talk to my backend API server (laravel). Auth is done via JWT stored in the cookies. It all works seamlessly when I send an auth request to https://my-backend-server.com/api/login, as I respond with a cookie, and set to the my-backend-server.com domain. And even when I send requests from the browser.
Problems arise when I want to load the page, and sent the request from getInitialProps, as this is a serverside call. How am I able to access the cookies to my-backend-server.com, and put those in the header, so the server-side request from NextJS is properly authorized?
Most of the answers say something about req.cookies or req.headers.cookies, however this is empty as the request in getInitialProps is to http://my-local-clientside-site.com
As you explained correctly, Next's getInitialProps is called on client & on server.
If your Next app & Api services are served from the same domain, your Api service can put the cookie on the domain, and it will work on the client side (browser).
Whenever your Next app accessing the api from server-side, you need to attach the cookie by yourself.
getInitialProps method on the server side gets on the context (first param) the request (as req) from the browser, that means that this request has the cookie.
If you have a custom server, you probably need add to it a cookieParser,
// server.js
import cookieParser from 'cookie-parser';
import express from 'express';
import next from 'next';
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
app.prepare().then(() => {
const nextHandler = app.getRequestHandler();
const server = express();
server.use(cookieParser());
// -----------^
server.get('*', (req, res) => nextHandler(req, res));
});
This parser will parse the Cookie header and put it as an object on the req.
After that, your req.cookie should have the cookie value (make sure that you see that the browser sends it in the document request) you can access it in your getInitialProps,
//pages/index.js
const IndexPage = () => <div>BLA</div>
IndexPage.getInitialProps = (context) => {
if(context.req) {
// it runs on server side
axios.defaults.headers.get.Cookie = context.req.headers.cookie;
}
};
I've given you an example that sets up axios to put the cookie on all requests that will be made from the client.
Felixmosh' answer is half correct. rather than context.req.cookie it should be context.req.headers.cookie.
const IndexPage = () => <div>BLA</div>
IndexPage.getInitialProps = (context) => {
if(context.req) {
// it runs on server side
axios.defaults.headers.get.Cookie = context.req.headers.cookie;
//make api call with axios - it would have correct cookies to authenticate your api call
}
};

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.

Resources