Skip to content

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 a CreateAPIView requires much less hacks.

  • Its serializer extends the UserSerializer, making every field read-only except for email.

  • 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 into self.instance on the serializer. This will allow the user's updated data to be returned in the API response.

  • The .validate() method removes the token from data 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 calls super().update, then creates the user scopes, adds a membership to the SIGNUP_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 to user/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 and POST them to VerifyEmail by itself.

Edited by Erwan Rouchet