The Passlib documentation has moved to https://passlib.readthedocs.io
passlib.totp
– TOTP / Two Factor Authentication¶
New in version 1.7.
Overview¶
The passlib.totp
module provides a number of classes for implementing
two-factor authentication (2FA) using the TOTP [1] specification.
This page provides a reference to all the classes and methods in this module.
Passlib’s TOTP support is centered around the TOTP
class. There are also
some additional helpers, including the AppWallet
class, which
helps to securely encrypt TOTP keys for storage.
See also
- TOTP Tutorial – Overview of this module and walkthrough of how to use it.
TOTP Class¶
-
class
passlib.totp.
TOTP
(key=None, format="base32", *, new=False, **kwds)¶ Helper for generating and verifying TOTP codes.
Given a secret key and set of configuration options, this object offers methods for token generation, token validation, and serialization. It can also be used to track important persistent TOTP state, such as the last counter used.
This class accepts the following options (only key and format may be specified as positional arguments).
Parameters: - key (str) –
The secret key to use. By default, should be encoded as a base32 string (see format for other encodings).
Exactly one of key or
new=True
must be specified. - format (str) – The encoding used by the key parameter. May be one of:
"base32"
(base32-encoded string),"hex"
(hexadecimal string), or"raw"
(raw bytes). Defaults to"base32"
. - new (bool) –
If
True
, a new key will be generated usingrandom.SystemRandom
.Exactly one
new=True
or key must be specified. - label (str) – Label to associate with this token when generating a URI.
Displayed to user by most OTP client applications (e.g. Google Authenticator),
and typically has format such as
"John Smith"
or"jsmith@webservice.example.org"
. Defaults toNone
. Seeto_uri()
for details. - issuer (str) – String identifying the token issuer (e.g. the domain name of your service).
Used internally by some OTP client applications (e.g. Google Authenticator) to distinguish entries
which otherwise have the same label.
Optional but strongly recommended if you’re rendering to a URI.
Defaults to
None
. Seeto_uri()
for details. - size (int) –
Number of bytes when generating new keys. Defaults to size of hash algorithm (e.g. 20 for SHA1).
Warning
Overriding the default values for
digits
,period
, oralg
may cause problems with some OTP client programs (such as Google Authenticator), which may have these defaults hardcoded. - digits (int) –
The number of digits in the generated / accepted tokens. Defaults to
6
. Must be in range [6 .. 10].Caution
Due to a limitation of the HOTP algorithm, the 10th digit can only take on values 0 .. 2, and thus offers very little extra security.
- alg (str) – Name of hash algorithm to use. Defaults to
"sha1"
."sha256"
and"sha512"
are also accepted, per RFC 6238. - period (int) – The time-step period to use, in integer seconds. Defaults to
30
.
- key (str) –
See below for all the TOTP
methods & attributes...
Alternate Constructors¶
There are a few alternate class constructors offered.
These range from simple convenience wrappers such as TOTP.new()
,
to deserialization methods such as TOTP.from_source()
.
-
classmethod
TOTP.
new
()¶ convenience alias for creating new TOTP key, same as
TOTP(new=True)
-
classmethod
TOTP.
from_source
(source)¶ Load / create a TOTP object from a serialized source. This acts as a wrapper for the various deserialization methods:
- TOTP URIs are handed off to
from_uri()
- Any other strings are handed off to
from_json()
- Dicts are handed off to
from_dict()
Parameters: source – Serialized TOTP object. Raises: ValueError – If the key has been encrypted, but the application secret isn’t available; or if the string cannot be recognized, parsed, or decoded.
See
TOTP.using()
for how to configure application secrets.Returns: a TOTP
instance.- TOTP URIs are handed off to
-
classmethod
TOTP.
from_uri
(uri)¶ create an OTP instance from a URI (such as returned by
to_uri()
).Returns: TOTP
instance.Raises: ValueError – if the uri cannot be parsed or contains errors. See also
Configuring Clients tutorial for a usage example
-
classmethod
TOTP.
from_json
(source)¶ Load / create an OTP object from a serialized json string (as generated by
to_json()
).Parameters: json – Serialized output from to_json()
, as unicode or ascii bytes.Raises: ValueError – If the key has been encrypted, but the application secret isn’t available; or if the string cannot be recognized, parsed, or decoded.
See
TOTP.using()
for how to configure application secrets.Returns: a TOTP
instance.See also
Storing TOTP instances tutorial for a usage example
-
classmethod
TOTP.
from_dict
(source)¶ Load / create a TOTP object from a dictionary (as generated by
to_dict()
)Parameters: source – dict containing serialized TOTP key & configuration. Raises: ValueError – If the key has been encrypted, but the application secret isn’t available; or if the dict cannot be recognized, parsed, or decoded.
See
TOTP.using()
for how to configure application secrets.Returns: A TOTP
instance.See also
Storing TOTP instances tutorial for a usage example
Factory Creation¶
One powerful method offered by the TOTP class is TOTP.using()
.
This method allows you to quickly create TOTP subclasses with preconfigured defaults,
for configuration application secrets and setting default TOTP behavior
for your application:
-
classmethod
TOTP.
using
(digits=None, alg=None, period=None, issuer=None, wallet=None, now=None, **kwds)¶ Dynamically create subtype of
TOTP
class which has the specified defaults set.Parameters: digits, alg, period, issuer:
All these options are the same as in the
TOTP
constructor, and the resulting class will use any values you specify here as the default for all TOTP instances it creates.Parameters: Returns: subclass of
TOTP
.This method is useful for creating a TOTP class configured to use your application’s secrets for encrypting & decrypting keys, as well as create new keys using it’s desired configuration defaults.
As an example:
>>> # your application can create a custom class when it initializes >>> from passlib.totp import TOTP, generate_secret >>> TotpFactory = TOTP.using(secrets={"1": generate_secret()}) >>> # subsequent TOTP objects created from this factory >>> # will use the specified secrets to encrypt their keys... >>> totp = TotpFactory.new() >>> totp.to_dict() {'enckey': {'c': 14, 'k': 'H77SYXWORDPGVOQTFRR2HFUB3C45XXI7', 's': 'G5DOQPIHIBUM2OOHHADQ', 't': '1', 'v': 1}, 'type': 'totp', 'v': 1}
See also
Creating TOTP Instances and Storing TOTP instances tutorials for a usage example
Basic Attributes¶
All the TOTP objects offer the following attributes,
which correspond to the constructor options above.
Most of this information will be serialized by TOTP.to_uri()
and TOTP.to_json()
:
-
TOTP.
key
¶ secret key as raw bytes
-
TOTP.
hex_key
¶ secret key encoded as hexadecimal string
-
TOTP.
base32_key
¶ secret key encoded as base32 string
-
TOTP.
digits
= 6¶ number of digits in the generated tokens.
-
TOTP.
alg
= 'sha1'¶ name of hash algorithm in use (e.g.
"sha1"
)
-
TOTP.
period
= 30¶ number of seconds per counter step. (TOTP uses an internal time-derived counter which increments by 1 every
period
seconds).
-
TOTP.
changed
= False¶ Flag set by deserialization methods to indicate the object needs to be re-serialized. This can be for a number of reasons – encoded using deprecated format, or encrypted using a deprecated key or too few rounds.
Token Generation¶
Token generation is generally useful client-side, and for generating values to test your server implementation. There is one main generation method:
-
TOTP.
generate
(time=None)¶ Generate token for specified time (uses current time if none specified).
Parameters: time – Can be None
, adatetime
, or class:!float /int
unix epoch timestamp. IfNone
(the default), uses current system time. Naive datetimes are treated as UTC.Returns: A TotpToken
instance, which can be treated as a sequence of(token, expire_time)
– see that class for more details.Usage example:
>>> # generate a new token, wrapped in a TotpToken instance... >>> otp = TOTP('s3jdvb7qd2r7jpxx') >>> otp.generate(1419622739) <TotpToken token='897212' expire_time=1419622740> >>> # when you just need the token... >>> otp.generate(1419622739).token '897212'
Warning
Tokens should be displayed as strings, as
they may contain leading zeros which will get stripped if they are
first converted to an int
.
TotpToken¶
The TOTP.generate()
method returns instances of the following class,
which offers up detailed information about the generated token:
-
class
passlib.totp.
TotpToken
¶ Object returned by
TOTP.generate()
. It can be treated as a sequence of(token, expire_time)
, or accessed via the following attributes:-
token
= None¶ Token as decimal-encoded ascii string.
-
expire_time
¶ Timestamp marking end of period when token is valid
-
counter
= None¶ HOTP counter value used to generate token (derived from time)
-
remaining
¶ number of (float) seconds before token expires
-
valid
¶ whether token is still valid
-
Token Matching / Verification¶
Matching user-provided tokens is the main operation when implementing server-side TOTP support.
Passlib offers one main method: TOTP.match()
, as well as a convenience wrapper TOTP.verify()
:
-
TOTP.
match
(token, time=None, window=30, skew=0, last_counter=None)¶ Match TOTP token against specified timestamp. Searches within a window before & after the provided time, in order to account for transmission delay and small amounts of skew in the client’s clock.
Parameters: - token – Token to validate. may be integer or string (whitespace and hyphens are ignored).
- time – Unix epoch timestamp, can be any of
float
,int
, ordatetime
. ifNone
(the default), uses current system time. this should correspond to the time the token was received from the client. - window (int) – How far backward and forward in time to search for a match.
Measured in seconds. Defaults to
30
. Typically only useful if set to multiples ofperiod
. - skew (int) –
Adjust timestamp by specified value, to account for excessive client clock skew. Measured in seconds. Defaults to
0
.Negative skew (the common case) indicates transmission delay, and/or that the client clock is running behind the server.
Positive skew indicates the client clock is running ahead of the server (and by enough that it cancels out any negative skew added by the transmission delay).
You should ensure the server clock uses a reliable time source such as NTP, so that only the client clock’s inaccuracy needs to be accounted for.
This is an advanced parameter that should usually be left at
0
; The window parameter is usually enough to account for any observed transmission delay. - last_counter –
Optional value of last counter value that was successfully used. If specified, verify will never search earlier counters, no matter how large the window is.
Useful when client has previously authenticated, and thus should never provide a token older than previously verified value.
Raises: TokenError – If the token is malformed, fails to match, or has already been used.
Returns TotpMatch: Returns a
TotpMatch
instance on successful match. Can be treated as tuple of(counter, time)
. Raises error if token is malformed / can’t be verified.Usage example:
>>> totp = TOTP('s3jdvb7qd2r7jpxx') >>> # valid token for this time period >>> totp.match('897212', 1419622729) <TotpMatch counter=47320757 time=1419622729 cache_seconds=60> >>> # token from counter step 30 sec ago (within allowed window) >>> totp.match('000492', 1419622729) <TotpMatch counter=47320756 time=1419622729 cache_seconds=60> >>> # invalid token -- token from 60 sec ago (outside of window) >>> totp.match('760389', 1419622729) Traceback: ... InvalidTokenError: Token did not match
-
classmethod
TOTP.
verify
(token, source, **kwds)¶ Convenience wrapper around
TOTP.from_source()
andTOTP.match()
.This parses a TOTP key & configuration from the specified source, and tries and match the token. It’s designed to parallel the
passlib.ifc.PasswordHash.verify()
method.Parameters: - token – Token string to match.
- source – Serialized TOTP key.
Can be anything accepted by
TOTP.from_source()
. - **kwds – All additional keywords passed to
TOTP.match()
.
Returns: A
TotpMatch
instance, or raises aTokenError
.
See also
Verifying Tokens tutorial for a usage example
TotpMatch¶
If successful, the TOTP.verify()
method returns instances of the following class,
which offers up detailed information about the matched token:
-
class
passlib.totp.
TotpMatch
¶ Object returned by
TOTP.match()
andTOTP.verify()
on a successful match.It can be treated as a sequence of
(counter, time)
, or accessed via the following attributes:-
counter
= 0¶ TOTP counter value which matched token. (Best practice is to subsequently ignore tokens matching this counter or earlier)
-
time
= 0¶ Timestamp when verification was performed.
-
expected_counter
= 0¶ Counter value expected for timestamp.
-
skipped
= 0¶ How many steps were skipped between expected and actual matched counter value (may be positive, zero, or negative).
-
expire_time
= 0¶ Timestamp marking end of period when token is valid
-
cache_seconds
= 60¶ Number of seconds counter should be cached before it’s guaranteed to have passed outside of verification window.
-
cache_time
= 0¶ Timestamp marking when counter has passed outside of verification window.
This object will always have a
True
boolean value.-
Client Configuration Methods¶
Once a server has generated a new TOTP key & configuration, it needs to be communicated to the user in order for them to store it in a suitable TOTP client.
This can be done by displaying the key & configuration for the user to hand-enter into their client, or by encoding TOTP object into a URI [3]. These configuration URIs can subsequently be displayed as a QR code, for easy transfer to many smartphone-based TOTP clients (such as Authy or Google Authenticator).
-
TOTP.
to_uri
(label=None, issuer=None)¶ Serialize key and configuration into a URI, per Google Auth’s KeyUriFormat.
Parameters: - label (str) –
Label to associate with this token when generating a URI. Displayed to user by most OTP client applications (e.g. Google Authenticator), and typically has format such as
"John Smith"
or"jsmith@webservice.example.org"
.Defaults to label constructor argument. Must be provided in one or the other location. May not contain
:
. - issuer (str) –
String identifying the token issuer (e.g. the domain or canonical name of your service). Optional but strongly recommended if you’re rendering to a URI. Used internally by some OTP client applications (e.g. Google Authenticator) to distinguish entries which otherwise have the same label.
Defaults to issuer constructor argument, or
None
. May not contain:
.
Raises: ValueError –
- if a label was not provided either as an argument, or in the constructor.
- if the label or issuer contains invalid characters.
Returns: all the configuration information for this OTP token generator, encoded into a URI.
These URIs are frequently converted to a QRCode for transferring to a TOTP client application such as Google Auth. Usage example:
>>> from passlib.totp import TOTP >>> tp = TOTP('s3jdvb7qd2r7jpxx') >>> uri = tp.to_uri("user@example.org", "myservice.another-example.org") >>> uri 'otpauth://totp/user@example.org?secret=S3JDVB7QD2R7JPXX&issuer=myservice.another-example.org'
- label (str) –
-
TOTP.
pretty_key
(format='base32', sep='-')¶ pretty-print the secret key.
This is mainly useful for situations where the user cannot get the qrcode to work, and must enter the key manually into their TOTP client. It tries to format the key in a manner that is easier for humans to read.
Parameters: - format – format to output secret key.
"hex"
and"base32"
are both accepted. - sep – separator to insert to break up key visually.
can be any of
"-"
(the default)," "
, orFalse
(no separator).
Returns: key as native string.
Usage example:
>>> t = TOTP('s3jdvb7qd2r7jpxx') >>> t.pretty_key() 'S3JD-VB7Q-D2R7-JPXX'
- format – format to output secret key.
See also
- The
TOTP.from_source()
andTOTP.from_uri()
constructors for decoding URIs. - The Configuring Clients tutorial for details about these methods, and how to render URIs to a QR Code.
Serialization Methods¶
The TOTP.to_uri()
method is useful, but limited, because it requires
additional information (label & issuer), and lacks the ability to encrypt the key.
The TOTP
provides the following methods for serializing TOTP objects
to internal storage. When application secrets are configured via TOTP.using()
,
these methods will automatically encrypt the resulting keys.
-
TOTP.
to_json
(encrypt=None)¶ Serialize configuration & internal state to a json string, mainly useful for persisting client-specific state in a database. All keywords passed to
to_dict()
.Returns: json string containing serializes configuration & state.
-
TOTP.
to_dict
(encrypt=None)¶ Serialize configuration & internal state to a dict, mainly useful for persisting client-specific state in a database.
Parameters: encrypt – Whether to output should be encrypted.
None
(the default) – uses encrypted key if application secrets are available, otherwise uses plaintext key.True
– uses encrypted key, or raises TypeError if application secret wasn’t provided to OTP constructor.False
– uses raw key.
Returns: dictionary, containing basic (json serializable) datatypes.
See also
- The
TOTP.from_source()
andTOTP.from_json()
constructors for decoding the results of these methods. - The Storing TOTP instances tutorial for more details.
Helper Methods¶
While TOTP.generate()
, TOTP.match()
, and TOTP.verify()
automatically handle normalizing tokens & time values, the following methods
are exposed in case they are useful in other contexts:
-
TOTP.
normalize_token
(self_or_cls, token)¶ Normalize OTP token representation: strips whitespace, converts integers to a zero-padded string, validates token content & number of digits.
This is a hybrid method – it can be called at the class level, as
TOTP.normalize_token()
, or the instance level asTOTP().normalize_token()
. It will normalize to the instance-specific number ofdigits
, or use the class default.Parameters: token – token as ascii bytes, unicode, or an integer. Raises: ValueError – if token has wrong number of digits, or contains non-numeric characters. Returns: token as unicode
string, containing only digits 0-9.
-
classmethod
TOTP.
normalize_time
(time)¶ Normalize time value to unix epoch seconds.
Parameters: time – Can be None
,datetime
, or unix epoch timestamp asfloat
orint
. IfNone
, uses current system time. Naive datetimes are treated as UTC.Returns: unix epoch timestamp as int
.
AppWallet¶
The AppWallet
class is used internally by the TOTP.using()
method
to store the application secrets provided for handling encrypted keys.
If needed, they can also be created and passed in directly.
-
class
passlib.totp.
AppWallet
(secrets=None, default_tag=None, encrypt_cost=None, secrets_path=None)¶ This class stores application-wide secrets that can be used to encrypt & decrypt TOTP keys for storage. It’s mostly an internal detail, applications usually just need to pass
secrets
orsecrets_path
toTOTP.using()
.See also
Storing TOTP instances for more details on this workflow.
Arguments¶
Parameters: - secrets –
Dict of application secrets to use when encrypting/decrypting stored TOTP keys. This should include a secret to use when encrypting new keys, but may contain additional older secrets to decrypt existing stored keys.
The dict should map tags -> secrets, so that each secret is identified by a unique tag. This tag will be stored along with the encrypted key in order to determine which secret should be used for decryption. Tag should be string that starts with regex range
[a-z0-9]
, and the remaining characters must be in[a-z0-9_.-]
.It is recommended to use something like a incremental counter (“1”, “2”, ...), an ISO date (“2016-01-01”, “2016-05-16”, ...), or a timestamp (“19803495”, “19813495”, ...) when assigning tags.
This mapping be provided in three formats:
- A python dict mapping tag -> secret
- A JSON-formatted string containing the dict
- A multiline string with the format
"tag: value\ntag: value\n..."
(This last format is mainly useful when loading from a text file via secrets_path)
See also
generate_secret()
to create a secret with sufficient entropy - secrets_path – Alternately, callers can specify a separate file where the application-wide secrets are stored, using either of the string formats described in secrets.
- default_tag –
Specifies which tag in secrets should be used as the default for encrypting new keys. If omitted, the tags will be sorted, and the largest tag used as the default.
if all tags are numeric, they will be sorted numerically; otherwise they will be sorted alphabetically. this permits tags to be assigned numerically, or e.g. using
YYYY-MM-DD
dates. - encrypt_cost – Optional time-cost factor for key encryption. This value corresponds to log2() of the number of PBKDF2 rounds used.
Warning
The application secret(s) should be stored in a secure location by your application, and each secret should contain a large amount of entropy (to prevent brute-force attacks if the encrypted keys are leaked).
generate_secret()
is provided as a convenience helper to generate a new application secret of suitable size.Best practice is to load these values from a file via secrets_path, and then have your application give up permission to read this file once it’s running.
Public Methods¶
-
has_secrets
¶ whether at least one application secret is present
-
default_tag
= None¶ tag for default secret
Semi-Private Methods¶
The following methods are used internally by the
TOTP
class in order to encrypt & decrypt keys using the provided application secrets. They will generally not be publically useful, and may have their API changed periodically.-
get_secret
(tag)¶ resolve a secret tag to the secret (as bytes). throws a KeyError if not found.
-
encrypt_key
(key)¶ Helper used to encrypt TOTP keys for storage.
Parameters: key – TOTP key to encrypt, as raw bytes. Returns: dict containing encrypted TOTP key & configuration parameters. this format should be treated as opaque, and potentially subject to change, though it is designed to be easily serialized/deserialized (e.g. via JSON). Note
This function requires installation of the external cryptography package.
To give some algorithm details: This function uses AES-256-CTR to encrypt the provided data. It takes the application secret and randomly generated salt, and uses PBKDF2-HMAC-SHA256 to combine them and generate the AES key & IV.
-
decrypt_key
(enckey)¶ Helper used to decrypt TOTP keys from storage format. Consults configured secrets to decrypt key.
Parameters: source – source object, as returned by encrypt_key()
.Returns: (key, needs_recrypt)
–key will be the decrypted key, as bytes.
needs_recrypt will be a boolean flag indicating whether encryption cost or default tag is too old, and henace that key needs re-encrypting before storing.
Note
This function requires installation of the external cryptography package.
- secrets –
Support Functions¶
Deviations¶
- The TOTP Spec [1] includes an param (
T0
) providing an optional offset from the base time. Passlib omits this parameter (fixing it at0
), but so do pretty much all other TOTP implementations.
Footnotes
[1] | (1, 2) TOTP Specification - RFC 6238 |
[2] | HOTP Specification - RFC 4226 |
[3] | Google’s OTPAuth URI format - https://github.com/google/google-authenticator/wiki/Key-Uri-Format |