0
# Django OTP
1
2
A pluggable framework for adding two-factor authentication to Django applications using one-time passwords. Django-otp provides a comprehensive solution for implementing multi-factor authentication with support for HOTP (RFC 4226), TOTP (RFC 6238), email-based tokens, and static backup codes.
3
4
## Package Information
5
6
- **Package Name**: django-otp
7
- **Language**: Python
8
- **Installation**: `pip install django-otp`
9
- **Django Version**: 4.2+
10
- **Python Version**: 3.7+
11
12
## Core Imports
13
14
```python
15
import django_otp
16
from django_otp import login, verify_token, match_token, devices_for_user, user_has_device, device_classes, DEVICE_ID_SESSION_KEY
17
from django_otp.util import random_hex, random_number_token, hex_validator
18
from django_otp.qr import write_qrcode_image
19
```
20
21
For specific plugins:
22
23
```python
24
from django_otp.plugins.otp_totp.models import TOTPDevice
25
from django_otp.plugins.otp_static.models import StaticDevice, StaticToken
26
from django_otp.plugins.otp_email.models import EmailDevice
27
from django_otp.plugins.otp_hotp.models import HOTPDevice
28
```
29
30
For forms and views:
31
32
```python
33
from django_otp.forms import OTPAuthenticationForm, OTPTokenForm
34
from django_otp.views import LoginView
35
from django_otp.decorators import otp_required
36
from django_otp.middleware import OTPMiddleware, is_verified
37
```
38
39
## Basic Usage
40
41
### Basic Setup and Device Management
42
43
```python
44
from django_otp import devices_for_user, user_has_device
45
from django_otp.plugins.otp_totp.models import TOTPDevice
46
from django.contrib.auth.models import User
47
48
# Check if user has any OTP devices
49
user = User.objects.get(username='alice')
50
has_device = user_has_device(user)
51
52
# Get all devices for a user
53
devices = list(devices_for_user(user))
54
55
# Create a TOTP device for a user
56
device = TOTPDevice.objects.create(
57
user=user,
58
name='My Authenticator',
59
confirmed=True
60
)
61
62
# Generate a QR code URL for device setup
63
config_url = device.config_url
64
```
65
66
### Token Verification
67
68
```python
69
from django_otp import verify_token
70
71
# Verify a token against a specific device
72
device = verify_token(user, device.persistent_id, '123456')
73
if device:
74
print(f"Token verified with device: {device.name}")
75
else:
76
print("Token verification failed")
77
```
78
79
### Using OTP in Views
80
81
```python
82
from django_otp.decorators import otp_required
83
from django.shortcuts import render
84
85
@otp_required
86
def secure_view(request):
87
# This view requires OTP verification
88
return render(request, 'secure_page.html')
89
90
# Check if user is OTP verified
91
from django_otp.middleware import is_verified
92
93
def my_view(request):
94
if is_verified(request.user):
95
# User is verified with OTP
96
pass
97
```
98
99
## Architecture
100
101
Django-otp is built around a plugin architecture with several key components:
102
103
- **Core Framework**: Provides the base `Device` model and common functionality
104
- **Device Plugins**: Implement specific OTP methods (TOTP, HOTP, Email, Static)
105
- **Django Integration**: Forms, views, middleware, and admin interfaces
106
- **Security Features**: Throttling, cooldowns, and drift compensation
107
108
The `Device` abstract model serves as the foundation, with concrete implementations provided by plugins. Each device can generate challenges and verify tokens, with built-in security features like rate limiting and cooldown periods.
109
110
## Capabilities
111
112
### Core Authentication API
113
114
Core functions for managing OTP authentication, including user login, token verification, and device management. These functions form the foundation of django-otp's authentication system.
115
116
```python { .api }
117
def login(request, device):
118
"""
119
Persist the given OTP device in the current session.
120
121
Args:
122
request: The HTTP request
123
device: The OTP device used to verify the user
124
"""
125
126
def verify_token(user, device_id, token):
127
"""
128
Attempts to verify a token against a specific device.
129
130
Args:
131
user: The user supplying the token
132
device_id: A device's persistent_id value
133
token: An OTP token to verify
134
135
Returns:
136
The device that accepted token, if any, or None
137
"""
138
139
def match_token(user, token):
140
"""
141
Attempts to verify a token on every device attached to the user.
142
143
Warning: Use of this function is no longer recommended.
144
145
Args:
146
user: The user supplying the token
147
token: An OTP token to verify
148
149
Returns:
150
The device that accepted token, if any, or None
151
"""
152
153
def devices_for_user(user, confirmed=True, for_verify=False):
154
"""
155
Return an iterable of all devices registered to the given user.
156
157
Args:
158
user: Standard or custom user object
159
confirmed: If None, all devices returned; otherwise filter by confirmed status
160
for_verify: If True, load devices with select_for_update
161
162
Returns:
163
Iterable of Device objects
164
"""
165
166
def user_has_device(user, confirmed=True):
167
"""
168
Return True if the user has at least one device.
169
170
Args:
171
user: Standard or custom user object
172
confirmed: If None, all devices considered; otherwise filter by confirmed status
173
174
Returns:
175
Boolean indicating if user has devices
176
"""
177
178
def device_classes():
179
"""
180
Returns an iterable of all loaded device models.
181
182
Returns:
183
Iterable of Device model classes
184
"""
185
```
186
187
[Core Authentication](./core-authentication.md)
188
189
### Device Models and Management
190
191
Abstract base models and mixins that provide the foundation for all OTP devices, including security features like throttling and cooldowns.
192
193
```python { .api }
194
class Device(models.Model): ...
195
class SideChannelDevice(Device): ...
196
class CooldownMixin: ...
197
class ThrottlingMixin: ...
198
```
199
200
[Device Models](./device-models.md)
201
202
### TOTP (Time-based OTP)
203
204
Time-based one-time passwords following RFC 6238, typically used with authenticator apps like Google Authenticator or Authy.
205
206
```python { .api }
207
class TOTPDevice(TimestampMixin, ThrottlingMixin, Device):
208
key = models.CharField(max_length=80)
209
step = models.PositiveSmallIntegerField(default=30)
210
t0 = models.BigIntegerField(default=0)
211
digits = models.PositiveSmallIntegerField(choices=[(6, 6), (8, 8)], default=6)
212
tolerance = models.PositiveSmallIntegerField(default=1)
213
drift = models.SmallIntegerField(default=0)
214
last_t = models.BigIntegerField(default=-1)
215
```
216
217
[TOTP Devices](./totp-devices.md)
218
219
### HOTP (Counter-based OTP)
220
221
HMAC-based one-time passwords following RFC 4226, using a counter that increments with each use.
222
223
```python { .api }
224
class HOTPDevice(TimestampMixin, ThrottlingMixin, Device):
225
key = models.CharField(max_length=80)
226
digits = models.PositiveSmallIntegerField(choices=[(6, 6), (8, 8)], default=6)
227
tolerance = models.PositiveSmallIntegerField(default=5)
228
counter = models.BigIntegerField(default=0)
229
```
230
231
[HOTP Devices](./hotp-devices.md)
232
233
### Email-based OTP
234
235
One-time passwords delivered via email, useful for users who don't have smartphone access to authenticator apps.
236
237
```python { .api }
238
class EmailDevice(TimestampMixin, CooldownMixin, ThrottlingMixin, SideChannelDevice):
239
email = models.EmailField(blank=True)
240
```
241
242
[Email Devices](./email-devices.md)
243
244
### Static Backup Tokens
245
246
Pre-generated backup codes for emergency access when primary OTP devices are unavailable.
247
248
```python { .api }
249
class StaticDevice(TimestampMixin, ThrottlingMixin, Device): ...
250
class StaticToken(models.Model):
251
device = models.ForeignKey(StaticDevice, on_delete=models.CASCADE)
252
token = models.CharField(max_length=16)
253
```
254
255
[Static Tokens](./static-tokens.md)
256
257
### Django Integration
258
259
Forms, views, middleware, and decorators for integrating OTP authentication into Django applications.
260
261
```python { .api }
262
class OTPAuthenticationForm(OTPAuthenticationFormMixin, AuthenticationForm): ...
263
class OTPTokenForm(OTPAuthenticationFormMixin, forms.Form): ...
264
class LoginView(auth_views.LoginView): ...
265
def otp_required(view=None, redirect_field_name='next', login_url=None, if_configured=False): ...
266
class OTPMiddleware: ...
267
```
268
269
[Django Integration](./django-integration.md)
270
271
### Admin Interface
272
273
Admin classes and forms for managing OTP devices through Django's admin interface.
274
275
```python { .api }
276
class OTPAdminSite(admin.AdminSite): ...
277
class OTPAdminAuthenticationForm(AdminAuthenticationForm, OTPAuthenticationFormMixin): ...
278
```
279
280
[Admin Interface](./admin-interface.md)
281
282
### OATH Algorithms
283
284
Low-level implementations of HOTP and TOTP algorithms for direct use or custom device implementations.
285
286
```python { .api }
287
def hotp(key, counter, digits=6): ...
288
def totp(key, step=30, t0=0, digits=6, drift=0): ...
289
class TOTP: ...
290
```
291
292
[OATH Algorithms](./oath-algorithms.md)
293
294
### QR Code Generation
295
296
Utility for generating QR codes for device setup, supporting both qrcode and segno libraries.
297
298
```python { .api }
299
def write_qrcode_image(data, out):
300
"""
301
Write a QR code image for data to out in SVG format.
302
303
Args:
304
data: Data to encode in QR code
305
out: Output stream to write SVG image
306
307
Raises:
308
ModuleNotFoundError: If neither qrcode nor segno is available
309
"""
310
```
311
312
### Utilities and Validation
313
314
Helper functions for generating secure tokens and validating hex-encoded data.
315
316
```python { .api }
317
def random_hex(length: int = 20) -> str:
318
"""
319
Returns a string of random bytes encoded as hex.
320
321
Args:
322
length: The number of (decoded) bytes to return
323
324
Returns:
325
A string of hex digits
326
"""
327
328
def random_number_token(length: int = 6) -> str:
329
"""
330
Returns a string of random digits.
331
332
Args:
333
length: The number of digits to return
334
335
Returns:
336
A string of decimal digits
337
"""
338
339
def hex_validator(length: int = 0):
340
"""
341
Returns a function to validate hex-encoded CharField values.
342
343
Args:
344
length: If > 0, validation fails unless decoded value is exactly this many bytes
345
346
Returns:
347
Validator function for use in model fields
348
"""
349
```
350
351
### Middleware Functions
352
353
Utility functions for checking OTP verification status.
354
355
```python { .api }
356
def is_verified(user) -> bool:
357
"""
358
Check if a user has been verified with OTP.
359
360
Args:
361
user: User object to check
362
363
Returns:
364
True if user.otp_device is not None
365
"""
366
```
367
368
## Constants
369
370
```python { .api }
371
DEVICE_ID_SESSION_KEY = 'otp_device_id' # Session key for storing device ID
372
```
373
374
## Common Types
375
376
```python { .api }
377
# Device verification states
378
class GenerateNotAllowed(enum.Enum):
379
"""Enum for reasons why token generation is not allowed."""
380
COOLDOWN_DURATION_PENDING = 'COOLDOWN_DURATION_PENDING'
381
382
class VerifyNotAllowed(enum.Enum):
383
"""Enum for reasons why token verification is not allowed."""
384
N_FAILED_ATTEMPTS = 'N_FAILED_ATTEMPTS'
385
386
# Settings wrapper
387
class Settings:
388
"""Settings object for django-otp configuration."""
389
def __getattr__(self, name): ...
390
391
# Device manager
392
class DeviceManager(models.Manager):
393
"""Manager for Device models."""
394
def devices_for_user(self, user, confirmed=None): ...
395
396
# Model mixins
397
class CooldownMixin(models.Model):
398
"""Mixin that provides cooldown functionality for devices."""
399
class Meta:
400
abstract = True
401
402
class ThrottlingMixin(models.Model):
403
"""Mixin that provides throttling functionality for devices."""
404
class Meta:
405
abstract = True
406
407
class TimestampMixin(models.Model):
408
"""Mixin that provides timestamp tracking for devices."""
409
class Meta:
410
abstract = True
411
```