passlib.totp -- TOTP / Two Factor Authentication¶
The passlib.totp module provides totp / two factor authentication.
Warning
Changed in 1.7: Added.
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.
Tip
TOTP Tutorial-- Overview of this module and walkthrough of how to use it.
TOTP Class¶
TOTP
¶
TOTP(
key=None,
format="base32",
new=False,
digits=None,
alg=None,
size=None,
period=None,
label=None,
issuer=None,
changed=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, default:None) –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=Truemust be specified. -
format(str, default:'base32') –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, default:False) –If
True, a new key will be generated using :class:random.SystemRandom.Exactly one
new=Trueor key must be specified. -
label(str, default:None) –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. See :meth:to_urifor details. -
issuer(str, default:None) –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 :meth:to_urifor details. -
size(int, default:None) –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, default:None) –The number of digits in the generated / accepted tokens. Defaults to
6. Must be in range [6 .. 10]... rst-class:: inline-title .. 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, default:None) –Name of hash algorithm to use. Defaults to
"sha1"."sha256"and"sha512"are also accepted, per :rfc:6238. -
period(int, default:None) –The time-step period to use, in integer seconds. Defaults to
30... See the passlib documentation for a full list of attributes & methods.
encrypted_key
property
writable
¶
encrypted_key
secret key, encrypted using application secret.
this match the output of :meth:AppWallet.encrypt_key,
and should be treated as an opaque json serializable object.
using
classmethod
¶
using(
digits=None,
alg=None,
period=None,
issuer=None,
wallet=None,
now=None,
**kwds,
)
Dynamically create subtype of :class:!TOTP class
which has the specified defaults set.
Parameters:
-
wallet–Optional :class:
AppWalletthat will be used for encrypting/decrypting keys. -
encrypt_cost–If specified, these options will be passed to the :class:
AppWalletconstructor, allowing you to directly specify the secret keys that should be used to encrypt & decrypt stored keys.
Returns:
-
–
subclass of :class:
!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}.. seealso:: :ref:
totp-creationand :ref:totp-storing-instancestutorials for a usage example
pretty_key
¶
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'
normalize_time
classmethod
¶
normalize_time(time)
Normalize time value to unix epoch seconds.
Parameters:
-
time–Can be
None, :class:!datetime, or unix epoch timestamp as :class:!floator :class:!int. IfNone, uses current system time. Naive datetimes are treated as UTC.
Returns:
-
–
unix epoch timestamp as :class:
int.
normalize_token
¶
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 as TOTP().normalize_token().
It will normalize to the instance-specific number of :attr:~TOTP.digits,
or use the class default.
Parameters:
-
token–token as ascii bytes, str, or an integer.
Returns:
-
–
token as :class:
!str, containing only digits 0-9.
Raises:
-
ValueError–if token has wrong number of digits, or contains non-numeric characters.
generate
¶
generate(time=None)
Generate token for specified time (uses current time if none specified).
Parameters:
-
time–Can be
None, a :class:!datetime, or class:!float/ :class:!intunix epoch timestamp. IfNone(the default), uses current system time. Naive datetimes are treated as UTC.
Returns:
-
–
A :class:
TotpTokeninstance, 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'
verify
classmethod
¶
verify(token, source, **kwds)
Convenience wrapper around :meth:TOTP.from_source and :meth:TOTP.match.
This parses a TOTP key & configuration from the specified source,
and tries and match the token.
It's designed to parallel the :meth:passlib.ifc.PasswordHash.verify method.
Parameters:
-
token–Token string to match.
-
source–Serialized TOTP key. Can be anything accepted by :meth:
TOTP.from_source. -
\\*\\*kwds–All additional keywords passed to :meth:
TOTP.match.
Returns:
-
–
A :class:
TotpMatchinstance, or raises a :exc:TokenError.
match
¶
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 :class:
!float, :class:!int, or :class:!datetime. ifNone(the default), uses current system time. this should correspond to the time the token was received from the client. -
window(int, default:30) –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 :attr:period. -
skew(int, default:0) –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.
Returns:
-
–
Returns a :class:
TotpMatchinstance 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
Raises:
-
~passlib.exc.TokenError–If the token is malformed, fails to match, or has already been used.
from_source
classmethod
¶
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 :meth:
from_uri - Any other strings are handed off to :meth:
from_json - Dicts are handed off to :meth:
from_dict
Parameters:
-
source–Serialized TOTP object.
Returns:
-
–
a :class:
TOTPinstance.
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 :meth:
TOTP.using()for how to configure application secrets.
from_uri
classmethod
¶
from_uri(uri)
create an OTP instance from a URI (such as returned by :meth:to_uri).
Returns:
-
–
:class:
TOTPinstance.
Raises:
-
ValueError–if the uri cannot be parsed or contains errors.
.. seealso:: :ref:
totp-configuring-clientstutorial for a usage example
to_uri
¶
to_uri(label=None, issuer=None)
Serialize key and configuration into a URI, per
Google Auth's KeyUriFormat <http://code.google.com/p/google-authenticator/wiki/KeyUriFormat>_.
Parameters:
-
label(str, default:None) –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, default:None) –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:.
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'.. versionchanged:: 1.7.2
This method now prepends the issuer URI label. This is recommended by the KeyURI specification, for compatibility with older clients.
Raises:
-
ValueError–- if a label was not provided either as an argument, or in the constructor.
- if the label or issuer contains invalid characters.
from_json
classmethod
¶
from_json(source)
Load / create an OTP object from a serialized json string
(as generated by :meth:to_json).
Parameters:
-
json–Serialized output from :meth:
to_json, as str or ascii bytes.
Returns:
-
–
a :class:
TOTPinstance... seealso:: :ref:
totp-storing-instancestutorial for a usage example
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 :meth:
TOTP.using()for how to configure application secrets.
to_json
¶
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 :meth:to_dict.
Returns:
-
–
json string containing serializes configuration & state.
from_dict
classmethod
¶
from_dict(source)
Load / create a TOTP object from a dictionary
(as generated by :meth:to_dict)
Parameters:
-
source–dict containing serialized TOTP key & configuration.
Returns:
-
–
A :class:
TOTPinstance... seealso:: :ref:
totp-storing-instancestutorial for a usage example
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 :meth:
TOTP.using()for how to configure application secrets.
to_dict
¶
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 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 new(), to deserialization methods such as from_source(). These are all covered by the TOTP reference above: new(), from_source(), from_uri(), from_json(), and from_dict().
Factory Creation¶
One powerful method offered by the TOTP class is 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: covered by the TOTP reference above.
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 to_uri() and to_json(): these are all covered by the TOTP reference above (key, hex_key, base32_key, label, issuer, digits, alg, period, and changed).
Token Generation¶
Token generation is generally useful client-side, and for generating values to test your server implementation. There is one main generation method: generate().
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:
TotpToken
¶
TotpToken(totp, token, counter)
Object returned by :meth:TOTP.generate.
It can be treated as a sequence of (token, expire_time),
or accessed via the following attributes:
.. autoattribute:: token .. autoattribute:: expire_time .. autoattribute:: counter .. autoattribute:: remaining .. autoattribute:: valid
.. warning:: the constructor signature is an internal detail, and is subject to change.
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: both covered by the TOTP reference above.
Tip
totp-verifying 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:
TotpMatch
¶
TotpMatch(totp, counter, time, window=30)
Object returned by :meth:TOTP.match and :meth:TOTP.verify on a successful match.
It can be treated as a sequence of (counter, time),
or accessed via the following attributes:
.. autoattribute:: counter :annotation: = 0
.. autoattribute:: time :annotation: = 0
.. autoattribute:: expected_counter :annotation: = 0
.. autoattribute:: skipped :annotation: = 0
.. autoattribute:: expire_time :annotation: = 0
.. autoattribute:: cache_seconds :annotation: = 60
.. autoattribute:: cache_time :annotation: = 0
This object will always have a True boolean value.
.. warning:: the constructor signature is an internal detail, and is subject to change.
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 2. 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).
The to_uri() and pretty_key() methods are covered by the TOTP reference above.
Tip
- The
from_sourceandfrom_uriconstructors for decoding URIs. - The
totp-configuring-clientstutorial for details about these methods, and how to render URIs to a QR Code.
Serialization Methods¶
The 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: to_json() and to_dict(), both covered by the TOTP reference above. When application secrets are configured via using(), these methods will automatically encrypt the resulting keys.
Tip
- The
from_sourceandfrom_jsonconstructors for decoding the results of these methods. - The
totp-storing-instancestutorial for more details.
Helper Methods¶
While generate(), match(), and verify() automatically handle normalizing tokens & time values, the following methods are exposed in case they are useful in other contexts: normalize_token() and normalize_time(), both covered by the TOTP reference above.
AppWallet¶
The AppWallet class is used internally by the using() method to store the application secrets provided for handling encrypted keys. If needed, they can also be created and passed in directly.
AppWallet
¶
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 :meth:TOTP.using.
.. seealso::
:ref:`totp-storing-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)
.. seealso:: :func:
generate_secretto 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-DDdates. -
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).
:func:
generate_secretis 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¶
.. autoattribute:: has_secrets .. autoattribute:: default_tag
Semi-Private Methods¶
The following methods are used internally by the :class:
TOTPclass 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
¶
get_secret(tag)
resolve a secret tag to the secret (as bytes). throws a KeyError if not found.
encrypt_key
¶
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 <https://cryptography.io>`_ 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
¶
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 :meth:
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 <https://cryptography.io>`_ package.
Support Functions¶
generate_secret
¶
generate_secret(
entropy=256, charset=BASE64_CHARS[:-2]
)
generate a random string suitable for use as an
:class: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 at0), but so do pretty much all other TOTP implementations.
References¶
- HOTP Specification -
RFC 4226
-
Google's OTPAuth URI format - https://github.com/google/google-authenticator/wiki/Key-Uri-Format ↩