23

Pretty simple. I set a cookie like so in my /user/login route:

if (rememberMe) {
    console.log('Login will remembered.');
    res.cookie('user', userObj, { signed: true, httpOnly: true, path: '/' });
}
else {
    console.log('Login will NOT be remembered.');
}

I've already set my secret for cookie-parser:

app.use(cookieParser('shhh!'));

Pretty basic stuff. Everything is working great insofar as I'm able to retrieve whatever I stored in the cookie:

app.use(function (req, res, next) {
    if (req.signedCookies.user) {
        console.log('Cookie exists!');
        req.session.user = req.signedCookies.user;
    }
    else {
        console.log('No cookie found.');
    }

    next();
});

This middleware is called before anything else, so for the sake of the argument "Cookie exists!" is always logged in my console if the cookie is valid.

The problem is when I try to delete the cookie. I've tried res.clearCookie('user'), res.cookie('user', '', { expires: new Date() }), and I've tried passing in the same flags (that I pass to res.cookie() in /user/login). I've attempted to use combinations of these methods, but nothing has worked.

Currently, the only way I am able to clear the cookie (and not receive the "Cookie exists!" log message) is by clearing my browser history. Here is what my logout route looks like:

route.get('/user/logout', function (req, res, next) {
    res.clearCookie('user');
    req.session.destroy();
    util.response.ok(res, 'Successfully logged out.');
});

It seems as though I can't even modify the cookie value; I put

res.cookie('user', {}, { signed: true, httpOnly: true, path: '/' })

in my logout route, but the cookie value remains unchanged.

