0
# Static Tokens
1
2
Pre-generated backup codes for emergency access when primary OTP devices are unavailable. Static tokens are single-use codes that provide reliable backup authentication.
3
4
## Capabilities
5
6
### StaticDevice Model
7
8
```python { .api }
9
class StaticDevice(TimestampMixin, ThrottlingMixin, Device):
10
"""
11
Static token device for backup/emergency codes.
12
"""
13
14
def verify_token(self, token) -> bool:
15
"""
16
Verify and consume static token.
17
18
Parameters:
19
- token: str - Static token to verify
20
21
Returns:
22
bool - True if token was valid and consumed
23
"""
24
25
def get_throttle_factor(self) -> int:
26
"""Return throttle factor from settings."""
27
```
28
29
### StaticToken Model
30
31
```python { .api }
32
class StaticToken(models.Model):
33
"""
34
Individual static token.
35
36
Fields:
37
- device: ForeignKey(StaticDevice) - Associated device
38
- token: CharField(max_length=16) - Token value
39
"""
40
41
device = models.ForeignKey(StaticDevice, on_delete=models.CASCADE)
42
token = models.CharField(max_length=16)
43
44
@staticmethod
45
def random_token() -> str:
46
"""Generate random token string."""
47
```
48
49
### Admin Interface
50
51
```python { .api }
52
class StaticDeviceAdmin(admin.ModelAdmin):
53
"""Admin interface for StaticDevice."""
54
55
class StaticTokenInline(admin.TabularInline):
56
"""Inline admin for StaticToken."""
57
```
58
59
### Library Functions
60
61
```python { .api }
62
def add_static_token(username, token=None):
63
"""
64
Add static token to user (used by management command).
65
66
Parameters:
67
- username: str - Username to add token for
68
- token: str or None - Specific token value or None for random
69
70
Returns:
71
StaticToken - The created token instance
72
"""
73
```
74
75
### Management Commands
76
77
```python { .api }
78
# Django management command
79
python manage.py addstatictoken <username> [token]
80
```
81
82
## Usage Examples
83
84
### Creating Static Token Devices
85
86
```python
87
from django_otp.plugins.otp_static.models import StaticDevice, StaticToken
88
89
# Create device with tokens
90
device = StaticDevice.objects.create(
91
user=user,
92
name='Backup Codes',
93
confirmed=True
94
)
95
96
# Generate backup tokens
97
backup_codes = []
98
for i in range(10): # Generate 10 backup codes
99
token = StaticToken.objects.create(
100
device=device,
101
token=StaticToken.random_token()
102
)
103
backup_codes.append(token.token)
104
105
print("Your backup codes:")
106
for code in backup_codes:
107
print(f"- {code}")
108
```
109
110
### Token Verification and Consumption
111
112
```python
113
def verify_static_token(user, token):
114
"""Verify static token and show remaining count."""
115
116
try:
117
device = StaticDevice.objects.get(user=user, confirmed=True)
118
remaining_before = device.statictoken_set.count()
119
120
if device.verify_token(token):
121
remaining_after = device.statictoken_set.count()
122
return {
123
'valid': True,
124
'remaining_tokens': remaining_after,
125
'message': f"Token verified. {remaining_after} backup codes remaining."
126
}
127
else:
128
return {
129
'valid': False,
130
'remaining_tokens': remaining_before,
131
'message': "Invalid backup code."
132
}
133
134
except StaticDevice.DoesNotExist:
135
return {
136
'valid': False,
137
'remaining_tokens': 0,
138
'message': "No backup codes configured."
139
}
140
141
# Usage
142
result = verify_static_token(user, 'abc123def456')
143
print(result['message'])
144
```
145
146
### Bulk Token Management
147
148
```python
149
def regenerate_backup_codes(user, count=10):
150
"""Regenerate all backup codes for a user."""
151
152
try:
153
device = StaticDevice.objects.get(user=user)
154
155
# Remove existing tokens
156
device.statictoken_set.all().delete()
157
158
# Generate new tokens
159
new_codes = []
160
for i in range(count):
161
token = StaticToken.objects.create(
162
device=device,
163
token=StaticToken.random_token()
164
)
165
new_codes.append(token.token)
166
167
return new_codes
168
169
except StaticDevice.DoesNotExist:
170
# Create new device if none exists
171
device = StaticDevice.objects.create(
172
user=user,
173
name='Backup Codes',
174
confirmed=True
175
)
176
return regenerate_backup_codes(user, count)
177
178
# Usage
179
new_backup_codes = regenerate_backup_codes(user)
180
```
181
182
### Using Management Command
183
184
```bash
185
# Add random token for user
186
python manage.py addstatictoken alice
187
188
# Add specific token for user
189
python manage.py addstatictoken alice mytoken123
190
191
# The command uses the add_static_token library function
192
```
193
194
### Checking Remaining Tokens
195
196
```python
197
def get_backup_code_info(user):
198
"""Get backup code information for user."""
199
200
try:
201
device = StaticDevice.objects.get(user=user, confirmed=True)
202
tokens = device.statictoken_set.all()
203
204
return {
205
'has_backup_codes': True,
206
'total_codes': tokens.count(),
207
'codes': [token.token for token in tokens] # Only for admin display
208
}
209
210
except StaticDevice.DoesNotExist:
211
return {
212
'has_backup_codes': False,
213
'total_codes': 0,
214
'codes': []
215
}
216
217
# Usage (for admin/user dashboard)
218
info = get_backup_code_info(user)
219
print(f"User has {info['total_codes']} backup codes remaining")
220
```
221
222
## Configuration Settings
223
224
```python
225
# settings.py
226
227
# Throttling factor for failed attempts (default: 1)
228
OTP_STATIC_THROTTLE_FACTOR = 2
229
```
230
231
## Security Considerations
232
233
### Single Use
234
235
Static tokens are consumed immediately upon successful verification and cannot be reused. This prevents replay attacks but means users need multiple backup codes.
236
237
### Storage
238
239
Backup codes should be stored securely by users (password manager, secure physical storage) and never transmitted over insecure channels.
240
241
### Regeneration
242
243
Consider implementing a policy for periodic regeneration of backup codes, especially after any security incidents or when codes are running low.