authentik.stages.authenticator_totp.models

OTP Time-based models

  1"""OTP Time-based models"""
  2
  3import time
  4from base64 import b32encode
  5from binascii import unhexlify
  6from urllib.parse import quote, urlencode
  7
  8from django.conf import settings
  9from django.db import models
 10from django.utils.translation import gettext_lazy as _
 11from django.views import View
 12from rest_framework.serializers import BaseSerializer
 13
 14from authentik.core.types import UserSettingSerializer
 15from authentik.flows.models import ConfigurableStage, FriendlyNamedStage, Stage
 16from authentik.lib.models import SerializerModel
 17from authentik.stages.authenticator.models import Device, ThrottlingMixin
 18from authentik.stages.authenticator.oath import TOTP
 19from authentik.stages.authenticator.util import hex_validator, random_hex
 20
 21
 22class TOTPDigits(models.TextChoices):
 23    """OTP Time Digits"""
 24
 25    SIX = "6", _("6 digits, widely compatible")
 26    EIGHT = "8", _("8 digits, not compatible with apps like Google Authenticator")
 27
 28
 29class AuthenticatorTOTPStage(ConfigurableStage, FriendlyNamedStage, Stage):
 30    """Setup Time-based OTP authentication for the user."""
 31
 32    digits = models.IntegerField(choices=TOTPDigits.choices)
 33
 34    @property
 35    def serializer(self) -> type[BaseSerializer]:
 36        from authentik.stages.authenticator_totp.api import AuthenticatorTOTPStageSerializer
 37
 38        return AuthenticatorTOTPStageSerializer
 39
 40    @property
 41    def view(self) -> type[View]:
 42        from authentik.stages.authenticator_totp.stage import AuthenticatorTOTPStageView
 43
 44        return AuthenticatorTOTPStageView
 45
 46    @property
 47    def component(self) -> str:
 48        return "ak-stage-authenticator-totp-form"
 49
 50    def ui_user_settings(self) -> UserSettingSerializer | None:
 51        return UserSettingSerializer(
 52            data={
 53                "title": self.friendly_name or str(self._meta.verbose_name),
 54                "component": "ak-user-settings-authenticator-totp",
 55            }
 56        )
 57
 58    def __str__(self) -> str:
 59        return f"TOTP Authenticator Setup Stage {self.name}"
 60
 61    class Meta:
 62        verbose_name = _("TOTP Authenticator Setup Stage")
 63        verbose_name_plural = _("TOTP Authenticator Setup Stages")
 64
 65
 66def default_key():
 67    """Default TOTP Device key"""
 68    return random_hex(20)
 69
 70
 71def key_validator(value):
 72    """Validate totp key"""
 73    return hex_validator()(value)
 74
 75
 76class TOTPDevice(SerializerModel, ThrottlingMixin, Device):
 77    """
 78    A generic TOTP :class:`~authentik.stages.authenticator.models.Device`. The model fields mostly
 79    correspond to the arguments to :func:`authentik.stages.authenticator.oath.totp`. They all have
 80    sensible defaults, including the key, which is randomly generated.
 81
 82    .. attribute:: key
 83
 84        *CharField*: A hex-encoded secret key of up to 40 bytes. (Default: 20
 85        random bytes)
 86
 87    .. attribute:: step
 88
 89        *PositiveSmallIntegerField*: The time step in seconds. (Default: 30)
 90
 91    .. attribute:: t0
 92
 93        *BigIntegerField*: The Unix time at which to begin counting steps.
 94        (Default: 0)
 95
 96    .. attribute:: digits
 97
 98        *PositiveSmallIntegerField*: The number of digits to expect in a token
 99        (6 or 8).  (Default: 6)
100
101    .. attribute:: tolerance
102
103        *PositiveSmallIntegerField*: The number of time steps in the past or
104        future to allow. For example, if this is 1, we'll accept any of three
105        tokens: the current one, the previous one, and the next one. (Default:
106        1)
107
108    .. attribute:: drift
109
110        *SmallIntegerField*: The number of time steps the prover is known to
111        deviate from our clock.  If :setting:`OTP_TOTP_SYNC` is ``True``, we'll
112        update this any time we match a token that is not the current one.
113        (Default: 0)
114
115    .. attribute:: last_t
116
117        *BigIntegerField*: The time step of the last verified token. To avoid
118        verifying the same token twice, this will be updated on each successful
119        verification. Only tokens at a higher time step will be verified
120        subsequently. (Default: -1)
121
122    """
123
124    key = models.CharField(
125        max_length=80,
126        validators=[key_validator],
127        default=default_key,
128        help_text="A hex-encoded secret key of up to 40 bytes.",
129    )
130    step = models.PositiveSmallIntegerField(default=30, help_text="The time step in seconds.")
131    t0 = models.BigIntegerField(
132        default=0, help_text="The Unix time at which to begin counting steps."
133    )
134    digits = models.PositiveSmallIntegerField(
135        choices=[(6, 6), (8, 8)],
136        default=6,
137        help_text="The number of digits to expect in a token.",
138    )
139    tolerance = models.PositiveSmallIntegerField(
140        default=1, help_text="The number of time steps in the past or future to allow."
141    )
142    drift = models.SmallIntegerField(
143        default=0,
144        help_text="The number of time steps the prover is known to deviate from our clock.",
145    )
146    last_t = models.BigIntegerField(
147        default=-1,
148        help_text=(
149            "The t value of the latest verified token. "
150            "The next token must be at a higher time step."
151        ),
152    )
153
154    @property
155    def serializer(self) -> type[BaseSerializer]:
156        from authentik.stages.authenticator_totp.api import TOTPDeviceSerializer
157
158        return TOTPDeviceSerializer
159
160    @property
161    def bin_key(self):
162        """
163        The secret key as a binary string.
164        """
165        return unhexlify(self.key.encode())
166
167    def verify_token(self, token):
168        otp_totp_sync = getattr(settings, "OTP_TOTP_SYNC", True)
169
170        verify_allowed, _ = self.verify_is_allowed()
171        if not verify_allowed:
172            return False
173
174        try:
175            token = int(token)
176        except ValueError:
177            verified = False
178        else:
179            key = self.bin_key
180
181            totp = TOTP(key, self.step, self.t0, self.digits, self.drift)
182            totp.time = time.time()
183
184            verified = totp.verify(token, self.tolerance, self.last_t + 1)
185            if verified:
186                self.last_t = totp.t()
187                if otp_totp_sync:
188                    self.drift = totp.drift
189                self.throttle_reset(commit=False)
190                self.save()
191
192        if not verified:
193            self.throttle_increment(commit=True)
194
195        return verified
196
197    def get_throttle_factor(self):
198        return getattr(settings, "OTP_TOTP_THROTTLE_FACTOR", 1)
199
200    @property
201    def config_url(self):
202        """
203        A URL for configuring Google Authenticator or similar.
204
205        See https://github.com/google/google-authenticator/wiki/Key-Uri-Format.
206        The issuer is taken from :setting:`OTP_TOTP_ISSUER`, if available.
207        The image (for e.g. FreeOTP) is taken from :setting:`OTP_TOTP_IMAGE`, if available.
208
209        """
210        label = str(self.user.username)
211        params = {
212            "secret": b32encode(self.bin_key),
213            "algorithm": "SHA1",
214            "digits": self.digits,
215            "period": self.step,
216        }
217        urlencoded_params = urlencode(params)
218
219        issuer = self._read_str_from_settings("OTP_TOTP_ISSUER")
220        if issuer:
221            issuer = issuer.replace(":", "")
222            label = f"{issuer}:{label}"
223            urlencoded_params += (
224                f"&issuer={quote(issuer)}"  # encode issuer as per RFC 3986, not quote_plus
225            )
226
227        image = self._read_str_from_settings("OTP_TOTP_IMAGE")
228        if image:
229            urlencoded_params += "&image={}".format(quote(image, safe=":/"))
230
231        url = f"otpauth://totp/{quote(label)}?{urlencoded_params}"
232
233        return url
234
235    def _read_str_from_settings(self, key):
236        val = getattr(settings, key, None)
237        if callable(val):
238            val = val(self)
239        if isinstance(val, str) and (val != ""):
240            return val
241        return None
242
243    class Meta(Device.Meta):
244        verbose_name = _("TOTP Device")
245        verbose_name_plural = _("TOTP Devices")
class TOTPDigits(django.db.models.enums.TextChoices):
23class TOTPDigits(models.TextChoices):
24    """OTP Time Digits"""
25
26    SIX = "6", _("6 digits, widely compatible")
27    EIGHT = "8", _("8 digits, not compatible with apps like Google Authenticator")

