19
votes

My desktop app connects to a web application that's hosted on Google App engine. Once it authenticates it gets an authtoken cookie that it passes along for all future requests. That all works.

But now I want to add "Sign out". I’ve tried to implement Sign Out like this:

- (void)signOut {
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *each in [[[cookieStorage cookiesForURL:[NSURL URLWithString:self.serviceRootURLString]] copy] autorelease]) {
        [cookieStorage deleteCookie:each];
    }
    [self clearCredentialStorage];
}

The problem is that it only seems to work the first time. For instance I can open my app. Sign in. Make some requests. Sign out. Then next time I make a request I'm asked to authenticate again. Good!

But after I authenticate the second time the problem happens. The authentication works. I get the authtoken cookie. I can make requests. But then when I try to log out for the second time (without restarting my app) the authtoken cookie doesn’t seem to get deleted. It does seem deleted from my apps perspective... I ask NSHTTPCookieStorage for the cookies that it has my URL and it returns none. But if I try to make another request (that should require the authtoken cookie) the request just works, I don’t get a 401 response and I'm never asked to authenticate again.

So if I'm understanding things correctly it seems that the cookies are deleted from my perspective, but they are not deleted from the underlying URL loading frameworks perspective.

Of possible interest, maybe the problem is related to: http://www.macworld.com/article/143343/2009/10/safaricookieproblems.html

Does anyone know how to consistently implement "log out" functionality in an app that interacts with a web service?

Thanks, Jesse

2

2 Answers

52
votes
+(void)clearAllCookies {
    NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (NSHTTPCookie *each in cookieStorage.cookies) {
        [cookieStorage deleteCookie:each];
    }
}

I know this is an old question, but here is the answer. We are currently using this with our app to clear out ALL cookies for UIWebView (this only has access to cookies in your app, not shared cross apps in any way).

If you want to clear only specific ones, you can always check the properties of each cookie object before deciding if you want to delete it or not. for example cookie.name isEqualToString@"somename"

Hopefully this helps someone out there.

Edit: as of some iOS version there is an easier way now, there is a new method to clear out cookies by date.

NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[cookieStorage removeCookiesSinceDate:[NSDate dateWithTimeIntervalSince1970:0]];

SWIFT 4.X version: (a lot simpler, one liner)

HTTPCookieStorage.shared.cookies?.forEach(HTTPCookieStorage.shared.deleteCookie)
0
votes

Theory: there are other relevant cookies that are not under your service's URL, because some requests result in a redirect which may get or set cookies on your system.

Also: I recommend using tcpdump for debugging. You'll be able to see exactly what is going over the network, and know exactly what cookies are being sent or received.