views:

306

answers:

11

This question is not about when to use GET or POST in general; it is about which is the recommended one for handling logging out of a web application. I have found plenty of information on the differences between GET and POST in the general sense, but I did not find a definite answer for this particular scenario.

As a pragmatist, I'm inclined to use GET, because implementing it is way simpler than POST; just drop a simple link and you're done. This seems to be case with the vast majority of websites I can think of, at least from the top of my head. Even Stack Overflow handles logging out with GET.

The thing making me hesitate is the (albeit old) argument that some web accelerators/proxies pre-cache pages by going and retrieving every link they find in the page, so the user gets a faster response when she clicks on them. I'm not sure if this still applies, but if this was the case, then in theory a user with one of these accelerators would get kicked out of the application as soon as she logs in, because her accelerator would find and retrieve the logout link even if she never clicked on it.

Everything I have read so far suggest that POST should be used for "destructive actions", whereas actions that do not alter the internal state of the application -like querying and such- should be handled with GET. Based on this, the real question here is:

Is logging out of an application considered a destructive action/does it alter the internal state of the application?

A: 

Well if you let your web application abandon the session through a log out script, you usually don't need either. Normally there's a session variable that's unique for the session you want abandoned.

Rob
Could you elaborate the "log out script"? I'm not sure if you are referring to setting a cookie expiration (which does not eliminate the need for a way of letting users manually logout.)
Daniel Liuzzi
A log out script would end the session of the user (actually: browser) calling it. In ASP.net, the session is a server side object which can be abandoned. PHP has a similar system. Because that browser calls the script that ends the session, it already knows which one to end, eliminating the need for POST or GET variables.
Rob
Yes, I get you now. I already have the script in place, specifically FormsAuthentication.SignOut(), but my question is about *how* to invoke the script, as in GET or POST.
Daniel Liuzzi
Oh you have the url in a form? It doesn't matter if you're not passing any information to it. The worst thing that could happen is someone manually opening the script, logging themselves out. I wouldn't even make it a form field if not neccessary, a link to the script would work as well.If you DO send information to the script, I'd probably go for a POST, so as to not show any information to the user (unless they view the page source), and if they refresh they'll get a warning from their browser (page expired), which might be desirable.
Rob
+2  A: 

To be correct, GET/POST (or other verbs) are actions on some resource (addressed by URL) - so its generally about resource's state and not about application state as such. So in true spirits, you should have a URL such as [host name]\[user name]\session, then 'DELETE' would be the correct verb for log out action.

Using [host name]\bla bla\logout as URL in not really an REST full way (IMO), so why debate about correct use of GET/POST on it?

Of course, I also use GET to an logout url in my applications :-)

VinayC
In that case, I would then argue that having the [user name] part in the URL seems unnecessary, as users always logout from (i.e. DELETE) *their own* session; never other users' :-)
Daniel Liuzzi
Not really - we are saying that session is an resource and we want to delete it. So for uniformly addressing any session, you need to have user name as a part of URL. Your argument is as good as saying issuing PUT action on [photo gallary]\pictures means you are adding to your photos (available at [photo gallary]\[user name]\pictures). Different resources has to be addressed explicitly, there can't be any implicitness into it. The site may allow other users to add pictures to your gallery - it would be a part of access control just as you can have a super user who can kill anybody's sessions.
VinayC
Philosophically speaking, you could call sessions and photos 'resources', but realistically I wouldn't treat them the same. Session are always intrinsically restricted to the current user (hence the name Session) and, at least in ASP.NET, there is no way of accessing another user's sessions. Even the application developer has no direct way of enumerating all active sessions, or means to kill sessions individually. You could restart the application to kill all sessions (InProc), but I wouldn't call that access control. URLs aside, the question still remains: GET or POST?
Daniel Liuzzi
Resource, hence its address (URL) are important part of REST. So if you choose URL as I said, DELETE becomes the correct word - not GET or POST.Also, even if you are limiting yourself to ASP.NET, you can always have your custom state provider that can give you way to enumerate through sessions and kill other sessions if needed. For out of box in-proc sessions, some fiddling in global.asax should give you the functionality. Its really a question of whether such functionality would be needed or not. For infrequent needs, folks tend to re-start web site to kick people out of site.
VinayC
+1  A: 

The reason to avoid GET, as you observed, is "destructive actions," or actions that alter state. These are the things that you really don't want Google's Spider to do. For instance, deleting products from your catalog or placing fake orders is one of these things. Logout alters state in your application; it is thus also a destructive action.

In the case of logging out, though, you can't possibly go wrong: how is a web spider going to accidentally log in, in the first place? If GET is easier to implement, then you should do it.

(Pedantically speaking, I believe logging out should DELETE a "session" object.)

Andres Jaan Tack
That's the reason I used web accelerators in my example. As opposed to spiders, web accelerators can have access to the session state (think a Firefox extension), and could theoretically be crawling password-protected areas of the site, i.e. where a logout link would likely be.
Daniel Liuzzi
Ah, I skimmed over that part. Still, though, take the low-hanging fruit and start with GET. Later on, if you can reproduce the problem easily and/or if users complain, I'd go through the pain of POST/DELETE requests then. YAGNI.
Andres Jaan Tack
+1  A: 

