or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

account-management.mdcore-config.mdheadless-api.mdindex.mdmfa.mdsocial-authentication.mdtemplate-system.mduser-sessions.md

mfa.mddocs/

0

# Multi-Factor Authentication

1

2

TOTP authenticators, WebAuthn hardware keys, recovery codes, and MFA management flows. Provides enterprise-grade security with support for multiple authentication factors including time-based codes, hardware security keys, and backup recovery codes.

3

4

## Capabilities

5

6

### Models

7

8

Core models for managing MFA authenticators, recovery codes, and authentication sessions.

9

10

```python { .api }

11

class Authenticator(models.Model):

12

"""

13

Base model for MFA authenticators (TOTP, WebAuthn, etc.).

14

"""

15

user: User = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

16

type: str = models.CharField(max_length=20)

17

data: dict = models.JSONField(default=dict)

18

created_at: datetime = models.DateTimeField(auto_now_add=True)

19

last_used_at: Optional[datetime] = models.DateTimeField(null=True, blank=True)

20

21

def __str__(self) -> str: ...

22

def record_usage(self) -> None: ...

23

24

class RecoveryCode(models.Model):

25

"""

26

Recovery codes for MFA account recovery.

27

"""

28

user: User = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

29

code: str = models.CharField(max_length=16)

30

used_at: Optional[datetime] = models.DateTimeField(null=True, blank=True)

31

32

def is_used(self) -> bool: ...

33

def use_code(self) -> None: ...

34

35

class AuthenticationSession(models.Model):

36

"""

37

Track MFA authentication sessions.

38

"""

39

user: User = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

40

created_at: datetime = models.DateTimeField(auto_now_add=True)

41

expires_at: datetime = models.DateTimeField()

42

token: str = models.CharField(max_length=255)

43

44

def is_expired(self) -> bool: ...

45

```

46

47

### TOTP (Time-based One-Time Passwords)

48

49

TOTP authenticator implementation using standard RFC 6238.

50

51

```python { .api }

52

class TOTPAuthenticator:

53

"""

54

Time-based One-Time Password authenticator.

55

"""

56

57

def __init__(self, authenticator: Authenticator): ...

58

59

def generate_qr_code(self, name: str = None) -> str:

60

"""

61

Generate QR code URL for TOTP setup.

62

63

Parameters:

64

- name: Optional name for the account

65

66

Returns:

67

QR code data URL

68

"""

69

70

def get_secret_key(self) -> str:

71

"""

72

Get the secret key for manual entry.

73

74

Returns:

75

Base32-encoded secret key

76

"""

77

78

def validate_token(self, token: str) -> bool:

79

"""

80

Validate TOTP token.

81

82

Parameters:

83

- token: 6-digit TOTP code

84

85

Returns:

86

True if token is valid

87

"""

88

89

@classmethod

90

def generate_secret(cls) -> str:

91

"""

92

Generate new TOTP secret.

93

94

Returns:

95

Base32-encoded secret

96

"""

97

98

def get_totp_key(user: User) -> str:

99

"""

100

Get or generate TOTP secret key for user.

101

102

Parameters:

103

- user: User instance

104

105

Returns:

106

TOTP secret key

107

"""

108

109

def validate_totp_token(user: User, token: str) -> bool:

110

"""

111

Validate TOTP token for user.

112

113

Parameters:

114

- user: User instance

115

- token: TOTP token to validate

116

117

Returns:

118

True if token is valid

119

"""

120

```

121

122

### WebAuthn (Hardware Security Keys)

123

124

WebAuthn implementation for hardware security keys and platform authenticators.

125

126

