Search code examples
djangodjango-authentication

Django password reset flow without UIDB64


A team at our company is working on a new app. This app will consist of a javascript frontend and a Django backend (using graphql to communicate between the two). I am working on the Django backend and I'm the sole backend developer of the project.

We are currently working on the 'reset_password' functionality, which will follow the familiar pattern of clicking a button, receiving an email with a password reset link that will lead to the an 'reset_password' form. Though the frontend will render all of the forms, it's the backend thats handling the logic.

The code that I've written is borrowing heavily from the default django.contrib.auth views / forms. The link in the email consists both of an token (created with a PasswordResetTokenGenerator().make_token(user) call) and a uid (created with a urlsafe_base64_encode(force_bytes(user.pk)) call).

However, my frontend colleagues asked me if it would be possible to forgo using the uid (of any other fields that can be used to identify the user) and instead 'work backwards' from the token to the user. Now I know that the token is generated with the user (as its provided as an argument in the create token call: PasswordResetTokenGenerator().make_token(user)) But so far it seems that its impossible to use a token to retrieve the user that was used to create it. (It has also occured to me that being able to do so would be a security risk)

So my question is as follows: Am I correct in believing that its impossible (or at the very least undesirable) to use a token to get the user?


Solution

  • Under the hood PasswordResetTokenGenerator is using the hmac lib to generate an SHA-1 hash (cf django.contrib.tokens, django.utils.crypto), so while technically it's not to be considered secure against an adversary with sufficient resources, I don't believe it's remotely practical to try to "work backwards" there in an everyday case where a simpler solution exists. You're correct.