Cant assign a JWT to the header request - node.js

I have a problem using JWT. In the router responsible for the login page, on the post request, I assign a JWT for each login user, though I am not able to either send the token in the header of each page request after or actually save the token in the header. When I console log the token after each login and copy-paste it to the header in POSTMAN, it works fine, therefore i think this is my issue;
// generate a jwt for the login user
const token = jwt.sign({_id: this._id, isAdmin: this.isAdmin}, process.env.TOKEN_SECRET,
{expiresIn: 1800});
// send back to the homepage with the token in the header (?)
res.header('auth-token', token).redirect('/');
console.log(token);
And after this assignment, I have tried to access an authenticated users page and it didn't work, I think because of the reasons I have mentioned.
This is my auth middleware, responsible for the authentication I add to the routers:
const jwt = require('jsonwebtoken');
module.exports = function(req, res, next) {
const token = req.header('auth-token');
if(!token){
console.log('Access denied. No token provided.');
return res.status(401).redirect('/login');
}
try{
const decoded = jwt.verify(token, process.env.TOKEN_SECRET);
console.log(decoded);
req.user = decoded;
console.log('Access approved.');
next();
}
catch(ex){
console.log('Invalid token');
res.status(403).redirect('/');
}
}
I have no idea what am I missing. Tried to find a solution but nothing worked for me.
Thanks to the helpers!

Related

Recognizing first user login (Node.js/JWT)

I've developed an authentication system who consists on Node.js/Express and JWT.
I need to recognize the first time a user logs on and show him a message relevant only on that one time.
How can I do it?
This is the auth middleware i'm using to verify the user:
const auth = (req, res, next) => {
const token = req.header("x-auth-token")
if (!token) return res.status(401).json({ msg : "No token, authorization failed" })
try {
const decoded = jwt.verify(token, config.get("jwtSecret"))
req.user = decoded
next()
}
catch {
res.status(400).json({ msg : "Token is not valid" })
}
}
For this approach, you should let User to login with Basic Authentication for the first time (Email/Username + Password). After you validate that the user is the valid user on the backend, then you should store his _id in JWT and send him that JWT. On each next request, that user should send that JWT, and you can use your JWT authentication (but for initial login, you should go with Basic Authentication).

Refresh token how to handle POST routing