```python { .api }

127

class WebAuthnAuthenticator:

128

"""

129

WebAuthn hardware security key authenticator.

130

"""

131

132

def __init__(self, authenticator: Authenticator): ...

133

134

def get_credential_creation_options(self, request: HttpRequest) -> Dict[str, Any]:

135

"""

136

Get options for WebAuthn credential creation.

137

138

Parameters:

139

- request: HTTP request object

140

141

Returns:

142

WebAuthn creation options dictionary

143

"""

144

145

def verify_registration(self, request: HttpRequest, credential: Dict[str, Any]) -> bool:

146

"""

147

Verify WebAuthn registration.

148

149

Parameters:

150

- request: HTTP request object

151

- credential: WebAuthn credential data

152

153

Returns:

154

True if registration is valid

155

"""

156

157

def get_credential_request_options(self, request: HttpRequest) -> Dict[str, Any]:

158

"""

159

Get options for WebAuthn authentication.

160

161

Parameters:

162

- request: HTTP request object

163

164

Returns:

165

WebAuthn request options dictionary

166

"""

167

168

def verify_authentication(self, request: HttpRequest, credential: Dict[str, Any]) -> bool:

169

"""

170

Verify WebAuthn authentication.

171

172

Parameters:

173

- request: HTTP request object

174

- credential: WebAuthn credential data

175

176

Returns:

177

True if authentication is valid

178

"""

179

180

def get_webauthn_rp_id(request: HttpRequest) -> str:

181

"""

182

Get WebAuthn Relying Party ID from request.

183

184

Parameters:

185

- request: HTTP request object

186

187

Returns:

188

RP ID string

189

"""

190

191

def get_webauthn_origin(request: HttpRequest) -> str:

192

"""

193

Get WebAuthn origin from request.

194

195

Parameters:

196

- request: HTTP request object

197

198

Returns:

199

Origin URL string

200

"""

201

```

202

203

### Recovery Codes

204

205

Recovery code generation and management for MFA account recovery.

206

207

```python { .api }

208

def generate_recovery_codes(user: User, count: int = 10) -> List[str]:

209

"""

210

Generate recovery codes for user.

211

212

Parameters:

213

- user: User instance

214

- count: Number of codes to generate

215

216

Returns:

217

List of recovery code strings

218

"""

219

220

def validate_recovery_code(user: User, code: str) -> bool:

221

"""

222

Validate and consume recovery code.

223

224

Parameters:

225

- user: User instance

226

- code: Recovery code to validate

227

228

Returns:

229

True if code is valid and unused

230

"""

231

232

def get_unused_recovery_codes(user: User) -> List[RecoveryCode]:

233

"""

234

Get unused recovery codes for user.

235

236

Parameters:

237

- user: User instance

238

239

Returns:

240

List of unused RecoveryCode instances

241

"""

242

243

def regenerate_recovery_codes(user: User) -> List[str]:

244

"""

245

Regenerate all recovery codes for user.

246

247

Parameters:

248

- user: User instance

249

250

Returns:

251

List of new recovery code strings

252

"""

253

```

254

255

### Views

256

257

Django views for MFA setup, authentication, and management.

258

259

```python { .api }

260

class AuthenticateView(FormView):

261

"""

262

MFA authentication view.

263

"""

264

template_name: str = "mfa/authenticate.html"

265

form_class: type = AuthenticateForm

266

267

def get_form_kwargs(self) -> Dict[str, Any]: ...

268

def form_valid(self, form: AuthenticateForm) -> HttpResponse: ...

269

270

class TOTPAddView(FormView):

271

"""

272

Add TOTP authenticator view.

273

"""

274

template_name: str = "mfa/totp/add.html"

275

form_class: type = TOTPAddForm

276

277

def get_context_data(self, **kwargs) -> Dict[str, Any]: ...

278

def form_valid(self, form: TOTPAddForm) -> HttpResponse: ...

279

280

class TOTPRemoveView(FormView):

281

"""

282

Remove TOTP authenticator view.

283

"""

284

template_name: str = "mfa/totp/remove.html"

285

form_class: type = TOTPRemoveForm

286

287

class WebAuthnAddView(FormView):

288

"""

289

Add WebAuthn authenticator view.

290

"""

291

template_name: str = "mfa/webauthn/add.html"

292

form_class: type = WebAuthnAddForm

293

294

def get_context_data(self, **kwargs) -> Dict[str, Any]: ...

295

296

class RecoveryCodesView(TemplateView):

297

"""

298

Recovery codes management view.

299

"""

300

template_name: str = "mfa/recovery_codes/index.html"

301

302

def get_context_data(self, **kwargs) -> Dict[str, Any]: ...

303

304

class RecoveryCodesGenerateView(FormView):

305

"""

306

Generate new recovery codes view.

307

"""

308

template_name: str = "mfa/recovery_codes/generate.html"

309

form_class: type = GenerateRecoveryCodesForm

310

311

def form_valid(self, form: GenerateRecoveryCodesForm) -> HttpResponse: ...

312

```