OTP Time Digits

30class AuthenticatorTOTPStage(ConfigurableStage, FriendlyNamedStage, Stage):
31    """Setup Time-based OTP authentication for the user."""
32
33    digits = models.IntegerField(choices=TOTPDigits.choices)
34
35    @property
36    def serializer(self) -> type[BaseSerializer]:
37        from authentik.stages.authenticator_totp.api import AuthenticatorTOTPStageSerializer
38
39        return AuthenticatorTOTPStageSerializer
40
41    @property
42    def view(self) -> type[View]:
43        from authentik.stages.authenticator_totp.stage import AuthenticatorTOTPStageView
44
45        return AuthenticatorTOTPStageView
46
47    @property
48    def component(self) -> str:
49        return "ak-stage-authenticator-totp-form"
50
51    def ui_user_settings(self) -> UserSettingSerializer | None:
52        return UserSettingSerializer(
53            data={
54                "title": self.friendly_name or str(self._meta.verbose_name),
55                "component": "ak-user-settings-authenticator-totp",
56            }
57        )
58
59    def __str__(self) -> str:
60        return f"TOTP Authenticator Setup Stage {self.name}"
61
62    class Meta:
63        verbose_name = _("TOTP Authenticator Setup Stage")
64        verbose_name_plural = _("TOTP Authenticator Setup Stages")

