or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-interface.mdcore-authentication.mddevice-models.mddjango-integration.mdemail-devices.mdhotp-devices.mdindex.mdoath-algorithms.mdstatic-tokens.mdtotp-devices.md

static-tokens.mddocs/

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.