django-sesame builds authentication tokens as follows:
Encode the primary key of the user for which they were generated;
SESAME_MAX_AGEis enabled, encode the token generation timestamp;
Assemble a revocation key which is used for invalidating tokens;
Add a message authentication code (MAC) to prevent tampering with the token.
Primary keys are stored in clear text. If this is a concern, you can customize primary keys.
The revocation key is derived from:
The password of the user, unless
The last login date of the user, if
django-sesame provides two token formats:
v1 is the original format; it is still fully supported;
v2 is a better, cleaner, faster design that produces shorter tokens.
SESAME_TOKENS defaults to
This means “generate tokens v2, accept tokens v2 and v1”.
New in version 2.0.
Tokens v2 contain a primary key, an optional timestamp, and a signature.
The signature covers the primary key, the optional timestamp, and the revocation key. If the revocation key changes, the signature becomes invalid. As a consequence, there’s no need to include the revocation key in tokens.
The signature algorithm is Blake2 in keyed mode. A unique key is derived by
SECRET_KEY setting and relevant django-sesame settings.
By default the signature length is 10 bytes. You can adjust it to any value
between 1 and 64 bytes with the
Once a token is created, you can invalidate it in several ways.
Invalid tokens are simply rejected. You may enable logs to understand the reason.
By default, tokens are valid forever. You can configure expiration to give them a finite lifetime.
When expiration is enabled, tokens store the time when they were created. When authenticating them, django-sesame verifies how old they are.
You can check if an invalid token is expired by
re-authenticating it with a very large
If that makes it valid, then it was expired.
By default, tokens can be reused. You can enable single-use tokens to invalidate them when they’re used.
Single-use tokens are tied to the user’s last login date. When authenticating a single-use token successfully, django-sesame updates the user’s last login date, which invalidates the token.
As a consequence of this design:
As soon as a user logs in, via django-sesame or via another login mechanism, all their single-use tokens become invalid.
Authenticating a single-use token updates the user’s last login date, even if the user isn’t logged in permanently.
Finally, single-use tokens can easily get invalidated by accident.
For all these reasons, tokens with a short lifetime are recommended over single-use tokens.
By default, tokens are tied to the users’ passwords. Changing the password invalidates the token.
Indeed, when there’s a suspicion that an account may be compromised, changing the password is the first step. Invalidating tokens makes sense in that case.
Invalidation on password change is less needed when tokens expire quickly.
For example, if you rely on short-lived tokens to validate the email address in a sign up process and you don’t know whether validation will occur before or after initializing the password, you need to disable invalidation. That’s fine from a security perspective.
Since Django hashes the password with a random salt, the token is invalidated even if the new password is identical to the old one.
When users log in with django-sesame only, they don’t need a password. In that
case, you should set their passwords to a invalid value with
set_unusable_password(). You can
invalidate a token at any time by calling
set_unusable_password() again and saving
the user instance.
Disabling invalidation on password change makes it impossible to invalidate a single token.
If a token is compromised, your only options are to deactivate the user or to invalidate all tokens for all users.
You must generate tokens and authenticate them with the same settings.
If you need to invalidate all tokens, set the
SESAME_KEY setting to a
new value. This invalidates the signatures of all tokens v2.
If you still have non-expired tokens v1, do the same with
Custom primary keys#
New in version 3.1.
When generating a token for a user, django-sesame stores the user’s primary key in the token.
If you’d like to store an alternative key in the token instead of the primary
key of the user model, set the
SESAME_PRIMARY_KEY_FIELD setting to the
name of the field storing the alternative key. This field must be declared with
This may be useful if your user model defines a UUID key in addition to Django’s standard integer primary key and you always want to rely on the UUID externally.
To keep tokens short, django-sesame creates a compact binary representations depending on the type of the primary key.
If you’re using integer or UUID primary keys, you’re fine.
If you’re using another type of primary key, for example a string created by a unique ID generation algorithm, the default representation may be suboptimal.
For example, let’s say primary keys are strings containing 24 hexadecimal characters. The default packer represents them with 25 bytes. You can reduce them to 12 bytes with this custom packer:
from sesame.packers import BasePacker class Packer(BasePacker): @staticmethod def pack_pk(user_pk): assert len(user_pk) == 24 return bytes.fromhex(user_pk) @staticmethod def unpack_pk(data): return data[:12].hex(), data[12:]
SESAME_PACKER setting to the dotted Python path to the custom
For details, see
BasePacker and look at built-in
packers defined in the
AuthenticationMiddleware removes the token from the
URL with an HTTP 302 Redirect after authenticating a user successfully.
Unfortunately, this triggers a false positive of Safari’s Protection Against First Party Bounce Trackers. As a consequence, Safari clears cookies and the user is logged out.
To avoid this problem, django-sesame doesn’t redirect when it detects that the browser is Safari. This relies on the ua-parser package, which is an optional dependency. If ua-parser isn’t installed, django-sesame always redirects.
Theoretically, django-sesame can provide stateless authenticated navigation
django.contrib.sessions, provided all internal links include the
There is no clear use case for this. Better persist authentication in cookies than in URLs.