Setup Time-based OTP authentication for the user.

def digits(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

serializer: type[rest_framework.serializers.BaseSerializer]
35    @property
36    def serializer(self) -> type[BaseSerializer]:
37        from authentik.stages.authenticator_totp.api import AuthenticatorTOTPStageSerializer
38
39        return AuthenticatorTOTPStageSerializer

Get serializer for this model

view: type[django.views.generic.base.View]
41    @property
42    def view(self) -> type[View]:
43        from authentik.stages.authenticator_totp.stage import AuthenticatorTOTPStageView
44
45        return AuthenticatorTOTPStageView

Return StageView class that implements logic for this stage

component: str
47    @property
48    def component(self) -> str:
49        return "ak-stage-authenticator-totp-form"

Return component used to edit this object

def ui_user_settings(self) -> authentik.core.types.UserSettingSerializer | None:
51    def ui_user_settings(self) -> UserSettingSerializer | None:
52        return UserSettingSerializer(
53            data={
54                "title": self.friendly_name or str(self._meta.verbose_name),
55                "component": "ak-user-settings-authenticator-totp",
56            }
57        )

Entrypoint to integrate with User settings. Can either return None if no user settings are available, or a challenge.

configure_flow

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example::

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

def friendly_name(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def get_digits_display(unknown):

Method descriptor with partial application of the given arguments and keywords.

Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.

configure_flow_id
stage_ptr_id
stage_ptr

Accessor to the related object on the forward side of a one-to-one relation.

In the example::

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Restaurant.place is a ForwardOneToOneDescriptor instance.

class AuthenticatorTOTPStage.DoesNotExist(authentik.flows.models.Stage.DoesNotExist):

The requested object does not exist

class AuthenticatorTOTPStage.MultipleObjectsReturned(authentik.flows.models.Stage.MultipleObjectsReturned):

The query returned multiple objects when only one was expected.

def default_key():
67def default_key():
68    """Default TOTP Device key"""
69    return random_hex(20)

Default TOTP Device key

def key_validator(value):
72def key_validator(value):
73    """Validate totp key"""
74    return hex_validator()(value)

Validate totp key

 77class TOTPDevice(SerializerModel, ThrottlingMixin, Device):
 78    """
 79    A generic TOTP :class:`~authentik.stages.authenticator.models.Device`. The model fields mostly
 80    correspond to the arguments to :func:`authentik.stages.authenticator.oath.totp`. They all have
 81    sensible defaults, including the key, which is randomly generated.
 82
 83    .. attribute:: key
 84
 85        *CharField*: A hex-encoded secret key of up to 40 bytes. (Default: 20
 86        random bytes)
 87
 88    .. attribute:: step
 89
 90        *PositiveSmallIntegerField*: The time step in seconds. (Default: 30)
 91
 92    .. attribute:: t0
 93
 94        *BigIntegerField*: The Unix time at which to begin counting steps.
 95        (Default: 0)
 96
 97    .. attribute:: digits
 98
 99        *PositiveSmallIntegerField*: The number of digits to expect in a token
100        (6 or 8).  (Default: 6)
101
102    .. attribute:: tolerance
103
104        *PositiveSmallIntegerField*: The number of time steps in the past or
105        future to allow. For example, if this is 1, we'll accept any of three
106        tokens: the current one, the previous one, and the next one. (Default:
107        1)
108
109    .. attribute:: drift
110
111        *SmallIntegerField*: The number of time steps the prover is known to
112        deviate from our clock.  If :setting:`OTP_TOTP_SYNC` is ``True``, we'll
113        update this any time we match a token that is not the current one.
114        (Default: 0)
115
116    .. attribute:: last_t
117
118        *BigIntegerField*: The time step of the last verified token. To avoid
119        verifying the same token twice, this will be updated on each successful
120        verification. Only tokens at a higher time step will be verified
121        subsequently. (Default: -1)
122
123    """
124
125    key = models.CharField(
126        max_length=80,
127        validators=[key_validator],
128        default=default_key,
129        help_text="A hex-encoded secret key of up to 40 bytes.",
130    )
131    step = models.PositiveSmallIntegerField(default=30, help_text="The time step in seconds.")
132    t0 = models.BigIntegerField(
133        default=0, help_text="The Unix time at which to begin counting steps."
134    )
135    digits = models.PositiveSmallIntegerField(
136        choices=[(6, 6), (8, 8)],
137        default=6,
138        help_text="The number of digits to expect in a token.",
139    )
140    tolerance = models.PositiveSmallIntegerField(
141        default=1, help_text="The number of time steps in the past or future to allow."
142    )
143    drift = models.SmallIntegerField(
144        default=0,
145        help_text="The number of time steps the prover is known to deviate from our clock.",
146    )
147    last_t = models.BigIntegerField(
148        default=-1,
149        help_text=(
150            "The t value of the latest verified token. "
151            "The next token must be at a higher time step."
152        ),
153    )
154
155    @property
156    def serializer(self) -> type[BaseSerializer]:
157        from authentik.stages.authenticator_totp.api import TOTPDeviceSerializer
158
159        return TOTPDeviceSerializer
160
161    @property
162    def bin_key(self):
163        """
164        The secret key as a binary string.
165        """
166        return unhexlify(self.key.encode())
167
168    def verify_token(self, token):
169        otp_totp_sync = getattr(settings, "OTP_TOTP_SYNC", True)
170
171        verify_allowed, _ = self.verify_is_allowed()
172        if not verify_allowed:
173            return False
174
175        try:
176            token = int(token)
177        except ValueError:
178            verified = False
179        else:
180            key = self.bin_key
181
182            totp = TOTP(key, self.step, self.t0, self.digits, self.drift)
183            totp.time = time.time()
184
185            verified = totp.verify(token, self.tolerance, self.last_t + 1)
186            if verified:
187                self.last_t = totp.t()
188                if otp_totp_sync:
189                    self.drift = totp.drift
190                self.throttle_reset(commit=False)
191                self.save()
192
193        if not verified:
194            self.throttle_increment(commit=True)
195
196        return verified
197
198    def get_throttle_factor(self):
199        return getattr(settings, "OTP_TOTP_THROTTLE_FACTOR", 1)
200
201    @property
202    def config_url(self):
203        """
204        A URL for configuring Google Authenticator or similar.
205
206        See https://github.com/google/google-authenticator/wiki/Key-Uri-Format.
207        The issuer is taken from :setting:`OTP_TOTP_ISSUER`, if available.
208        The image (for e.g. FreeOTP) is taken from :setting:`OTP_TOTP_IMAGE`, if available.
209
210        """
211        label = str(self.user.username)
212        params = {
213            "secret": b32encode(self.bin_key),
214            "algorithm": "SHA1",
215            "digits": self.digits,
216            "period": self.step,
217        }
218        urlencoded_params = urlencode(params)
219
220        issuer = self._read_str_from_settings("OTP_TOTP_ISSUER")
221        if issuer:
222            issuer = issuer.replace(":", "")
223            label = f"{issuer}:{label}"
224            urlencoded_params += (
225                f"&issuer={quote(issuer)}"  # encode issuer as per RFC 3986, not quote_plus
226            )
227
228        image = self._read_str_from_settings("OTP_TOTP_IMAGE")
229        if image:
230            urlencoded_params += "&image={}".format(quote(image, safe=":/"))
231
232        url = f"otpauth://totp/{quote(label)}?{urlencoded_params}"
233
234        return url
235
236    def _read_str_from_settings(self, key):
237        val = getattr(settings, key, None)
238        if callable(val):
239            val = val(self)
240        if isinstance(val, str) and (val != ""):
241            return val
242        return None
243
244    class Meta(Device.Meta):
245        verbose_name = _("TOTP Device")
246        verbose_name_plural = _("TOTP Devices")

A generic TOTP :class:~authentik.stages.authenticator.models.Device. The model fields mostly correspond to the arguments to :func:authentik.stages.authenticator.oath.totp. They all have sensible defaults, including the key, which is randomly generated.

.. attribute:: key

*CharField*: A hex-encoded secret key of up to 40 bytes. (Default: 20
random bytes)

.. attribute:: step

*PositiveSmallIntegerField*: The time step in seconds. (Default: 30)

.. attribute:: t0

*BigIntegerField*: The Unix time at which to begin counting steps.
(Default: 0)

.. attribute:: digits

*PositiveSmallIntegerField*: The number of digits to expect in a token
(6 or 8).  (Default: 6)

.. attribute:: tolerance

*PositiveSmallIntegerField*: The number of time steps in the past or
future to allow. For example, if this is 1, we'll accept any of three
tokens: the current one, the previous one, and the next one. (Default:
1)

.. attribute:: drift

*SmallIntegerField*: The number of time steps the prover is known to
deviate from our clock.  If :setting:`OTP_TOTP_SYNC` is ``True``, we'll
update this any time we match a token that is not the current one.
(Default: 0)

.. attribute:: last_t

*BigIntegerField*: The time step of the last verified token. To avoid
verifying the same token twice, this will be updated on each successful
verification. Only tokens at a higher time step will be verified
subsequently. (Default: -1)
def key(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def step(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def t0(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def digits(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def tolerance(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def drift(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def last_t(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

serializer: type[rest_framework.serializers.BaseSerializer]
155    @property
156    def serializer(self) -> type[BaseSerializer]:
157        from authentik.stages.authenticator_totp.api import TOTPDeviceSerializer
158
159        return TOTPDeviceSerializer

Get serializer for this model

bin_key
161    @property
162    def bin_key(self):
163        """
164        The secret key as a binary string.
165        """
166        return unhexlify(self.key.encode())

The secret key as a binary string.

def verify_token(self, token):
168    def verify_token(self, token):
169        otp_totp_sync = getattr(settings, "OTP_TOTP_SYNC", True)
170
171        verify_allowed, _ = self.verify_is_allowed()
172        if not verify_allowed:
173            return False
174
175        try:
176            token = int(token)
177        except ValueError:
178            verified = False
179        else:
180            key = self.bin_key
181
182            totp = TOTP(key, self.step, self.t0, self.digits, self.drift)
183            totp.time = time.time()
184
185            verified = totp.verify(token, self.tolerance, self.last_t + 1)
186            if verified:
187                self.last_t = totp.t()
188                if otp_totp_sync:
189                    self.drift = totp.drift
190                self.throttle_reset(commit=False)
191                self.save()
192
193        if not verified:
194            self.throttle_increment(commit=True)
195
196        return verified

Verifies a token. As a rule, the token should no longer be valid if this returns True.

:param str token: The OTP token provided by the user. :rtype: bool

def get_throttle_factor(self):
198    def get_throttle_factor(self):
199        return getattr(settings, "OTP_TOTP_THROTTLE_FACTOR", 1)

This must be implemented to return the throttle factor.

The number of seconds required between verification attempts will be :math:c2^{n-1} where c is this factor and n is the number of previous failures. A factor of 1 translates to delays of 1, 2, 4, 8, etc. seconds. A factor of 0 disables the throttling.

Normally this is just a wrapper for a plugin-specific setting like :setting:OTP_EMAIL_THROTTLE_FACTOR.

config_url
201    @property
202    def config_url(self):
203        """
204        A URL for configuring Google Authenticator or similar.
205
206        See https://github.com/google/google-authenticator/wiki/Key-Uri-Format.
207        The issuer is taken from :setting:`OTP_TOTP_ISSUER`, if available.
208        The image (for e.g. FreeOTP) is taken from :setting:`OTP_TOTP_IMAGE`, if available.
209
210        """
211        label = str(self.user.username)
212        params = {
213            "secret": b32encode(self.bin_key),
214            "algorithm": "SHA1",
215            "digits": self.digits,
216            "period": self.step,
217        }
218        urlencoded_params = urlencode(params)
219
220        issuer = self._read_str_from_settings("OTP_TOTP_ISSUER")
221        if issuer:
222            issuer = issuer.replace(":", "")
223            label = f"{issuer}:{label}"
224            urlencoded_params += (
225                f"&issuer={quote(issuer)}"  # encode issuer as per RFC 3986, not quote_plus
226            )
227
228        image = self._read_str_from_settings("OTP_TOTP_IMAGE")
229        if image:
230            urlencoded_params += "&image={}".format(quote(image, safe=":/"))
231
232        url = f"otpauth://totp/{quote(label)}?{urlencoded_params}"
233
234        return url

A URL for configuring Google Authenticator or similar.

See https://github.com/google/google-authenticator/wiki/Key-Uri-Format. The issuer is taken from :setting:OTP_TOTP_ISSUER, if available. The image (for e.g. FreeOTP) is taken from :setting:OTP_TOTP_IMAGE, if available.

def throttling_failure_timestamp(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def throttling_failure_count(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

user

Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.

In the example::

class Child(Model):
    parent = ForeignKey(Parent, related_name='children')

Child.parent is a ForwardManyToOneDescriptor instance.

def name(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def confirmed(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def last_used(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def created(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def last_updated(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

def get_digits_display(unknown):

Method descriptor with partial application of the given arguments and keywords.

Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.

def get_next_by_created(unknown):

Method descriptor with partial application of the given arguments and keywords.

Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.

def get_previous_by_created(unknown):

Method descriptor with partial application of the given arguments and keywords.

Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.

def get_next_by_last_updated(unknown):

Method descriptor with partial application of the given arguments and keywords.

Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.

def get_previous_by_last_updated(unknown):

Method descriptor with partial application of the given arguments and keywords.

Supports wrapping existing descriptors and handles non-descriptor callables as instance methods.

user_id
def id(unknown):

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

class TOTPDevice.DoesNotExist(django.core.exceptions.ObjectDoesNotExist):

The requested object does not exist

class TOTPDevice.MultipleObjectsReturned(django.core.exceptions.MultipleObjectsReturned):

The query returned multiple objects when only one was expected.