Turn VerifyEmail into a normal API
https://redmine.teklia.com/issues/7318
To better handle issues with email verification, particularly expired tokens, already verified users or Outlook's Advanced Threat Protection, we need to have the frontend handle the email verifications through the VerifyEmail
endpoint, instead of having that endpoint redirect the user.
The VerifyEmail
endpoint should therefore be updated to be closer to regular API endpoints:
-
Its URL is now
/api/v1/user/verify-email/
, which makes more sense than/user/token/
and ensures that older verification links will no longer work.If we kept the same URL, users would be confused anyway because their older emails will no longer work, and it will be faster to help them if they report that they just get a HTTP 404 instead of trying to describe the standard DRF HTML view.
-
It should now be a
CreateAPIView
. This view technically does an update, but having it be aCreateAPIView
requires much less hacks. -
Its serializer extends the
UserSerializer
, making every field read-only except foremail
. -
The serializer adds a write-only
token
CharField. -
The existing token check is moved from the view to the serializer's
.validate()
method, and it should raise a HTTP 400 when it fails. -
To prevent attackers from using this endpoint to determine whether or not a user exists with a specified email address, the HTTP 400 must include the same message in the case of a non-existent email and in the case of an invalid token. Do not ever tell which of the two fields is invalid.
-
The
.validate()
method stores the user that was found from the email address intoself.instance
on the serializer. This will allow the user's updated data to be returned in the API response. -
The
.validate()
method removes thetoken
fromdata
and adds"verified_email": True
. This will cause the user to be updated as verified automatically by DRF. -
The serializer overrides the
.update()
method. It callssuper().update
, then creates the user scopes, adds a membership to theSIGNUP_DEFAULT_GROUP
, and creates a default corpus when there is none, just like now. -
The edge case where a user does not have a password set is now completely ignored. The endpoint no longer needs to ever refer to
user.has_usable_password()
. This is handled separately with #1757 (closed) and frontend#1418 (closed).
Finally, now that this endpoint has changed, we also need to change the verification email template. We will no longer be sending a link to this API directly, because this will confuse users a lot!
-
A new URL must be included under
arkindex.project.urls
as a frontend view, pointing touser/verify-email
. It will send users to the new verification page on the frontend. -
The verification email should now use this new URL, and should still be sending the
?email=…&token=…
. The frontend will take those parameters andPOST
them toVerifyEmail
by itself.