devise
devise copied to clipboard
HEAD requests on confirmation URL should not confirm the user
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
HEADrequests on URLs as they are typed or hovered to preload resources - cache re-validation (not really the case here)
- antispam-detection (see above)
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.
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.
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.
@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.