Django uses a very interesting approach to generate the Password reset tokens. I’m not really a security expert, neither I’m very familiar with cryptography algorithms, but it is very safe and reliable.
Before I elaborate a little bit more on the one-time-link generation, I wanted to discuss about the Django’s
PasswordResetTokenGenerator
implementation. Because what we will be doing is actually extending this particular
class to fit our needs.
Generally speaking, Django generate a token without persisting it in the database. Yet, it still have the capabilities of determining whether a given token is valid or not. Also the token is only valid for a defined number of days.
The default value for the Password Reset Token is 7 days, and it can be changed in the settings.py by changing the
value of PASSWORD_RESET_TIMEOUT_DAYS
.
The class have two public methods:
- make_token(user)
- check_token(user, token)
The make_token method will generate a hash value with user related data that will change after the password reset. Meaning, after the user clicks on the link with the hash and proceed to the password reset, the link (or the hash) will no longer be valid:
And then this hash value is used to create a hash that will be mailed to the user:
So, two things: it is using the user.password
salt and user.last_login
timestamp. Both will change and the link
will no longer be valid. Also the SECRET_KEY
is used in the salted_hmac
function. So unless your SECRET_KEY
was
compromised, it would be impossible to reproduce the hash value.
Creating your own token
So, basically you will need an information that will change after using the link. The simplest approach would be:
tokens.py
I’m pretending we have an User model with a Profile model through a One-to-One relationship. And then in this profile
model we have an boolean flag named email_confirmed
.
In order to use it, we could use the same approach as the password reset:
urls.py
views.py
Of course there are cases and cases. Sometimes will be just way easier to generate a random token and save it in the database and simply check it and invalidate after it is “used”. But, if that’s not the case, you can inspire yourself on how Django implements the Password Reset Token.