Kenny Worden
  • 4,335
  • 11
  • 35
  • 62
  • Which session & cookie middleware are you using? – Paul Jul 25 '16 at 01:19
  • cookie-parser: https://github.com/expressjs/cookie-parser – Kenny Worden Jul 25 '16 at 01:20
  • Possible duplicate of [Destroy cookie NodeJs](http://stackoverflow.com/questions/27978868/destroy-cookie-nodejs) – Paul Jul 25 '16 at 01:23
  • 4
    I'm going to have to disagree with you that this question is a duplicate. I'm not even using the same cookie middleware, and I've tried the solution to that question to no avail. – Kenny Worden Jul 25 '16 at 01:25
  • Fair enough; sorry, I don't know why it's not working then. But as a non-answer to your question, I'd recommend *not* managing your own cookies. I've not set my own cookie in Express for years, ever since I started using Passport.js to manage my user sessions for me. Much cleaner and simpler. – Paul Jul 25 '16 at 01:29
  • Appreciate the tip, thanks – Kenny Worden Jul 25 '16 at 02:09
  • I know this is an old question, but how did you manage to resolve this? If you did, please post it as an answer below. Thanks – Milan Velebit Oct 06 '17 at 13:25
  • @MilanVelebit I did not end up solving this. I used passport.js instead. – Kenny Worden Oct 06 '17 at 18:38

8 Answers8

19

I realized after a long and annoying time that my front end was not sending the cookie to the end point were I was trying to clear the cookie...

On the server:

function logout(req, res) {
  res.clearCookie('mlcl');
  return res.sendStatus(200);
}

And on the front end,

fetch('/logout', { method: 'POST', credentials: 'same-origin' })

adding the "credentials: 'same-origin'" is what made the clearCookie work for me. If the cookie is not being sent, it has nothing to clear.

I hope this helps. I wish I had found this earlier...

Kevin
  • 465
  • 6
  • 12
  • Interesting. I have since abandoned the project that I asked the original question for. If anyone can confirm that this fixes the problem, I will accept this answer. – Kenny Worden Apr 03 '18 at 02:01
  • adding `credentials: "include"` also works – Jeremy Bernier Jan 31 '23 at 20:05
  • Can it be cleared with a simple hyperlink or do I have to use fetch with the credentials option? I have `logout` and if that's the only way I'd have to change that to a javascript call – 1.21 gigawatts May 04 '23 at 05:02
  • You would have to send the credentials/ cookie so that the backend would know who to logout. If no information is sent, then the backend wouldn't be able to logout any user – Kevin May 08 '23 at 17:06
18

Even though it's not gonna help the author of this question, i hope this might help someone. I run into the same problem that i could not delete cookies in my React app that was using Express api. I used axios, and after a couple of hours i was finally able to fix it.

await axios.post('http://localhost:4000/api/logout', { } , { withCredentials: true })

{ withCredentials: true } is what made it work for me.

This is my Express code:

 const logOutUser = (req, res) => {
  res.clearCookie('username')
  res.clearCookie('logedIn')
  res.status(200).json('User Logged out')
}
Noob
  • 2,247
  • 4
  • 20
  • 31
  • In my case, I opted out of the request body. The third argument became the request body and cookies are not sent to the server. Your code saved me. – angel_dust Sep 29 '22 at 17:55
5

Judging by (an extensive) search and a random thought that popped into my head, the answer is to use

res.clearCookie('<token_name>',{path:'/',domain:'<your domain name which is set in the cookie>'});

i.e.

    res.clearCookie('_random_cookie_name',{path:'/',domain:'.awesomedomain.co'}); 

Note the . which is specified in the cookie, because we use it for subdomains (you can use it for subdomains without the dot too, but it's simply safer to use one).

TLDR; You have to provide a route and domain: in the backend, so that the request is made to the same endpoint in the frontend.

Milan Velebit
  • 1,933
  • 2
  • 15
  • 32
4

Make sure you are sending your credentials to be cleared

Even though it's only a /logout endpoint, you still need to send credentials.

// FRONT END
let logOut = () => {

  fetch('logout', {
    method: 'get',
    credentials: 'include', // <--- YOU NEED THIS LINE
    redirect: "follow"
  }).then(res => {
    console.log(res);
  }).catch(err => {
    console.log(err);
  });

}


// BACK END
app.get('/logout', (req, res) => {
  res.clearCookie('token');
  return res.status(200).redirect('/login');
});
joshuakcockrell
  • 5,200
  • 2
  • 34
  • 47
2

Had a nightmare getting this to work as well this works for me hopefully helps someone.

Express router

router.post('/logout', (req, res) => {
    res.clearCookie('github-token', {
        domain: 'www.example.com',
        path: '/'
    });
    return res.status(200).json({
        status: 'success',
        message: 'Logged out...'
    });
});

React frontend handle logout.

const handleLogout = async () => {
    const logout = await fetch('/logout', {
        method: 'POST',
        credentials: 'include',
    });
    if (logout.status === 200) {
        localStorage.clear();
        alert('Logged out');
    } else {
        alert('Error logging out');
    }
};

I am setting the cookie in my auth call like this.

res.cookie('github-token', token, {
    httpOnly: true,
    domain: 'www.example.com',
    secure: true
});

Important you need to add the path and domain in the clearCookie method.

user1503606
  • 3,872
  • 13
  • 44
  • 78
0

Path needs to be correct. In my case it was a typo in path

kenodek
  • 362
  • 1
  • 2
  • 13
0

Nov 2022 (Chrome) - What worked for me

Frontend:

const logOut = async () =>{
  await axios.post(LOGOUT_URL, {}, {withCredentials: true}) // <-- POST METHOD, WITH CREDENTIALS IN BODY
}

Backend:

res.clearCookie('jwt') // <- NO EXTRA OPTIONS NEEDED, EVEN THOUGH HTTPONLY WAS SET
return res.sendStatus(204)
Bersan
  • 1,032
  • 1
  • 17
  • 28
0

I am new to this but adding a return (return res.sendStatus(204);)to Backend function is what deleted the cookie for me, hope it helps. without return it does not delete the cookie but only logs "session over"

 app.post("/logout", (req, res) => {
  if (req.session.user && req.cookies.user_sid) {
    res.clearCookie("user_sid");
    console.log("session over");
    return res.sendStatus(204);
  } else {
    console.log("error");
  }
});
P.R. D
  • 1
  • 1