313

314

### Forms

315

316

Django forms for MFA setup and authentication.

317

318

```python { .api }

319

class AuthenticateForm(forms.Form):

320

"""

321

MFA authentication form.

322

"""

323

code: str = forms.CharField(max_length=16)

324

325

def __init__(self, user: User, request: HttpRequest, *args, **kwargs): ...

326

def clean_code(self) -> str: ...

327

328

class TOTPAddForm(forms.Form):

329

"""

330

TOTP setup form.

331

"""

332

secret: str = forms.CharField(widget=forms.HiddenInput)

333

code: str = forms.CharField(max_length=6)

334

335

def __init__(self, user: User, *args, **kwargs): ...

336

def clean_code(self) -> str: ...

337

def save(self) -> Authenticator: ...

338

339

class TOTPRemoveForm(forms.Form):

340

"""

341

TOTP removal form.

342

"""

343

authenticator: int = forms.ModelChoiceField(queryset=None)

344

345

def __init__(self, user: User, *args, **kwargs): ...

346

def save(self) -> None: ...

347

348

class WebAuthnAddForm(forms.Form):

349

"""

350

WebAuthn setup form.

351

"""

352

name: str = forms.CharField(max_length=100)

353

credential: str = forms.CharField(widget=forms.HiddenInput)

354

355

def __init__(self, user: User, request: HttpRequest, *args, **kwargs): ...

356

def save(self) -> Authenticator: ...

357

358

class GenerateRecoveryCodesForm(forms.Form):

359

"""

360

Recovery code generation form.

361

"""

362

363

def __init__(self, user: User, *args, **kwargs): ...

364

def save(self) -> List[str]: ...

365

```

366

367

### Utilities

368

369

MFA utility functions and helpers.

370

371

```python { .api }

372

def is_mfa_enabled(user: User) -> bool:

373

"""

374

Check if user has MFA enabled.

375

376

Parameters:

377

- user: User instance

378

379

Returns:

380

True if user has any MFA authenticators

381

"""

382

383

def get_user_authenticators(user: User, authenticator_type: str = None) -> QuerySet:

384

"""

385

Get user's MFA authenticators.

386

387

Parameters:

388

- user: User instance

389

- authenticator_type: Optional filter by authenticator type

390

391

Returns:

392

QuerySet of Authenticator instances

393

"""

394

395

def create_authentication_session(user: User) -> AuthenticationSession:

396

"""

397

Create MFA authentication session.

398

399

Parameters:

400

- user: User instance

401

402

Returns:

403

AuthenticationSession instance

404

"""

405

406

def verify_authentication_session(token: str) -> Optional[AuthenticationSession]:

407

"""

408

Verify MFA authentication session token.

409

410

Parameters:

411

- token: Session token

412

413

Returns:

414

AuthenticationSession instance if valid, None otherwise

415

"""

416

```

417

418

## Usage Examples

419

420

### TOTP Setup

421

422

```python

423

from allauth.mfa.totp import TOTPAuthenticator, get_totp_key

424

from allauth.mfa.models import Authenticator

425

426

# Generate TOTP secret for user

427

secret = get_totp_key(user)

428

429

# Create authenticator

430

authenticator = Authenticator.objects.create(

431

user=user,

432

type='totp',

433

data={'secret': secret}

434

)

435

436

# Generate QR code for setup

437

totp_auth = TOTPAuthenticator(authenticator)

438

qr_code_url = totp_auth.generate_qr_code(f"{user.username}@example.com")

439

440

# Validate TOTP token

441

is_valid = totp_auth.validate_token('123456')

442

```

