How to set cookie with JWT token in ReactJS frontend using Node, Express, Axios

Viewed 3604

so I can successfully put in the access-token to the cookie with postman and validation works fine but on my frontend when I login the access-token is not going in a cookie

this is in my routes/Users.js

router.post('/login', async (req, res) => {
    const { username, password } = req.body;

    const user = await Users.findOne({ where: {username: username}});

    if(!user) res.status(400).json({error: `Username does not exist!`});

    bcrypt.compare(password, user.password).then((match) => {
        if(!match) res.status(400).json({error: 'Wrong password!'})

        const accessToken = createTokens(user);

        res.cookie('access-token', accessToken, {
            maxAge: 60*60*24*30*1000, //30 days
            secure: false,
            httpOnly: false
        });

        user.password = undefined;

        res.json(accessToken);
    })
});

controllers/jwt.js

const { sign, verify } = require('jsonwebtoken');

const createTokens = (user) => {
    const accessToken = sign(
        { username: user.username, id: user.user_id }, 
        'e2ereactsecret'
    );
    return accessToken;
};

const validateToken = (req, res, next) => {
    const accessToken = req.cookies['access-token']

    if (!accessToken) 
        return res.status(400).json({error: 'User not authenticated!'})

    try {
         const validToken = verify(accessToken, 'e2ereactsecret')
         if(validToken) {
            req.authenticated = true
            return next();
         }
    } catch(err) {
        return res.status(400).json({error: err})
    }
};

module.exports = { createTokens, validateToken };

And here is the login function in my react frontend:

    const login = (e) => {
        e.preventDefault();

        const config = { headers: {"Content-Type":"application/json"}};
        const data = { username: username, password: password };
        axios.post('http://localhost:4000/users/login', data, config).then((res) => {
            console.log(res);
          });
    }

this is what I get with the console.log, the token is there but it doesn't go into the cookies.

{data: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZ…DYzfQ.dm1nUa-9z7AQkvirCTM3jrC9a_mx_hsA2waDqQs3cD8", status: 200, statusText: "OK", headers: {…}, config: {…}, …}
config: {url: "http://localhost:4000/users/login", method: "post", data: "{\"username\":\"juan\",\"password\":\"password123\"}", headers: {…}, transformRequest: Array(1), …}
data: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imp1YW4iLCJpZCI6MiwiaWF0IjoxNjIzMDM0NDYzfQ.dm1nUa-9z7AQkvirCTM3jrC9a_mx_hsA2waDqQs3cD8"
headers: {content-length: "141", content-type: "application/json; charset=utf-8"}
request: XMLHttpRequest {readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, onreadystatechange: ƒ, …}
status: 200
statusText: "OK"
__proto__: Object

I'm really confused right now. lol.

2 Answers

Try changing the httpOnly setting to true.

The httpOnly setting means that the cookie can’t be read using JavaScript, but can still be sent back to the server in HTTP requests. Without this setting, an XSS attack could use document.cookie to get a list of stored cookies and their values.

Your backend and your frontend are on two different domains and each domain stores its cookies separately.

To store cookies in React, you can use the vanilla js way:

const login = (e) => {
    e.preventDefault();

    const config = { headers: {"Content-Type":"application/json"}};
    const data = { username: username, password: password };
    axios.post('http://localhost:4000/users/login', data, config).then((res) => {
        document.cookie = "token=" + res./*token location*/
        console.log(res, document.cookie);
      });
}

You can learn more about this way at https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie

There are also libraries that can also do this for you. react-cookie and universal-cookie are two.

Related