I am new to JWT and tokens for user verification and login. I used the following extensions for Node JS (NPM)
var jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser')
require('dotenv').config();
// Express ..
I already have a login that checks in MongoDB (Node JS as server) the user, checks email and password and then sets a cookie with access token and refresh token.
My login code is like
//create the access token with the shorter lifespan
let accessToken = jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET, {
algorithm: "HS256",
expiresIn: process.env.ACCESS_TOKEN_LIFE
})
//create the refresh token with the longer lifespan
let refreshToken = jwt.sign(payload, process.env.REFRESH_TOKEN_SECRET, {
algorithm: "HS256",
expiresIn: process.env.REFRESH_TOKEN_LIFE
})
//send the access token to the client inside a cookie
res.cookie("_login", accessToken, {secure: true, httpOnly: true})
res.send()
and here is the part for refresh token post
exports.refresh = function (req, res, next){
console.log("Test");
let accessToken = req.cookies._login
if (!accessToken){
return res.status(403).send()
}
let payload
try{
payload = jwt.verify(accessToken, process.env.ACCESS_TOKEN_SECRET)
}
catch(e){
return res.status(401).send()
}
//retrieve the refresh token from the users array
let refreshToken = payload.email.refreshToken
//verify the refresh token
try{
jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET)
}
catch(e){
return res.status(401).send()
}
let newToken = jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET,
{
algorithm: "HS256",
expiresIn: process.env.ACCESS_TOKEN_LIFE
})
res.cookie("_login", newToken, {secure: true, httpOnly: true})
res.send()
My question now is, since I see in so many tutorial and guides that they also work with refresh token via POST, how do I process that with the user?
Would the client send an AJAX or post to middleware for check on access token
-> If Access token is expired
--> code automatically takes refresh token and issues a new access token and gives an OK?
or the client sends to middleware where access token is checked
-> Access token is expired (result to the user)
-> client make now post request to /refresh-token result = new access and refresh token
-> And again post request to original middleware with new post request?
What is the procedure here, I can't find any workaround how this is handled.
Keep in mind that my answer is based on my experience. Feel free for anyone to edit if I happen to make a mistake in my ways.
So, in order to handle refresh token, I use this way:
When a user successfully logs in, the JWT (containing user's auth) and the refresh token (containing the user's refresh token) will be placed in the user's cookies (same like you).
The user will do his/her things inside your web application, until he/she closes the browser without signing out.
Remember that JWT always have expiration date - this expiration date will be kept in mind.
In every request, you're going to send that specific JWT (that contains the user's auth) and the refresh token to a middleware where you are going to make a POST request. If the JWT has expired, pick the refresh token and call your /refresh-token-result to get a new token. Else, just don't do anything with the refresh token and proceed with your request.
Ensure that your /refresh-token-result accepts a request token. The endpoint will check for its validity and will return a new access token.
If the refresh token had expired, log out the user. This is for security reasons and this is important!
Oh, and when a user logs out, ensure that both of your user's token and your user's refresh token is revoked properly, usually by changing the cookie value and the expiresIn attribute. For me, I usually change both cookie values to loggedOut and I'll set the expiresIn to five seconds.
Alternatively, if you're using React (an additional answer), you can do it like this:
If a user accesses your website, and the JWT expiration date is close to expiry, you can simply use a useEffect() hook in order to renew your access token.
TL;DR: Your second way is already good.
EDIT: Sample pseudocode to help you. Don't copy paste this right away, it most likely wouldn't work, but it should give you the general idea of how things work.
// middleware.js
const { token, refreshToken } = req.cookies;
// 1. If the token has not expired, call 'next()'
// assume 'isExpired' returns boolean: true or false depending on the state of your token.
if (!token.isExpired()) {
return next();
}
// 2. If the token has expired AND the refreshToken has not expired, issue a new token, THEN call 'next()'
if (token.isExpired() && !refreshToken.isExpired()) {
await issueToken();
return next();
}
// 3. Else, logout the user. I'll keep this one short.
await logoutUser();
res.status(401).json({
status: 'fail',
message: 'Your access has expired! Please log in again!',
});
And this is your controller.
// controller.js
const getAllComments = async (req, res, next) => {
const comments = await Comment.find();
res.status(200).json({
status: 'success',
data: comments,
});
}
And, this is what your route should look like.
// this import might be unresolved - keep in mind!
const middleware = require('./middleware');
const getAllComments = require('./controllers');
router.get('/api/v1/comments/', middleware,
checkToken, getAllComments); // assume checkToken is your function to check for a token's validity.
Keep in mind I did not include error handling to keep this example short.

Authorization middleware JWT confusion

I have a suspicion about the relative security of some authentication middleware code I came across in a course im enrolled in.
So I used postman to send a request to a protected route(see route code below) and found that I was able retrieve an order for one user with a token generated for another user.
const protected = asyncHandler(async (req, res, next) => {
let token;
if (
req.headers.authorization &&
req.headers.authorization.startsWith("Bearer")
) {
try {
token = req.headers.authorization.split(" ")[1];
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = await User.findById(decoded.id).select("-password");
next();
} catch (error) {
console.error(error);
res.status(401);
throw new Error("Not authorized, token failed");
}
}
if (!token) {
res.status(401);
throw new Error("Not authorized, No token found");
}
});
export protected
It seems evident to me that this middleware code will only verify if a user from decoded token exists in the DB and but will not limit access to resources based on the user/token.
import {addOrderItems, getOrderbyId} from "../controllers/orderController.js";
import { protected } from "../middleware/authMiddleware.js";
const router = express.Router();
router.route("/").post(protected, addOrderItems);
router.route("/:id").get(protected, getOrderbyId);
//:id is the order id
However, when testing another protected route for updating a user's profile info, I receive an error when using wrong token.
Was hoping for some clarification
jwt.verify will only verify that the given token is generated by the server or not. It doesn't care which user send this token.
For your protected middleware, it just check if the request is authorized. If so, the request will pass to the controller.
As for the updating route. It probably be something like this:
// route
router.route("/:userId", protected, updateController)
const updateController = (req, res) => {
const user = req.user; // this is the one generated by protected middleware
const reqUserId = req.params.userId; // this is the one send by request
if (user.id !== reqUserId) {
// if two ids are not the same, it means someone is trying
// to update the profile with the wrong token
res.status(401);
}
// update profile in database
}

