devise icon indicating copy to clipboard operation
devise copied to clipboard

HEAD requests on confirmation URL should not confirm the user

Open renchap opened this issue 5 years ago • 4 comments
trafficstars

Environment

  • Ruby 2.7
  • Rails 6.0.3.4
  • Devise 4.7.3

Current behavior

When an HTTP HEAD request is done on a confirmation link, the user is confirmed, like as if it was a GET request.

Our mail provider runs HEAD queries on links contained in sent emails to ensure customers are not sending links to malware. This causes every new user to be automatically confirmed by Devise :(

Expected behavior

HEAD HTTP requests on a confirmation link should not confirm the email, but maybe display a button to click to confirm the email (a simple link which does the GET request when clicked should work).

Analysis

In Rails, HEAD requests are treated like a GET for routing (but you can use request.head? to know what it was).

As per the HTTP spec, GET requests should be stateless and should not result in any change. I understand that for a better user experience, it is best to do the real confirmation when a user clicks the link rather than displaying a confirmation button that the user might not click, so the tradeoff is acceptable.

But this behaviour should not be caused by HEAD requests on this URL, as those are not direct user queries but can come from "automated" actions, like:

  • browser pre-fetching: some browsers do HEAD requests on URLs as they are typed or hovered to preload resources
  • cache re-validation (not really the case here)
  • antispam-detection (see above)

renchap avatar Nov 14 '20 16:11 renchap

Same issue here. In my application I solved this by creating a custom ConfirmationsController:

class Users::ConfirmationsController < Devise::ConfirmationsController
  # GET /resource/confirmation?confirmation_token=abcdef
  def show
    if request.head?
      # HEAD request on confirmation URL must not confirm the user
      head :ok
    else
      super
    end
  end
end

In routes.rb:

devise_for :users,
           controllers: {
             confirmations: 'users/confirmations'
           }

But, of course, this should be done by Devise itself.

ledermann avatar Feb 04 '21 12:02 ledermann

We just experienced this behaviour with Microsoft Safelink where the user clicks a button from his e-mail to unlock his account. This leads to 3 times the same request where the first one is a HEAD request which already unlocks the account. Therefor the response of the second and (sometimes) third request redirects the user to the wrong window.

It would be nice if this would be fixed within Device.

javinto avatar Oct 19 '23 13:10 javinto

I still encountered this behavior right now - a HEAD request kills the confirm (and reset password) functionality for the user thoroughly.

Wondering if the Devise team is planning some kind of configuration for this.

xanadiu avatar Apr 18 '24 19:04 xanadiu

@javinto @xanadiu It may be more a Rails issue/config than a Devise issue – The Rails API documentation specifies that "HEAD requests: Rails will transparently convert HEAD requests into GET ones, and return just the headers on the way out. This makes HEAD work reliably in all Rails APIs." That being said, it would be nice if Devise had an obvious way of handling this, or at a minimum, include a note in the documentation.

eric-norcross avatar May 13 '24 19:05 eric-norcross