16

I recently built a Django-based authentication system using a tutorial. Within this System I created a token within a forms.py. This Token is then send (as a link) in an activation activation mail.

from django.contrib.auth.tokens import default_token_generator    
token = default_token_generator.make_token(user)

The view which receives the get request matches the token and the user-id supplied in this link and checks the token using:

default_token_generator.check_token(user, token)

This verifies that the token was sent though my site. But I don't understand the process. The token is unique but I don't seem to save the token somewhere? So how does check_token()verify the token?

Xen_mar
  • 8,330
  • 11
  • 51
  • 74

1 Answers1

29

A token consist of a timestamp and a HMAC value. HMAC is a keyed hashing function: hashing uses a secret key (by default settings.SECRET_KEY) to get a unique value, but "unhashing" is impossible with or without the key.

The hash combines four values:

  • The user's primary key.
  • The user's hashed password.
  • The user's last login timestamp.
  • The current timestamp.

The token then consists of the current timestamp and the hash of these four values. The first three values are already in the database, and the fourth value is part of the token, so Django can verify the token at any time.

By including the user's hashed password and last login timestamp in the hash, a token is automatically invalidated when the user logs in or changes their password. The current timestamp is also checked to see if the token has expired. Note that even though the current timestamp is included in the token (as a base36 encoded string), if an attacker changes the value, the hash changes as well and the token is rejected.

knbk
  • 52,111
  • 9
  • 124
  • 122
  • 5
    The upshot of which is, there is no need to store them at all, as validity can be calculated from the token itself. – Daniel Roseman Sep 15 '17 at 09:51
  • 2
    I realize it's been 3 years since the last post on this topic, but perhaps @knbk (or anybody) can explain how exactly the current timestamp is used in this scenario. When the initial hash is created, when a reset password email is sent, for example, it would use the current timestamp from that point in time. Then when the user follows the link, and the token is checked, it would be a different point in time, and, thus, a different "current timestamp". Or am I missing something? – ExTexan Sep 20 '20 at 09:53
  • 4
    It takes the current time and subtracts the timestamp from within the token. It then makes sure that the result is less than the expiration value PASSWORD_RESET_TIMEOUT which is in seconds. The default value is 60*60*24*3. – user2108868 Sep 28 '20 at 17:10