How to send Bearer token to client and then call token from client

I have done a tutorial trying to get my head around JWT tokens. I seem to have got my head around the token creation as well as using the token to allow or disallow access to a route.
This all works great using postman, but in postman I enter the token under authorization. My question is:
1. how do I send the token to the client so it is saved on that client side.
2. How does the client return the token when they try to access a route?
I need to understand how this happens when NOT using postman. I am sure its pretty simple.
Do I just send
`res.header('Authorization', 'Bearer', + token);`
`res.header('Authorization', 'Bearer' + token);`
But can I send this with other stuff like a message / data etc?
Then when the user tries to access a protected route later, How do I access this header. IOW how is it stored client-side?
This is what I have thus far:
`//login route`
`app.post('/login', async function(req, res, next) {
const { name, password } = req.body;
if (name && password) {
let user = await getUser({ name: name });
if (!user) {
res.status(401).json({ message: 'No such user found' });
}
if (user.password === password) {
// from now on we'll identify the user by the id and the id is the
// only personalized value that goes into our token
let payload = { id: user.id };
let token = jwt.sign(payload, jwtOptions.secretOrKey);
res.json({ msg: 'ok', token: token });
} else {
res.status(401).json({ msg: 'Password is incorrect' });
}
}
});`
`// protected route
app.get('/protected', passport.authenticate('jwt', { session: false }), function(req, res) {
console.log('REQUEST HEADERS ON PROTECTED::',req.headers.authorization)
res.json('Success! You can now see this without a token.');
});`
The console.log under protected route gives me:
"REQUEST HEADERS ON PROTECTED:: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNTU2NjI3NTczfQ.gAU2VzpUpXHpcgM6_n8gf7D-xLCS59tK6K2RIlIk-L4" but I gather this is because I used the authorization in postman.
I recently worked with jwt auth using react as my front end and hapi.js as backend. To save the token on the client side, you can use localstorage like this:
You have to save this on the user login component.
localStorage.setItem('token', res.data.token);
And then, to access this token on the protected router, use this :
let token = localStorage.getItem('token');
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
I hope this may help you to solve your problem on the client side.

JWT nodejs / express - Invalid signature

I'm having trouble with Jwt and especially an error "Invalid Signature".
I'm generating a token after the user logs in (jsonwebtoken).
userSchema.methods.generateJwt = function() {
var expiry = new Date();
//expiry.setDate(expiry.getDate() + 7);
expiry.setDate(expiry.getDate() + 2);
return jwt.sign({
_id: this._id,
username: this.username,
name: this.lastname,
exp: parseInt(expiry.getTime() / 1000),
}, process.env.SRCT, {
algorithm: 'HS256'
});
}
Then I'm creating an express-jwt middleware to add it to routes :
var auth = jwt({
secret: process.env.SRCT,
userProperty: 'payload'
});
Used like this :
router.get('/', auth, ctrlUser.slash);
My JWT created is passed in the front end request (Authorization bearer) and is the same as the one created right after the login, according to the debugger.
But unfortunatly, I'm still having the error {"message":"UnauthorizedError: invalid signature"} after each request to the nodejs backend.
Could someone tell me what I am doing wrong to have an invalid signature?
Thanks in advance
Where is your verify function ? You need to check on every request made to a protected area that token is really valid, jwt provides a function verify to do that.
You don't seem to be parsing the request headers for the token, nor using verify() function of the JWT library for that. your auth middleware should look something like this
module.exports = (req, res, next) => {
try {
//parse the token from Authorization header (value of "bearer <token>")
let token = req.headers.authorization.split(" ")[1];
//verify the token against your secret key to parse the payload
const tokenData = jwt.verify(token, process.env.JWT_SECRET_KEY);
//add the data to the request body if you wish
req.user = tokenData;
next();
} catch (err) {
res.status(401).json({
message: "Unauthorized access error!",
});
}
};

Resources