Description
NOTE: Much of this has been referenced before in several different Issues and PRs, which I will attempt to link to. If I've left any out, I apologize in advance.
Although it appears that this was first noted in either #410 or #519, and eventually merged in #1001, the current behavior is still not great.
After confirming a user's email address, I can continue to click the confirmation link (i.e. make GET requests to the /auth/confirmations
endpoint, triggering the devise_token_auth/confirmations#show
action). It seems that the current behavior will generate a new auth token for the user, and redirect to the successful confirmation URL (either from the params if present, or the DeviseTokenAuth.default_confirm_success_url
).
As pointed out in #1064, #1067, and #1075, when the new token is created, it conditionally adds a expiration if the user has signed in (the :sign_in_count
attribute), which creates a dependency on :trackable
. And while #1064 + #1061 effectively uncouple the dependency, the result is that if :trackable
is not included, then no expiration is set on the token! What-the-huh!!?
The confirmation process should happen in a consistent manner, regardless of the presence of the :trackable
module. A review of the Devise internals shows that checking if a user has signed in (i.e. @resource.has_attribute?(:sign_in_count) && @resource.sign_in_count > 0
) is not an indicator of the user having been confirmed! Rather, it is the presence of a timestamp in the :confirmed_at
attribute that indicates if a user has confirmed their account. (See: Devise::Models::Confirmable#confirm
and Devise::Models::Confirmable#confirmed?
)
Furthermore, the Devise::ConfirmationsController#show
action simply and concisely checks for the presence of validation errors on the user resource, as it handles checking for already confirmed users at the model level. (The Devise::Models::Confirmable#confirm
method sets errors on the user's :email
attribute, if that user has already been confirmed).
We're already using the same Devise::Models::Confirmable::ClassMethods#confirm_by_token
method in:
Therefore, it shouldn't really be necessary to check for specific attributes (or their values) on the user instance (e.g. :sign_in_count
, :confirmed_at
, etc...); just check for errors on the returned user instance like the Devise::ConfirmationsController#show
action does. The question is, what does a failure response from the controller action look like? It currently is just a 404 Not Found
, but presumably it would call DeviseTokenAuth::ApplicationController#render_error
, passing in the relevant validation errors where appropriate.
Lastly, it seems like the tests in the confirmations_controller_test.rb
not actually test most model level attributes; instead the tests should assert that various requests (each in known states) lead to the correct set of controller responses given those states.
Specifically, the tests for :trackable
attributes should not exist at all here:
And additional tests are needed to check the various possible validation errors on the user that could happen when calling Devise::Models::Confirmable::ClassMethods#confirm_by_token
.
I do intend on making a PR for all this, but I'm hoping to collect some feedback in the meantime.