Timestamped tokens¶
Open Forms includes a base token generator implementation which generates timestamped salted Hashed Message Authentication Code (S-HMAC) tokens. These tokens invalidate after a configured number of days and/or when the hash input state has changed.
The tokens are especially well suited for one-time use and protect against replay attacks, without having to store state in the database.
As a developer needing such tokens, you can use the base class for the bulk of the work, which is inspired from Django’s password reset token generator.
- class openforms.tokens.BaseTokenGenerator¶
Generate and check tokens for object-level permission checks.
Implementation adapted from
django.contrib.auth.tokens.PasswordResetTokenGenerator
.When using timestamped tokens, keep in mind that:
the token should be single-use - once used/consumed, an attribute on the object should have been mutated that invalidates the token on replays.
the token expires automatically after a number of days, either configured through Django settings or information defined on the (related) object.
Expiry/validity is expressed in number of days - that’s the resolution. A token generated shortly before midnight is still valid for the following day.
the Django
settings.SECRET_KEY
is used to protect against tampering. KEEP IT SECRET.
Implementation guidelines
Subclasses MUST:
specify
key_salt
- the salt to use for all tokens, input tosalted_hmac()
specify
token_timeout_days
, determining how long the token is valid.implement
get_hash_value_parts()
- check_token(obj: django.db.models.base.Model, token: str) bool ¶
Check that the token is (still) valid for the given model instance.
- abstract get_hash_value_parts(obj: django.db.models.base.Model) list[str] ¶
Obtain a list of strings reflecting object state.
Token invalidation relies on this. Instance attribute values that mutate on token consumption should be returned here. For example, for a password reset token, the hashed password value should be included since the hash changes when the password is reset (even with the same value!).
The code protected with the token should have side-effects that change the values returned here, if the token should invalidate after consumption.
- get_token_timeout_days(obj: django.db.models.base.Model) int ¶
Determine how many days the token is valid for.
Defaults to
token_timeout_days
, optionally you can override this method and fetch information from the object being checked.
- key_salt: str = ''¶
Value to use as salt for the hashing process.
- make_token(obj: django.db.models.base.Model) str ¶
Return a token that expires or gets invalidated by state changes.
- token_timeout_days = 1¶
Default number of days the token is valid. Can be overridden via
get_token_timeout_days()
.