Sponsored Link •
|
Summary
While it may be attractive from the usability perspective to let users click on a link in an email to confirm a registration, it violates one of the cardinal rules of the web: don't change state on HTTP GET requests. This weblog post explains the problem and suggests solutions.
Advertisement
|
In REST Mistake #1: Confirming GETs (See Resources), Elliotte Rusty Harold described a conversation he and I had last week after the Software Developer conference about confirmation emails that use GET to change state. Over dinner he described a scheme he had devised to enable users to post comments to his blog without registering, while still requiring the user to authenticate. In his scheme you would need to supply your email with your comment. After submitting your comment, you would receive a confirmation email containing a link. Clicking on the link in the email would approve your comment. You hadn't registered, but you authenticated yourself as the person who has that email. He said this approach did a good job of eliminating comment spam and noisy comments.
I pointed out to Rusty that the scheme violates the rule not to change state as a result of a GET. When you click on the link in your email, it opens up the browser, and the browser does an HTTP GET to retrieve the page. If that action actually approves the comment, then you've changed the state of the web application as a result of the GET. To make such changes, however, you should use POST. When Rusty went back to look at his implementation, it turned out that only his description of his scheme had the flaw, not the actual implementation. He had forgotten how he had implemented it.
The reason this flaw was apparent to me is that at Artima we actually did send out emails that used a similar one-click mechanism, which had the same flaw. One day, however, it dawned on me we were changing state on GET requests, and we altered our design to POSTs.
We initially chose the one-click design to maximize ease of use. I wanted it to be easy for a user to unsubscribe from a newsletter, for example. Previously to unsubscribe you had to log in to your Artima account and unclick a checkbox in your settings. It was a several step process, which would grow to even more steps if you forgot your password and had to go through the process to get a new one. In addition, we wanted it to be easy for you to confirm an email address by clicking on a link in an email we send after you register.
The HTTP specification says that you mustn't hold users accountable for any state changes that result from a GET. It doesn't imply you can't change state at all on a GET. For example, it seems quite reasonable to log a user's GET requests (which changes state on the server), even if sometime later that user can look and see a report of that GET request (which means the state change can ultimately be visible to the user). But you shouldn't do something on a GET that from the user's perspective indicates they have agreed to something. This is an important aspect of HTTP, which enables various automated activities including caching, prefetching, and crawling.
Prefetching is a good example of why you should avoid using one-click confirmation emails. Google has a tool called Web Accelerator that you can install in your browser to speed up your experience of surfing of the web. Among other techniques, the Web Accelerator prefetches URLs mentioned on the page you are looking at, so that in case you click on a link, the page may already have been fetched and cached at your browser, in which case you won't have to wait for it to download.
Imagine you have installed Google Web Accelerator in your browser, and you are reading your email via Yahoo Mail. You open an email that says, "Click the following link to verify this email address and enable your newly created Artima account." Well, you've never heard of Artima, and you didn't attempt to register there, so you don't click. Unfortunately, however, because you are looking at that email in a web page, Google Web Accelerator on your browser may decide to prefetch the confrimation page to accelerate your access of it in case you click on the link. So even though you were careful to not click on the link, Web Accelerator performed the GET anyway. Thus, Google Web Accelerator verified the email and enable the account, even though you didn't actually attempt to register in the first place and never clicked on the confirmation link. The problem is not with Web Accelerator, however, but with one-click email confirmation itself.
The solution we deployed on Artima was simply that when you click on a link in an email, we take you to a page that contains a button to press to perform the action. To verify an email on a new account, for example, you click on the link in the email, which does a GET. The GET returns a page that says, "Please click on this button to verify your email," and provides a form button to press that sends a POST. This solves the HTTP problem, but now a smooth one-click process has become a more cumbersome click-read-then-click-again process. If you can send HTML email, then you can put the button right in the email, but if you send text email, you are left with a GET-then-POST solution if you want to use HTTP. (You could also have people reply to an obscure email address with something obscure in the subject, but I think that for most users using the web for email confirmation will be easier.)
On Rusty's blog a commenter named Avery Regier suggested that the page you return from the GET contain JavaScript that when executed performs the POST. If JavaScript is enabled, then the user just clicks once, and sees a page that indicates the confirmation was successful. If JavaScript is not enabled, then they see a button and some text inviting them to complete the confirmation by pressing the button. (The JavaScript could replace the invitation text and button with a confirmation message after it successfully submits the POST.) Avery says that, "Google’s spidering won’t run the JavaScript, so it is safe there." Regardless, for a POST that is supposed to indicate the user is agreeing to something, or confirming something, I would rather not make the correctness of that activity depend on whether a software agent (be it a web accelerator or search engine or something else) that grabs a page with a GET runs the JavaScript on that page or not.
REST Mistake #1: Confirming GETs:
http://cafe.elharo.com/web/rest-mistake-1-confirming-gets/
The W3C's URIs, Addressability, and the use of HTTP GET and POST:
http://www.w3.org/2001/tag/doc/whenToUseGet.html
Google Web Accelerator:
http://webaccelerator.google.com/
Have an opinion? Readers have already posted 21 comments about this weblog entry. Why not add yours?
If you'd like to be notified whenever Bill Venners adds a new entry to his weblog, subscribe to his RSS feed.
Bill Venners is president of Artima, Inc., publisher of Artima Developer (www.artima.com). He is author of the book, Inside the Java Virtual Machine, a programmer-oriented survey of the Java platform's architecture and internals. His popular columns in JavaWorld magazine covered Java internals, object-oriented design, and Jini. Active in the Jini Community since its inception, Bill led the Jini Community's ServiceUI project, whose ServiceUI API became the de facto standard way to associate user interfaces to Jini services. Bill is also the lead developer and designer of ScalaTest, an open source testing tool for Scala and Java developers, and coauthor with Martin Odersky and Lex Spoon of the book, Programming in Scala. |
Sponsored Links
|