The scenario of pre-caching is an interesting one. But I'm guessing that if lots of sites inc SO do not worry about this then maybe you shouldn't either.

Or perhaps the link could be implemented in javascript?

Edit: As I understand it, technically a GET should be for read-only requests, that do not change application state. A POST should be for write/edit requests that change state. However other application issues might prefer GET over POST for some state-changing requests, and I do not think there is any problem with this.

Richard
@Richard - Thanks. The *DB* state wouldn't be changed, but the *session* state would. The only problem I see is the one I mentioned in the question, about users getting kicked out. Non-destructive but rather annoying. I usually go by the "if the big guys do it, then it must be OK" mantra too. I just wanted to know what opinion others have on this.
Daniel Liuzzi
+3  A: 

Logging out does nothing to the application itself. It changes the user's state in relation to the application. In this case, it appears your question is more based on how should the command be initiated from the user to begin this action. Since this is not a "destructive action", sure the session is abandoned or destroyed but neither your application or your data is altered, it is not infeasible to allow both methods to initiate a log out procedure. The post should be used by any user initiated actions (e.g. - user clicks "Log out"), while get could be reserved for application initiated log outs (e.g. - an exception detecting potential user intrusion forcibly redirects to the login page with a logout GET).

Joel Etherton
Interesting; I never thought of it this way. +1.
strager
This could conceivably depend on the application (some kind of "cascading delete" behavior), but you're right.
Andres Jaan Tack
A: 

in my source code, it only set cookies...

eyhelchiu
I'm sorry but I have no idea what you're trying to say...
Daniel Liuzzi
A: 

If you use a form submission (using GET) to log out, instead of a link, your problem is solved as no accelerator would auto submit a form.

AlexW
I understand forms can also issue GET requests, but to me the main reason to use GET is to eliminate the form in the first place; if I have to bother with a form, then I might as well use POST. I'm using ASP.NET MVC, so nearly no difference in code in the controllers (i.e. [HttpGet] vs. [HttpPost])
Daniel Liuzzi
True. But as I'm sure you know, any Accelerator cannot follow forms automatically, so a good old fashioned form is your best bet here. I use ASP too and I know extra Forms can be a pain.
AlexW
+4  A: 

In REST there should be no session, therefore there is nothing to destroy. A REST client authenticates on every request. Logged in, or out, it's just an illusion.

What you are really asking is should the browser continue sending the authentication information on every request.

Arguably, if your application does create the illusion of being logged in, then you should be able to to "log out" using javascript. No round trip required.


Fielding Dissertation - Section 5.1.3

each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client

Darrel Miller
I actually was not aware of this. Then I guess my app won't be very RESTful at all, as I'm using ASP.NET MVC with FormsAuthentication and it relies on sessions...
Daniel Liuzzi
@Daniel I added the relevant section from the definition of REST.
Darrel Miller
@Darren - Good read, thanks. Bookmarked :)
Daniel Liuzzi
but in practice the login info is kept in a cookie marked with the `httponly` attribute to prevent some xss risks, which means it can only be reset from the server (short of manually clearing the cookie)
Remus Rusanu
@Remus What's wrong with manually clearing the cookie?
Darrel Miller
'Manual' as in the user goes to the Browser settings and chooses the 'Clear cookies' option. Hardly an acceptable way to 'log off' a web site.
Remus Rusanu
@Remus Ahhh, how the illustrious web browser makes writing web apps so painful.
Darrel Miller
+1  A: 

One way GET could be abused here is that a person (competitor perhaps:) placed an image tag with src="<your logout link>" ANYWHERE on the internet, and if a user of your site stumbles upon that page, he will be unknowingly logged out.

Raveren
No, this is not right. A log out link will only work if the correct cookie data is sent, which it will not be from another domain. And even if the session id is stored in the url, that wouldn't work either as these change for every session.
Richard
Wow, I never thought of that! So there, another reason not to use GET, and another reason I don't understand why everybody does it. Damn it, now I'm temped to include a http://stackoverflow.com/users/logout "image" too my post and see what happens :-D
Daniel Liuzzi
@Richard - Makes sense, but the problem would exist in community-driven sites such as SO, right? The domain would be the same in this case.
Daniel Liuzzi
@Daniel: I'm not sure cookie data is sent with an image request - although I never thought about this! But I doubt it.
Richard
src= is a simple browser request, it does not come from server side, but from the client. It carries all cookies and comes from the user IP. That is why ad tracking pixels work. Only way to determine such exploit would be to check the referrer.
Raveren
@Raveren: Checking the referrer could work, but unfortunately it isn't very reliable, as it merely is a header sent by the browser, so it's trivial to alter/fake. Namely, there's a Firefox extension called RefControl (https://addons.mozilla.org/firefox/addon/953) that allows you to do just this.
Daniel Liuzzi
A: 

Simple answer: I almost always use GET. I haven't had a problem and many other sites also do this.

David Radcliffe
A: 

I don't see how loging out (de-elevating user permissions) is a desctructive action. Thats because the "logout" action should be only available to users that are already logged in else it would be obsolete.

A random generated string contained in your browser cookies is all representing your user session. There are tons of ways to destroy it so effectively logging out is merely a service to your visitor.

jpluijmers