443

444

### WebAuthn Setup

445

446

```python

447

from allauth.mfa.webauthn import WebAuthnAuthenticator

448

from allauth.mfa.models import Authenticator

449

450

# Create WebAuthn authenticator

451

authenticator = Authenticator.objects.create(

452

user=user,

453

type='webauthn',

454

data={}

455

)

456

457

webauthn_auth = WebAuthnAuthenticator(authenticator)

458

459

# Get registration options (send to frontend)

460

creation_options = webauthn_auth.get_credential_creation_options(request)

461

462

# Verify registration (after credential creation)

463

credential_data = {

464

'id': 'credential_id',

465

'rawId': 'raw_credential_id',

466

'response': {

467

'attestationObject': 'attestation_data',

468

'clientDataJSON': 'client_data'

469

}

470

}

471

472

is_valid = webauthn_auth.verify_registration(request, credential_data)

473

```

474

475

### Recovery Codes

476

477

```python

478

from allauth.mfa.recovery_codes import (

479

generate_recovery_codes,

480

validate_recovery_code,

481

get_unused_recovery_codes

482

)

483

484

# Generate recovery codes

485

codes = generate_recovery_codes(user, count=10)

486

print("Recovery codes:", codes)

487

488

# Validate and use recovery code

489

is_valid = validate_recovery_code(user, 'ABC123DEF')

490

491

# Check remaining codes

492

remaining_codes = get_unused_recovery_codes(user)

493

print(f"Remaining codes: {len(remaining_codes)}")

494

```

495

496

### MFA Authentication Flow

497

498

```python

499

from allauth.mfa.utils import is_mfa_enabled, create_authentication_session

500

501

# Check if user has MFA enabled

502

if is_mfa_enabled(user):

503

# Create authentication session

504

session = create_authentication_session(user)

505

506

# Store session token (e.g., in session or redirect parameter)

507

request.session['mfa_session_token'] = session.token

508

509

# Redirect to MFA authentication page

510

return redirect('mfa_authenticate')

511

```

512

513

### Template Usage

514

515

```html

516

<!-- MFA status in user profile -->

517

{% if user.is_authenticated %}

518

{% load mfa_tags %}

519

520

<h3>Multi-Factor Authentication</h3>

521

{% if user|is_mfa_enabled %}

522

<p class="text-success">✓ MFA is enabled</p>

523

524

<!-- Show authenticators -->

525

{% for auth in user.authenticator_set.all %}

526

<div class="authenticator">

527

<strong>{{ auth.get_type_display }}</strong>

528

<small>Added {{ auth.created_at|date }}</small>

529

</div>

530

{% endfor %}

531

532

<a href="{% url 'mfa_recovery_codes' %}">View Recovery Codes</a>

533

{% else %}

534

<p class="text-warning">⚠ MFA is not enabled</p>

535

<a href="{% url 'mfa_add_totp' %}" class="btn btn-primary">Enable TOTP</a>

536

<a href="{% url 'mfa_add_webauthn' %}" class="btn btn-secondary">Add Security Key</a>

537

{% endif %}

538

{% endif %}

539

```

540

541

### Settings Configuration

542

543

```python

544

# In Django settings.py

545

546

# Enable MFA

547

INSTALLED_APPS = [

548

# ...

549

'allauth.mfa',

550

]

551

552

# MFA settings

553

MFA_TOTP_ISSUER = 'My Application'

554

MFA_RECOVERY_CODE_COUNT = 10

555

MFA_WEBAUTHN_RP_NAME = 'My Application'

556

557

# Require MFA for certain views

558

MFA_REQUIRED_FOR_STAFF = True

559

MFA_GRACE_PERIOD_SECONDS = 300 # 5 minutes

560

```