Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Node TS: JWT token sign to verify authentication between client and backend question

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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\":\"test@gmail.com\",\"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?

>Solution :

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

if (newUser) {
    const token = generateToken(newUser._id);
    await newUser.save();

    res.cookie("jwt", token, {
        httpOnly: true,
        secure: true,
        sameSite: "strict"
    });

    return res.status(201).json({
        user: newUser
    });
} else {
    return res.status(500).json({ message: "Something went wrong" });
}

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading