Is it safe to generate a JWT token on server-side and to pass it in a sign-up request within the response JSON back to the client?
Currently I’m generating a JWT in the following way:
import express from "express";
import jwt from "jsonwebtoken";
const generateToken = (id: any, res: express.Response) => {
const token = jwt.sign({ id }, process.env.JWT_SECRET as string, {
expiresIn: "15d",
});
return token;
};
export default generateToken;
Which is being used by the following auth.controller:
import express from "express";
import User from "../models/user.model";
import bcrypt from "bcrypt";
import generateToken from "../utils/generateToken";
export const signup = async (req: express.Request, res: express.Response) => {
try {
const { username, password, email } = req.body;
// Check if all fields are filled in and been sent
if (!username || !password || !email) {
return res
.status(400)
.json({ message: "Please fill in all fields" });
}
// Check if the user already exists
const userCheck = await User.findOne({ username });
if (userCheck) {
return res.status(400).json({ message: "User already exists" });
}
// Check if the email already exists
const emailCheck = await User.findOne({ email });
if (emailCheck) {
return res.status(400).json({ message: "Email already exists" });
}
// Hash the password
const salt = await bcrypt.genSalt(12);
const hashedPassword = await bcrypt.hash(password, salt);
// Create a new user
const newUser = new User({
username,
password: hashedPassword,
email,
});
// Generate and send token
if (newUser) {
const token = generateToken(newUser._id, res);
await newUser.save();
return res.status(201).json({
user: newUser,
token: token,
});
} else {
return res.status(500).json({ message: "Something went wrong" });
}
} catch (error) {
console.log(`Error in signup controller: ${error}`);
return res.status(500).json({ message: "Something went wrong" });
}
};
As the code shows, I’m generating the JWT token and send it from the backend to the client within a response from a client post.
// Generate and send token
if (newUser) {
const token = generateToken(newUser._id, res);
await newUser.save();
return res.status(201).json({
user: newUser,
token: token,
});
} else {
return res.status(500).json({ message: "Something went wrong" });
}
In the client it will be saved to redux local-storage.
auth:"{"session":{"signedIn":true,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjY2MWE1Y2U5NjAzYWRhNTMzODA2YjVkZSIsImlhdCI6MTcxMzAwMzc1MywiZXhwIjoxNzE0Mjk5NzUzfQ.v23o2WIIz6bYqxpP_wwG5Q3DZgwXtdPX1pMAnGsDKs4"},"user":{"avatar":"https://via.placeholder.com/150","username":"test","email":"[email protected]","authority":"user"}}"locale:"{"currentLang":"en"}"_persist:"{"version":-1,"rehydrated":true}"
Question: Is this a safe enough way to store it within the local-storage or is the set-header way required?
3
Answers
Storing JWT tokens in local storage can expose your application to security risks, particularly XSS (Cross-Site Scripting) attacks. If malicious scripts are injected into your website, they can access tokens stored in local storage, potentially leading to unauthorized access.
A more secure approach is to use HTTP-only cookies for storing JWT tokens. By setting the token as an HTTP-only cookie in the response header, you prevent client-side scripts from accessing it, mitigating the risk of XSS attacks. Additionally, you can enhance security by setting the Secure and SameSite attributes for the cookie.
Example
This approach ensures that the JWT token is securely stored and transmitted between the client and server, reducing the risk of security vulnerabilities. However, remember to implement proper CSRF (Cross-Site Request Forgery) protection to safeguard against CSRF attacks when using cookies for authentication.
In most of the websites, JWT is created on server side, and sent back to client.
There are couple of ways you can send this JWT to client
Storing JWT in localstorage is a common practice. Reading that in client side is very hard unless you expose the JWT secret to your users(you are not doing it). You can use localstorage, unless your application has very sensitive functionality such as banking or stocks, in that case a session based would be preferred..
Cookie will be nice.It will be sent with request.