0
# Multi-Authentication
1
2
Combines multiple authentication methods into a single handler, automatically selecting the appropriate authentication method based on request headers. MultiAuth enables flexible endpoint protection with fallback authentication schemes.
3
4
## Capabilities
5
6
### MultiAuth Class
7
8
Creates a multi-authentication handler that combines different authentication methods.
9
10
```python { .api }
11
class MultiAuth:
12
def __init__(self, main_auth, *args):
13
"""
14
Initialize multi-authentication handler.
15
16
Parameters:
17
- main_auth: Primary authentication method (used as fallback)
18
- *args: Additional authentication methods to support
19
20
Usage:
21
multi_auth = MultiAuth(basic_auth, token_auth, digest_auth)
22
"""
23
```
24
25
### Route Protection
26
27
Protect Flask routes with automatic authentication method selection.
28
29
```python { .api }
30
def login_required(self, f=None, role=None, optional=None):
31
"""
32
Decorator to require authentication using any compatible method.
33
34
Parameters:
35
- f (function, optional): Flask route function to protect
36
- role (str|list, optional): Required user role(s)
37
- optional (bool, optional): Make authentication optional
38
39
Returns:
40
Decorated function or decorator
41
42
Usage:
43
@multi_auth.login_required
44
def flexible_endpoint():
45
return f"Hello {multi_auth.current_user()}"
46
47
@multi_auth.login_required(role='admin')
48
def admin_endpoint():
49
return "Admin access via any auth method"
50
"""
51
```
52
53
### User Information
54
55
Access current authenticated user information within protected routes.
56
57
```python { .api }
58
def current_user(self):
59
"""
60
Get current authenticated user from whichever auth method was used.
61
62
Returns:
63
User object from the authentication method that handled the request
64
"""
65
```
66
67
## Usage Examples
68
69
### Basic + Token Authentication
70
71
```python
72
from flask import Flask
73
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth, MultiAuth
74
from werkzeug.security import generate_password_hash, check_password_hash
75
76
app = Flask(__name__)
77
78
# Set up Basic authentication
79
basic_auth = HTTPBasicAuth()
80
users = {
81
"john": generate_password_hash("hello"),
82
"susan": generate_password_hash("bye")
83
}
84
85
@basic_auth.verify_password
86
def verify_password(username, password):
87
if username in users and check_password_hash(users.get(username), password):
88
return username
89
90
# Set up Token authentication
91
token_auth = HTTPTokenAuth('Bearer')
92
tokens = {
93
"secret-token-1": "john",
94
"secret-token-2": "susan"
95
}
96
97
@token_auth.verify_token
98
def verify_token(token):
99
return tokens.get(token)
100
101
# Combine authentication methods
102
multi_auth = MultiAuth(basic_auth, token_auth)
103
104
@app.route('/api/data')
105
@multi_auth.login_required
106
def get_data():
107
return {
108
"user": multi_auth.current_user(),
109
"data": "Available via Basic auth or Bearer token"
110
}
111
112
# Usage examples:
113
# curl -u john:hello http://localhost:5000/api/data
114
# curl -H "Authorization: Bearer secret-token-1" http://localhost:5000/api/data
115
```
116
117
### Three-Way Authentication
118
119
```python
120
from flask import Flask
121
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth, HTTPDigestAuth, MultiAuth
122
123
app = Flask(__name__)
124
app.config['SECRET_KEY'] = 'secret key'
125
126
# Set up Basic authentication
127
basic_auth = HTTPBasicAuth()
128
129
@basic_auth.verify_password
130
def verify_basic_password(username, password):
131
users = {"john": "hello", "susan": "bye"}
132
if username in users and users[username] == password:
133
return username
134
135
# Set up Digest authentication
136
digest_auth = HTTPDigestAuth()
137
138
@digest_auth.get_password
139
def get_digest_password(username):
140
users = {"john": "hello", "susan": "bye"}
141
return users.get(username)
142
143
# Set up Token authentication
144
token_auth = HTTPTokenAuth('Bearer')
145
146
@token_auth.verify_token
147
def verify_token(token):
148
tokens = {"token123": "john", "token456": "susan"}
149
return tokens.get(token)
150
151
# Combine all three methods
152
multi_auth = MultiAuth(basic_auth, digest_auth, token_auth)
153
154
@app.route('/api/flexible')
155
@multi_auth.login_required
156
def flexible_endpoint():
157
return {
158
"message": f"Hello {multi_auth.current_user()}",
159
"auth_method": "Any of: Basic, Digest, or Bearer token"
160
}
161
```
162
163
### Role-Based Multi-Auth
164
165
```python
166
from flask import Flask
167
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth, MultiAuth
168
169
app = Flask(__name__)
170
171
# Set up authentication methods
172
basic_auth = HTTPBasicAuth()
173
token_auth = HTTPTokenAuth('Bearer')
174
175
# User database with roles
176
users = {
177
"john": {"password": "hello", "roles": ["user"]},
178
"susan": {"password": "bye", "roles": ["user", "admin"]},
179
"admin": {"password": "secret", "roles": ["admin"]}
180
}
181
182
tokens = {
183
"user-token": {"user": "john", "roles": ["user"]},
184
"admin-token": {"user": "susan", "roles": ["user", "admin"]}
185
}
186
187
@basic_auth.verify_password
188
def verify_password(username, password):
189
if username in users and users[username]["password"] == password:
190
return {"username": username, "roles": users[username]["roles"]}
191
192
@basic_auth.get_user_roles
193
def get_basic_user_roles(user):
194
return user["roles"]
195
196
@token_auth.verify_token
197
def verify_token(token):
198
if token in tokens:
199
return tokens[token]
200
201
@token_auth.get_user_roles
202
def get_token_user_roles(user):
203
return user["roles"]
204
205
# Combine with role support
206
multi_auth = MultiAuth(basic_auth, token_auth)
207
208
@app.route('/api/user')
209
@multi_auth.login_required(role='user')
210
def user_endpoint():
211
return {"message": f"User access: {multi_auth.current_user()}"}
212
213
@app.route('/api/admin')
214
@multi_auth.login_required(role='admin')
215
def admin_endpoint():
216
return {"message": f"Admin access: {multi_auth.current_user()}"}
217
```
218
219
### Custom Authentication Priority
220
221
```python
222
from flask import Flask
223
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth, MultiAuth
224
225
app = Flask(__name__)
226
227
# High-priority authentication (checked first)
228
api_key_auth = HTTPTokenAuth('ApiKey', header='X-API-Key')
229
230
@api_key_auth.verify_token
231
def verify_api_key(key):
232
if key == "premium-api-key":
233
return {"user": "premium_user", "tier": "premium"}
234
235
# Fallback authentication
236
basic_auth = HTTPBasicAuth()
237
238
@basic_auth.verify_password
239
def verify_password(username, password):
240
if username == "regular" and password == "user":
241
return {"user": "regular_user", "tier": "basic"}
242
243
# API key auth has priority over basic auth
244
multi_auth = MultiAuth(api_key_auth, basic_auth)
245
246
@app.route('/api/service')
247
@multi_auth.login_required
248
def service_endpoint():
249
user = multi_auth.current_user()
250
return {
251
"user": user["user"],
252
"tier": user["tier"],
253
"message": "Service accessed with priority auth selection"
254
}
255
256
# Usage:
257
# curl -H "X-API-Key: premium-api-key" http://localhost:5000/api/service (premium)
258
# curl -u regular:user http://localhost:5000/api/service (basic)
259
```
260
261
## Authentication Method Selection
262
263
MultiAuth automatically selects the appropriate authentication method based on request headers:
264
265
1. **Header Inspection**: Examines incoming request headers
266
2. **Compatibility Check**: Tests each auth method's `is_compatible_auth()` method
267
3. **First Match**: Uses the first compatible authentication method found
268
4. **Fallback**: Uses main authentication method if no others match
269
270
The selection order follows the constructor parameter order: `MultiAuth(first_priority, second_priority, ...)`.
271
272
## Error Handling
273
274
MultiAuth delegates error handling to the selected authentication method:
275
276
- **401 Unauthorized**: No compatible authentication method found valid credentials
277
- **403 Forbidden**: Authentication succeeded but role authorization failed
278
- **Method-Specific Errors**: Each auth method handles its own error responses
279
- **Automatic Header**: WWW-Authenticate header from the selected auth method
280
281
The error response format depends on which authentication method processed the request.