16

My web app is made so that when a user logs in the server adds a Set-Cookie header to the response, like this:

Set-Cookie:JSESSIONID=1; Path=/myApp/; Secure

On logout I try to delete this cookie on the client (browser), as I don't care if the session was successfully destroyed on the server as long as the cookie is deleted. Any lingering "ghost" sessions will be cleaned up from time to time on the server.

However, my app is unable to delete the JSESSIONID cookie. Say the logout function was called from https://test.myserver.com/myApp/app/index.html#/mySubPage and the logout function does:

delete $cookies["JSESSIONID"];
$location.path("/login");

The cookie isn't deleted. Refreshing the cookies listing in the "Resources" tab in Chrome Developer Tools shows it's still there. Reloading the login page and refreshing the cookies listing in the "Resources" tab still shows the cookie.

Why can't I delete the cookie from my Javascript client when it's not a HTTPOnly cookie? Is it the path that's causing problems? Shouldn't be, as the script is running on a page included in the cookie's path. Cookies aren't really that difficult to deal with normally, so I'm well aware that there might be something trivial I'm overlooking here - but any help would be much appreciated.

UPDATE:

I had given the wrong path to my app in my original post. It's now edited to reflect the correct path (well, abstractly). It turns out that this was critical information for the question. AngularJS uses the complete relative path of the app as the path attribute of all cookies it creates/deletes, so since our server set the cookie with a path of /myApp/ and the app was running on the relative path of /myApp/app, Angular was trying to delete the former cookie, which doesn't exist (in order to overwrite or delete an existing cookie the name, domain, and path all need to be identical to those used when creating the cookie).

Joe Dyndale
  • 1,073
  • 1
  • 15
  • 32
  • Did you include ngCookies in your module? Like angular.module('myApp', ['ngCookies']) – asgoth Jan 07 '13 at 14:09
  • Yes. I can read the cookie without any problems. I'm not getting any errors anywhere, the cookie simply stays put even though it should have been deleted. – Joe Dyndale Jan 07 '13 at 14:14
  • 1
    Have you tried with $cookieStore.remove(key)? – asgoth Jan 07 '13 at 14:23
  • One other thing, does $scope.digest() occurs? What triggers the cookie delete? If it is from outside angular, you'll have to use $scope.$apply() to kickoff the watches. If you're debugging (Chrome/Firebug), put a breakpoint in push() function in angular-cookies.js (best use the non-minified version). – asgoth Jan 07 '13 at 14:34
  • I'm not doing it outside of Angular, so there's no need for $scope.$apply(). I haven't tried $cookieStore.removeKey(), but since it simply does `delete $cookies[key];` there wouldn't be any difference. – Joe Dyndale Jan 07 '13 at 14:41
  • Do try to inspect the push() function. This function should be called to push cookie changes to the browser (at least, that's what it looks like). – asgoth Jan 07 '13 at 14:45
  • Tried it. Stepped through a lot of code as well. Looks like the lastCookies and $browser.cookies arrays are updated correctly. – Joe Dyndale Jan 07 '13 at 15:00
  • 1
    Had the exact same problem a little while ago. It seems the $.cookies is only able to reach cookies it has set itself. My solution was setting the same cookie path and clearing them with jQuery cookies outside the angular app. – Index Dec 18 '13 at 13:27
  • My server sets a "token" cookie with path=/. After "delete $cookies['token']" it appears to angularjs that the cookie is gone, but I see in subsequent browser requests that the cookie is still being sent. KG, can you show a bit more about the jQuery workaround? I tried setting $document.cookie directly, to force the cookie to expire ('token' + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/') but that doesn't appear to have any effect. – jamshid Jun 17 '14 at 18:20

3 Answers3

11

I suppose you should check the responses from server - maybe they include a 'set cookie' header field that sets the cookie's value.

Here is a Plunker example that illustrates how you can add/change/delete/watch for cookie's value (but without server-side responses that can change cookie values).

But generally, $cookies object is kind of 'proxy object' that is two-way tracked by AngularJS ngCookies module and from one side change its fields when browser's cookies are changed (so you can $watch for changes) but also changes are reflected to browser's real cookies, so you can change this object.

So the only reason why cookies cannot be deleted is that you delete them on browser, and server sets the cookie again and after reloading page it is still there.

joragupra
  • 692
  • 1
  • 12
  • 23
Valentyn Shybanov
  • 19,331
  • 7
  • 66
  • 59
  • I have checked the response from the server, and it had no cookies attatched :( – Joe Dyndale Jan 08 '13 at 10:10
  • +1 for providing a good explanation and good examples of using the $cookie service. However, it didn't solve the problem for me so I can't mark it as the accepted answer. It's my own fault you couldn't answer the question though, as a crucial mistake was made when I wrote the question (wrong application path). I have updated the question with the correct path and the explanation of what the problem turned out to be. – Joe Dyndale Jan 09 '13 at 09:38
5

Be aware of the cookie domain of the cookie you want to delete. If you're working with multiple subdomains (i.e. one for static resources, another for the api) your problem could be that you're trying to delete a cookie for the wrong domain.

Have a look at your cookies with your browser's developer tool of choice. Whatever domain is set for the cookie you want to delete that you're having problems with, specify it in the options parameter to the remove method.

$cookies.remove('JSESSIONID', {domain: 'domain.tld'});

SECURITY TIP: Deleting the session ID via Javascript doesn't delete the session on the server. If your session IDs leak you could suffer from session fixation. It would be better to delete the cookie via calling a logout endpoint in your API which would clear the session completely on the server so that it can't be re-used.

2upmedia
  • 2,832
  • 1
  • 20
  • 16
  • Like the OP, my problem was with the path, not the domain, but setting the path in the options finally got rid of the cookie for me. This is the answer that pointed me in the right direction. – Danny Feb 23 '16 at 22:55
  • I tried many solutions, but this is the only one that gave me satisfaction : Setting the path AND domain when removing the cookie : $cookies.remove("sessionId", {path: "/", domain:"mydomain.fr"}); – tchoum Sep 15 '16 at 14:25
3

The answer that you gave in the update seems to be correct: Angular $cookieStore can only work on cookies whose path value is the same as the current path.

The way to trick it is to use the solution given by ajspera on this issue:

<head>
  <base href="/">
</head>

Simply add <base href="/"> to your head element of the HTML, and at that point it works.

The alternative solution is to set the path of the cookie using the server that sent it. In Node.js Express that looks like

res.cookie('specialCookie', 'special!', {path: '/myApp'});

Note that for me it seems like $cookieStore strips out the trailing slash, so you may need to try it both ways.

srlm
  • 3,186
  • 2
  • 27
  • 40
  • Thank you for actually providing instructions for how to solve this. I got the base href approach working, but I think there may be [undesirable consequences](http://stackoverflow.com/questions/1889076/is-it-recommended-to-use-the-base-html-tag), so I'd prefer to set the path from the server... but I can't seem to figure out where the value for "/myApp" should come from. I'm running on localhost:8080/mypage.html, with the argument to the angular.module 'theApp'. But setting path to '', /theApp, or /theApp/ all result in no Angular access to the cookie. – Dev93 Oct 05 '14 at 18:27
  • "/myApp" is the path option for the cookie that you're sending. In your case you should use "/mypage.html". Alternatively you could try no path option (default to the path of the request URL) or maybe "/mypage". – srlm Oct 06 '14 at 05:19
  • But I want the cookie to be available for all pages of my site. Any way to do that? In the original poster's question, he has site/myapp/app/index.html#topic, but only references myapp/app in the solution. – Dev93 Oct 06 '14 at 15:16