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 using random.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 to None. See to_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. See to_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, or alg 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.

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:

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.
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:
  • wallet – Optional AppWallet that will be used for encrypting/decrypting keys.
  • secrets_path, encrypt_cost (secrets,) – If specified, these options will be passed to the AppWallet constructor, allowing you to directly specify the secret keys that should be used to encrypt & decrypt stored keys.
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.label = None

default label for to_uri()

TOTP.issuer = None

default issuer for to_uri()

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, a datetime, or class:!float / int unix epoch timestamp. If None (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, or datetime. if None (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 of period.
  • 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() and TOTP.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 a TokenError.

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() and TOTP.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'

Changed in version 1.7.2: This method now prepends the issuer URI label. This is recommended by the KeyURI specification, for compatibility with older clients.

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), " ", or False (no separator).
Returns:

key as native string.

Usage example:

>>> t = TOTP('s3jdvb7qd2r7jpxx')
>>> t.pretty_key()
'S3JD-VB7Q-D2R7-JPXX'

See also

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

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(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 as TOTP().normalize_token(). It will normalize to the instance-specific number of digits, 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 as float or int. If None, 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 or secrets_path to TOTP.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.

Support Functions

passlib.totp.generate_secret(entropy=256)

generate a random string suitable for use as an AppWallet application secret.

Parameters:entropy – number of bits of entropy (controls size/complexity of password).

Deviations

  • The TOTP Spec [1] includes an param (T0) providing an optional offset from the base time. Passlib omits this parameter (fixing it at 0), 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