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

totp-devices.mddocs/

0

# TOTP Devices

1

2

Time-based one-time passwords (TOTP) following RFC 6238, typically used with authenticator apps like Google Authenticator, Authy, or 1Password. TOTP generates tokens based on the current time and a shared secret key.

3

4

## Capabilities

5

6

### TOTPDevice Model

7

8

The main model for TOTP-based OTP devices with built-in security features and drift compensation.

9

10

```python { .api }

11

class TOTPDevice(TimestampMixin, ThrottlingMixin, Device):

12

"""

13

Time-based OTP device following RFC 6238.

14

15

Fields:

16

- key: CharField(max_length=80) - Hex-encoded secret key

17

- step: PositiveSmallIntegerField(default=30) - Time step in seconds

18

- t0: BigIntegerField(default=0) - Unix time to start counting

19

- digits: PositiveSmallIntegerField - Number of digits (6 or 8)

20

- tolerance: PositiveSmallIntegerField(default=1) - Time step tolerance

21

- drift: SmallIntegerField(default=0) - Clock drift compensation

22

- last_t: BigIntegerField(default=-1) - Last verified time step

23

"""

24

25

key = models.CharField(max_length=80, validators=[hex_validator()])

26

step = models.PositiveSmallIntegerField(default=30)

27

t0 = models.BigIntegerField(default=0)

28

digits = models.PositiveSmallIntegerField(choices=[(6, 6), (8, 8)], default=6)

29

tolerance = models.PositiveSmallIntegerField(default=1)

30

drift = models.SmallIntegerField(default=0)

31

last_t = models.BigIntegerField(default=-1)

32

33

@property

34

def bin_key(self) -> bytes:

35

"""Secret key as binary string."""

36

37

@property

38

def config_url(self) -> str:

39

"""Configuration URL for QR codes and authenticator apps."""

40

41

def verify_token(self, token) -> bool:

42

"""

43

Verify TOTP token with drift compensation.

44

45

Parameters:

46

- token: str - Token to verify

47

48

Returns:

49

bool - True if token is valid

50

"""

51

52

def get_throttle_factor(self) -> int:

53

"""Return throttle factor from settings."""

54

```

55

56

### Admin Interface

57

58

Admin interface for managing TOTP devices with QR code generation support.

59

60

```python { .api }

61

class TOTPDeviceAdmin(admin.ModelAdmin):

62

"""Admin interface for TOTPDevice with QR code support."""

63

64

def qrcode_link(self, device):

65

"""Generate QR code link for device configuration."""

66

67

def config_view(self, request, pk):

68

"""Configuration view showing device setup information."""

69

70

def qrcode_view(self, request, pk):

71

"""QR code image view for device setup."""

72

```

73

74

## Usage Examples

75

76

### Creating TOTP Devices

77

78

```python

79

from django_otp.plugins.otp_totp.models import TOTPDevice

80

from django.contrib.auth.models import User

81

82

# Create a basic TOTP device

83

user = User.objects.get(username='alice')

84

device = TOTPDevice.objects.create(

85

user=user,

86

name='My Phone Authenticator',

87

confirmed=False # Set to True after user confirms setup

88

)

89

90

# Create device with custom settings

91

device = TOTPDevice.objects.create(

92

user=user,

93

name='High Security Device',

94

digits=8, # 8-digit tokens instead of 6

95

step=60, # 60-second time step instead of 30

96

tolerance=2 # Allow 2 time steps of tolerance

97

)

98

99

print(f"Device key: {device.key}")

100

print(f"Setup URL: {device.config_url}")

101

```

102

103

### QR Code Generation

104

105

```python

106

from django_otp.qr import write_qrcode_image

107

from io import BytesIO

108

109

def generate_qr_code_for_device(device):

110

"""Generate QR code image for TOTP device setup."""

111

112

# Create QR code data

113

qr_data = device.config_url

114

115

# Generate QR code image

116

img_buffer = BytesIO()

117

write_qrcode_image(qr_data, img_buffer)

118

img_buffer.seek(0)

119

120

return img_buffer.getvalue()

121

122

# Usage

123

device = TOTPDevice.objects.get(pk=1)

124

qr_image_data = generate_qr_code_for_device(device)

125

126

# Save to file or return in HTTP response

127

with open('qr_code.png', 'wb') as f:

128

f.write(qr_image_data)

129

```

130

131

### Token Verification

132

133

