2

When a user signs up to a web app, they often get a confirmation email. This email will contain a link. Once the user clicks the link, the app confirms the user's account as correctly associated with said email, perhaps by changing a confirmed field on the user document from false to true.

My question:

  1. The endpoint changes data (ei: user.confirmed from false to true) so this action isn't safe*.
  2. The link is a GET request.

Don't these two facts violate HTTP standards? GET requests are supposed to be safe. So PATCH seems more appropriate for changing the confirmed field. However, there is no way to make a link in an email a PATCH request.

How do software engineers handle this inconsistency? Is it just a violation that's accepted? Or is there a correct way to implement this so that we don't violate HTTP standards.

*An HTTP method is safe if it doesn't alter the state of the server. source

9
  • The endpoint data change should be implicit - the request itself doesn't carry any information, but the usage of the link itself is the information.
    – Aganju
    Feb 20 at 18:20
  • 1
    From your “safe” link: “Even if safe methods have a read-only semantic, servers can alter their state: e.g. they can log or keep statistics.” The verification email link seems to fall into this category. Feb 20 at 18:22
  • @JamesMcLeod I'm not sure I understand. The next sentence is "What is important here is that by calling a safe method, the client doesn't request any server change itself..." In the example, logging or keep statistics don't seem to be server changes. The page describes them as "state changes" not server changes. And then says server changes should not occur. Changing user.confirmed to true does seem like a server change. Feb 20 at 18:48
  • 2
    From the HTTP 1.1. spec on safe methods: "The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them. " w3.org/Protocols/rfc2616/rfc2616-sec9.html
    – bdsl
    Feb 20 at 18:57
  • 1
    I'm imagining the program that fetches you a preview of the page when you receive a link (ala Skype, Discord), and suddenly the link the user hasn't clicked is now invalid.
    – Ian Boyd
    Feb 21 at 4:53
6

Rather than being language lawyers and analysing the spec, let's look at the possible downside of a GET request changing the state in this case:

  • The action might be triggered without user interaction, e.g. by a malware scanner, link previewer, or cache primer.
  • Correlation against a particular user ID might be exploitable with CSRF.

Regardless of whether pure theory or practical considerations motivate us, we could reasonably ask this:

I want to implement an e-mail based confirmation system, but I want to avoid side-effects in GET requests. How can I do it?

The solution is that the GET request itself doesn't change the state, it just returns a custom form, to be submitted with POST. In an abstract description, the GET request is reading a resource which reflects the current status of a particular transaction; the form is a convenient representation of that transaction with hypermedia to transition to a new status. In a more concrete set of steps:

  1. Generate a random URL associated with the pending registration.
  2. Include that URL in the e-mail to the user.
  3. When that URL is requested, check if the registration is still pending. If not, skip to (6).
  4. Show an HTML form with a button for the user to complete the confirmation process. The target of the form can be the same URL, but with a method of POST.
  5. When the POST request for the URL is received, complete the registration process.
  6. Show the user a "thank you, your address is now confirmed" page.
8

Let's have a look into the RFC-7231: 4.2.1. Safe Methods. Safe methods are allowed to do state changes, althoug it is highly not recommended. So this is not a violation of the Standard. It's more a deviation from the convention to use GET-Requests for read only.

But having simply clickable links without active scripts in emails, is a higher goal and justifies this diviation from the norm.

4.2.1. Safe Methods

Request methods are considered "safe" if their defined semantics are essentially read-only; i.e., the client does not request, and does not expect, any state change on the origin server as a result of applying a safe method to a target resource. Likewise, reasonable use of a safe method is not expected to cause any harm, loss of property, or unusual burden on the origin server.

This definition of safe methods does not prevent an implementation from including behavior that is potentially harmful, that is not entirely read-only, or that causes side effects while invoking a safe method. What is important, however, is that the client did not request that additional behavior and cannot be held accountable for it.

2
  • Thanks. This clarified a bit, but I'm still unclear. When it says "What is important, however, is that the client did not request that additional behavior and cannot be held accountable for it." I'm a bit unclear on how the client isn't requesting their account be confirmed, like why is it considered a side effect instead of a request. What is the distinction between a client clicking that link to confirm their account and a client submitting a form to add edit a resource? How world the former be a side effect and the later be a request? Feb 21 at 19:23
  • 1
    The intention of the user is to "open a link", which might just display a form to confirm the email in a second step, as the result of the link is unknown until requested (some even implement it that way). You as a provider of your service just simplified that two step process into one GET request. But you cannot expect from every user that they know that opening the link already executes the confirmation.
    – Simulant
    Feb 22 at 7:38
2

You can consider the method safe if you say that the function executed on the server is simply to record that the email was successfully delivered - not specifically that the the user clicked the link. It's akin to a tracking pixel, except that it will generally only work if the email recipient wants it to work.

The user clicking the link isn't requesting a change on the server - instead the operators of the server have asked them to click a link and they are simply being helpful.

Or you can think of it as the user requesting a change to the server state and say that this is a widely accepted violation of HTTP standards.

1
  • 1
    The link is supposed to confirm that the user who initiated the registration process has control over the given mailbox. The successful delivery of the mail to the given mailbox is not what is desired to be recorded - in fact, if the mailbox is owned by somebody else than the initiating user, they are urged not to follow the link in the (successfully delivered!) mail Feb 21 at 5:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.