0
# Digest Authentication
1
2
HTTP Digest authentication implementation providing enhanced security over Basic auth through challenge-response mechanisms. Digest auth never transmits passwords in clear text, instead using MD5 hashing with nonce values to prevent replay attacks.
3
4
## Capabilities
5
6
### HTTPDigestAuth Class
7
8
Creates an HTTP Digest authentication handler with configurable algorithms, quality of protection, and nonce/opaque value management.
9
10
```python { .api }
11
class HTTPDigestAuth(HTTPAuth):
12
def __init__(self, scheme=None, realm=None, use_ha1_pw=False, qop='auth', algorithm='MD5'):
13
"""
14
Initialize Digest authentication handler.
15
16
Parameters:
17
- scheme (str, optional): Authentication scheme, defaults to 'Digest'
18
- realm (str, optional): Authentication realm, defaults to 'Authentication Required'
19
- use_ha1_pw (bool): Use HA1 hashed passwords instead of plain passwords
20
- qop (str|list): Quality of protection ('auth' or list of QOP values)
21
- algorithm (str): Hash algorithm ('MD5' or 'MD5-Sess')
22
"""
23
```
24
25
### Nonce Management
26
27
Configure nonce generation and verification for preventing replay attacks.
28
29
```python { .api }
30
def generate_nonce(self, f):
31
"""
32
Decorator to register nonce generation callback.
33
34
Parameters:
35
- f (function): Callback function() -> nonce_string
36
37
Returns:
38
The decorated function
39
40
Usage:
41
@auth.generate_nonce
42
def generate_nonce():
43
return secrets.token_hex(16)
44
"""
45
46
def verify_nonce(self, f):
47
"""
48
Decorator to register nonce verification callback.
49
50
Parameters:
51
- f (function): Callback function(nonce) -> bool
52
53
Returns:
54
The decorated function
55
56
Usage:
57
@auth.verify_nonce
58
def verify_nonce(nonce):
59
return nonce in valid_nonces
60
"""
61
62
def get_nonce(self):
63
"""
64
Generate a new nonce value.
65
66
Returns:
67
str: Generated nonce string
68
"""
69
```
70
71
### Opaque Value Management
72
73
Configure opaque value generation and verification for additional security.
74
75
```python { .api }
76
def generate_opaque(self, f):
77
"""
78
Decorator to register opaque value generation callback.
79
80
Parameters:
81
- f (function): Callback function() -> opaque_string
82
83
Returns:
84
The decorated function
85
"""
86
87
def verify_opaque(self, f):
88
"""
89
Decorator to register opaque value verification callback.
90
91
Parameters:
92
- f (function): Callback function(opaque) -> bool
93
94
Returns:
95
The decorated function
96
"""
97
98
def get_opaque(self):
99
"""
100
Generate a new opaque value.
101
102
Returns:
103
str: Generated opaque string
104
"""
105
```
106
107
### Password and Hash Management
108
109
Handle password retrieval and HA1 hash generation for digest authentication.
110
111
```python { .api }
112
def generate_ha1(self, username, password):
113
"""
114
Generate HA1 hash for digest authentication.
115
116
Parameters:
117
- username (str): Username
118
- password (str): Plain text password
119
120
Returns:
121
str: MD5 hash of username:realm:password
122
"""
123
```
124
125
### Route Protection
126
127
Protect Flask routes with Digest authentication using the login_required decorator.
128
129
```python { .api }
130
def login_required(self, f=None, role=None, optional=None):
131
"""
132
Decorator to require digest authentication for Flask routes.
133
134
Parameters:
135
- f (function, optional): Flask route function to protect
136
- role (str|list, optional): Required user role(s)
137
- optional (bool, optional): Make authentication optional
138
139
Returns:
140
Decorated function or decorator
141
"""
142
```
143
144
### Authentication Header Generation
145
146
Generate proper WWW-Authenticate headers for digest authentication challenges.
147
148
```python { .api }
149
def authenticate_header(self):
150
"""
151
Generate WWW-Authenticate header for digest authentication.
152
153
Returns:
154
str: Properly formatted digest authentication challenge header
155
"""
156
```
157
158
## Usage Examples
159
160
### Basic Digest Authentication
161
162
```python
163
from flask import Flask
164
from flask_httpauth import HTTPDigestAuth
165
166
app = Flask(__name__)
167
app.config['SECRET_KEY'] = 'secret key here'
168
auth = HTTPDigestAuth()
169
170
users = {
171
"john": "hello",
172
"susan": "bye"
173
}
174
175
@auth.get_password
176
def get_pw(username):
177
if username in users:
178
return users.get(username)
179
return None
180
181
@app.route('/')
182
@auth.login_required
183
def index():
184
return f"Hello, {auth.username()}"
185
186
if __name__ == '__main__':
187
app.run()
188
```
189
190
### Custom Nonce Generation
191
192
```python
193
from flask import Flask, session
194
from flask_httpauth import HTTPDigestAuth
195
import secrets
196
import time
197
198
app = Flask(__name__)
199
app.config['SECRET_KEY'] = 'secret key here'
200
auth = HTTPDigestAuth()
201
202
# Store nonces with timestamps
203
nonces = {}
204
205
@auth.generate_nonce
206
def generate_nonce():
207
nonce = secrets.token_hex(16)
208
nonces[nonce] = time.time()
209
return nonce
210
211
@auth.verify_nonce
212
def verify_nonce(nonce):
213
if nonce in nonces:
214
# Check if nonce is still valid (not expired)
215
if time.time() - nonces[nonce] < 300: # 5 minutes
216
return True
217
else:
218
del nonces[nonce]
219
return False
220
```
221
222
### HA1 Password Mode
223
224
```python
225
from flask import Flask
226
from flask_httpauth import HTTPDigestAuth
227
228
app = Flask(__name__)
229
app.config['SECRET_KEY'] = 'secret key here'
230
auth = HTTPDigestAuth(use_ha1_pw=True)
231
232
# Pre-computed HA1 hashes: MD5(username:realm:password)
233
users_ha1 = {
234
"john": "b4bbcabacfa91dcc1f5e1e47e3e6bdbe", # john:Authentication Required:hello
235
"susan": "1f3870be274f6c49b3e31a0c6728957f" # susan:Authentication Required:bye
236
}
237
238
@auth.get_password
239
def get_password_ha1(username):
240
if username in users_ha1:
241
return users_ha1[username]
242
return None
243
244
@app.route('/')
245
@auth.login_required
246
def index():
247
return f"Hello, {auth.username()}"
248
```
249
250
### Custom QOP and Algorithm
251
252
```python
253
from flask import Flask
254
from flask_httpauth import HTTPDigestAuth
255
256
app = Flask(__name__)
257
app.config['SECRET_KEY'] = 'secret key here'
258
259
# Configure digest auth with MD5-Sess algorithm
260
auth = HTTPDigestAuth(qop=['auth', 'auth-int'], algorithm='MD5-Sess')
261
262
users = {
263
"john": "hello",
264
"susan": "bye"
265
}
266
267
@auth.get_password
268
def get_pw(username):
269
return users.get(username)
270
271
@app.route('/')
272
@auth.login_required
273
def index():
274
return f"Hello, {auth.username()}"
275
```
276
277
## Error Handling
278
279
Digest authentication handles various error conditions:
280
281
- **401 Unauthorized**: Invalid credentials, expired nonce, or missing authentication
282
- **403 Forbidden**: Valid credentials but insufficient role permissions
283
- **Automatic Challenge**: WWW-Authenticate header with digest parameters
284
- **Nonce Validation**: Automatic nonce expiration and replay prevention
285
- **Opaque Validation**: Server-side opaque value verification
286
287
The digest implementation automatically manages the challenge-response cycle and validates all digest authentication parameters according to RFC 2617 specifications.