```python

134

from django_otp.plugins.otp_totp.models import TOTPDevice

135

136

def verify_totp_token(user, token):

137

"""Verify TOTP token for user's device."""

138

139

# Get user's TOTP devices

140

devices = TOTPDevice.objects.filter(user=user, confirmed=True)

141

142

for device in devices:

143

if device.verify_token(token):

144

print(f"Token verified with device: {device.name}")

145

print(f"Device drift: {device.drift}")

146

return device

147

148

return None

149

150

# Usage

151

user = User.objects.get(username='alice')

152

device = verify_totp_token(user, '123456')

153

```

154

155

### Device Configuration URLs

156

157

```python

158

from django_otp.plugins.otp_totp.models import TOTPDevice

159

160

def get_device_setup_info(device):

161

"""Get device setup information for user."""

162

163

info = {

164

'device_name': device.name,

165

'config_url': device.config_url,

166

'manual_setup': {

167

'secret_key': device.key,

168

'digits': device.digits,

169

'step': device.step,

170

'algorithm': 'SHA1'

171

},

172

'qr_code_data': device.config_url

173

}

174

175

return info

176

177

# Usage

178

device = TOTPDevice.objects.get(pk=1)

179

setup_info = get_device_setup_info(device)

180

181

# The config_url can be used in QR codes or manual setup

182

print(f"QR Code URL: {setup_info['config_url']}")

183

print(f"Manual key: {setup_info['manual_setup']['secret_key']}")

184

```

185

186

### Drift Compensation

187

188

```python

189

from django_otp.plugins.otp_totp.models import TOTPDevice

190

from django_otp.oath import TOTP

191

192

def check_device_drift(device):

193

"""Check and display device drift information."""

194

195

totp = TOTP(device.bin_key, device.step, device.t0, device.digits)

196

current_t = totp.t()

197

198

info = {

199

'device_name': device.name,

200

'current_drift': device.drift,

201

'last_verified_t': device.last_t,

202

'current_t': current_t,

203

'time_difference_seconds': (current_t - device.last_t) * device.step if device.last_t >= 0 else None

204

}

205

206

return info

207

208

# Usage

209

device = TOTPDevice.objects.get(pk=1)

210

drift_info = check_device_drift(device)

211

print(f"Current drift: {drift_info['current_drift']} time steps")

212

```

213

214

### Bulk Device Management

215

216

```python

217

from django_otp.plugins.otp_totp.models import TOTPDevice

218

from django.contrib.auth.models import User

219

220

def setup_totp_for_users(usernames, device_name="Default TOTP"):

221

"""Set up TOTP devices for multiple users."""

222

223

devices = []

224

for username in usernames:

225

try:

226

user = User.objects.get(username=username)

227

device = TOTPDevice.objects.create(

228

user=user,

229

name=device_name,

230

confirmed=False

231

)

232

devices.append({

233

'username': username,

234

'device_id': device.pk,

235

'setup_url': device.config_url,

236

'key': device.key

237

})

238

except User.DoesNotExist:

239

print(f"User {username} not found")

240

241

return devices

242

243

# Usage

244

setup_info = setup_totp_for_users(['alice', 'bob', 'charlie'])

245

for info in setup_info:

246

print(f"User: {info['username']}, Key: {info['key']}")

247

```

248

249

## Configuration Settings

250

251

TOTP devices can be configured through Django settings:

252

253

```python

254

# settings.py

255

256

# Enable drift synchronization (default: True)

257

OTP_TOTP_SYNC = True

258

259

# Throttling factor for failed verifications (default: 1)

260

OTP_TOTP_THROTTLE_FACTOR = 2

261

262

# Issuer name for QR codes (default: None)

263

OTP_TOTP_ISSUER = "My Company"

264

265

# Image URL for QR codes (default: None)

266

OTP_TOTP_IMAGE = "https://example.com/logo.png"

267

```

268

269

## Security Considerations

270

271

### Time Synchronization

272

273

TOTP relies on synchronized clocks between client and server. The `tolerance` field allows for some clock skew, and django-otp includes automatic drift compensation to handle gradual clock drift.

274

275

### Throttling

276

277

TOTP devices inherit from `ThrottlingMixin`, which provides exponential backoff for failed verification attempts. Configure the throttle factor through `OTP_TOTP_THROTTLE_FACTOR`.

278

279

### Key Management

280

281

Secret keys should be generated securely and stored safely. The keys are stored as hex-encoded strings in the database and should be backed up appropriately for disaster recovery.