0
# Consumer Authentication
1
2
Complete OpenID consumer implementation for web applications acting as relying parties. The consumer handles the full authentication flow from discovery through response processing, supporting both immediate and setup authentication modes.
3
4
## Capabilities
5
6
### Consumer Initialization
7
8
Initialize an OpenID consumer with session storage and an OpenID store backend.
9
10
```python { .api }
11
class Consumer:
12
def __init__(self, session, store, consumer_class=None):
13
"""
14
Initialize OpenID consumer.
15
16
Parameters:
17
- session: dict-like session storage for the consumer
18
- store: OpenIDStore instance for persistent storage
19
- consumer_class: Optional custom consumer class (defaults to GenericConsumer)
20
"""
21
22
def setAssociationPreference(self, association_preferences):
23
"""
24
Set association preferences for this consumer.
25
26
Parameters:
27
- association_preferences: List of (association_type, session_type) tuples
28
"""
29
```
30
31
### Authentication Flow
32
33
Start and complete the OpenID authentication process with discovery and response handling.
34
35
```python { .api }
36
def begin(self, user_url, anonymous=False):
37
"""
38
Start OpenID authentication for a user URL.
39
40
Parameters:
41
- user_url: str, user's OpenID identifier URL
42
- anonymous: bool, whether to request anonymous authentication
43
44
Returns:
45
AuthRequest object for redirecting user to identity provider
46
47
Raises:
48
DiscoveryFailure: if discovery fails for the user URL
49
"""
50
51
def beginWithoutDiscovery(self, service, anonymous=False):
52
"""
53
Start authentication with a known service endpoint.
54
55
Parameters:
56
- service: OpenIDServiceEndpoint object
57
- anonymous: bool, whether to request anonymous authentication
58
59
Returns:
60
AuthRequest object
61
"""
62
63
def complete(self, query, current_url):
64
"""
65
Complete OpenID authentication from identity provider response.
66
67
Parameters:
68
- query: dict, query parameters from identity provider response
69
- current_url: str, current page URL for verification
70
71
Returns:
72
Response object (SuccessResponse, FailureResponse, CancelResponse, or SetupNeededResponse)
73
"""
74
```
75
76
### Authentication Request
77
78
Represents an OpenID authentication request that can be used to redirect users or generate HTML forms.
79
80
```python { .api }
81
class AuthRequest:
82
def setAnonymous(self, is_anonymous):
83
"""
84
Set whether this request should be anonymous.
85
86
Parameters:
87
- is_anonymous: bool, anonymous flag
88
"""
89
90
def addExtension(self, extension_request):
91
"""
92
Add an OpenID extension to this authentication request.
93
94
Parameters:
95
- extension_request: Extension request object (SRegRequest, FetchRequest, etc.)
96
"""
97
98
def addExtensionArg(self, namespace, key, value):
99
"""
100
Add an extension argument directly.
101
102
Parameters:
103
- namespace: str, extension namespace URI
104
- key: str, argument key
105
- value: str, argument value
106
"""
107
108
def getMessage(self, realm, return_to=None, immediate=False):
109
"""
110
Get the OpenID message for this request.
111
112
Parameters:
113
- realm: str, trust root/realm URL
114
- return_to: str, return URL after authentication
115
- immediate: bool, whether to use immediate mode
116
117
Returns:
118
Message object
119
"""
120
121
def redirectURL(self, realm, return_to=None, immediate=False):
122
"""
123
Get redirect URL for sending user to identity provider.
124
125
Parameters:
126
- realm: str, trust root/realm URL
127
- return_to: str, return URL after authentication
128
- immediate: bool, whether to use immediate mode
129
130
Returns:
131
str, redirect URL
132
"""
133
134
def formMarkup(self, realm, return_to=None, immediate=False, form_tag_attrs=None):
135
"""
136
Generate HTML form for POST-based authentication.
137
138
Parameters:
139
- realm: str, trust root/realm URL
140
- return_to: str, return URL after authentication
141
- immediate: bool, whether to use immediate mode
142
- form_tag_attrs: dict, additional HTML form attributes
143
144
Returns:
145
str, HTML form markup
146
"""
147
148
def htmlMarkup(self, realm, return_to=None, immediate=False, form_tag_attrs=None):
149
"""
150
Generate complete HTML page with auto-submitting form.
151
152
Parameters:
153
- realm: str, trust root/realm URL
154
- return_to: str, return URL after authentication
155
- immediate: bool, whether to use immediate mode
156
- form_tag_attrs: dict, additional HTML form attributes
157
158
Returns:
159
str, complete HTML page
160
"""
161
162
def shouldSendRedirect(self):
163
"""
164
Check if redirect should be used instead of POST form.
165
166
Returns:
167
bool, True if redirect is recommended
168
"""
169
```
170
171
### Response Handling
172
173
Process responses from identity providers with status checking and data extraction.
174
175
```python { .api }
176
class Response:
177
"""Base class for OpenID authentication responses."""
178
179
status = None
180
181
def setEndpoint(self, endpoint):
182
"""
183
Set the endpoint for this response.
184
185
Parameters:
186
- endpoint: OpenIDServiceEndpoint or None
187
"""
188
189
def getDisplayIdentifier(self):
190
"""
191
Return the display identifier for this response.
192
193
The display identifier is related to the Claimed Identifier, but the
194
two are not always identical. The display identifier is something the
195
user should recognize as what they entered, whereas the response's
196
claimed identifier may have extra information for better persistence.
197
198
Returns:
199
str or None, display identifier for user interface
200
"""
201
202
class SuccessResponse(Response):
203
"""Successful authentication response with status SUCCESS."""
204
205
def isOpenID1(self):
206
"""
207
Check if response uses OpenID 1.x protocol.
208
209
Returns:
210
bool, True if OpenID 1.x
211
"""
212
213
def isSigned(self, ns_uri, ns_key):
214
"""
215
Check if a specific field is signed in the response.
216
217
Parameters:
218
- ns_uri: str, namespace URI
219
- ns_key: str, field key
220
221
Returns:
222
bool, True if field is signed
223
"""
224
225
def getSigned(self, ns_uri, ns_key, default=None):
226
"""
227
Get a signed field value from the response.
228
229
Parameters:
230
- ns_uri: str, namespace URI
231
- ns_key: str, field key
232
- default: default value if field not found
233
234
Returns:
235
str or default, field value
236
"""
237
238
def getSignedNS(self, ns_uri):
239
"""
240
Get all signed fields in a namespace.
241
242
Parameters:
243
- ns_uri: str, namespace URI
244
245
Returns:
246
dict, signed fields in namespace
247
"""
248
249
def extensionResponse(self, namespace_uri, require_signed):
250
"""
251
Extract extension data from response.
252
253
Parameters:
254
- namespace_uri: str, extension namespace URI
255
- require_signed: bool, whether to require signed data
256
257
Returns:
258
dict, extension data
259
"""
260
261
def getReturnTo(self):
262
"""
263
Get the return_to URL from response.
264
265
Returns:
266
str, return_to URL
267
"""
268
269
class FailureResponse(Response):
270
"""Failed authentication response with status FAILURE."""
271
272
def __init__(self, endpoint, message=None, contact=None, reference=None):
273
"""
274
Initialize a failure response.
275
276
Parameters:
277
- endpoint: OpenIDServiceEndpoint or None
278
- message: str or None, failure reason message
279
- contact: str or None, contact information for support
280
- reference: str or None, reference identifier for this failure
281
"""
282
283
# Attributes:
284
# message: str or None - failure reason message
285
# contact: str or None - contact information for support
286
# reference: str or None - reference identifier for this failure
287
288
class CancelResponse(Response):
289
"""User-cancelled authentication response with status CANCEL."""
290
291
def __init__(self, endpoint):
292
"""
293
Initialize a cancel response.
294
295
Parameters:
296
- endpoint: OpenIDServiceEndpoint or None
297
"""
298
299
class SetupNeededResponse(Response):
300
"""Setup needed for immediate mode response with status SETUP_NEEDED."""
301
302
def __init__(self, endpoint, setup_url=None):
303
"""
304
Initialize a setup needed response.
305
306
Parameters:
307
- endpoint: OpenIDServiceEndpoint or None
308
- setup_url: str or None, URL for user setup (OpenID 1.x only)
309
"""
310
311
# Attributes:
312
# setup_url: str or None - URL that can be used to send the user to the
313
# server to set up for authentication. None in OpenID 2.0.
314
```
315
316
## Usage Examples
317
318
### Basic Consumer Implementation
319
320
```python
321
from openid.consumer import consumer
322
from openid.store.filestore import FileOpenIDStore
323
324
# Initialize consumer
325
store = FileOpenIDStore('/tmp/openid_store')
326
openid_consumer = consumer.Consumer({}, store)
327
328
# Start authentication
329
user_url = "https://example.com/user"
330
try:
331
auth_request = openid_consumer.begin(user_url)
332
redirect_url = auth_request.redirectURL(
333
realm="https://mysite.com",
334
return_to="https://mysite.com/openid/complete"
335
)
336
# Redirect user to redirect_url
337
except consumer.DiscoveryFailure as e:
338
print(f"Discovery failed: {e}")
339
```
340
341
### Complete Authentication Flow
342
343
```python
344
# Handle return from identity provider
345
def handle_openid_return(request):
346
query = dict(request.GET.items())
347
current_url = request.build_absolute_uri()
348
349
response = openid_consumer.complete(query, current_url)
350
351
if response.status == consumer.SUCCESS:
352
print(f"Success! Identity URL: {response.identity_url}")
353
print(f"Display identifier: {response.getDisplayIdentifier()}")
354
355
# Extract extension data if present
356
sreg_response = sreg.SRegResponse.fromSuccessResponse(response)
357
if sreg_response:
358
email = sreg_response.get('email')
359
nickname = sreg_response.get('nickname')
360
361
elif response.status == consumer.FAILURE:
362
print(f"Authentication failed: {response.message}")
363
elif response.status == consumer.CANCEL:
364
print("Authentication cancelled by user")
365
elif response.status == consumer.SETUP_NEEDED:
366
print(f"Setup needed at: {response.setup_url}")
367
```
368
369
### Using Extensions
370
371
```python
372
from openid.extensions import sreg
373
374
# Add SREG extension to request
375
auth_request = openid_consumer.begin(user_url)
376
sreg_request = sreg.SRegRequest(
377
required=['nickname', 'email'],
378
optional=['fullname'],
379
policy_url="https://mysite.com/privacy"
380
)
381
auth_request.addExtension(sreg_request)
382
383
redirect_url = auth_request.redirectURL(
384
realm="https://mysite.com",
385
return_to="https://mysite.com/openid/complete"
386
)
387
```
388
389
## Types
390
391
```python { .api }
392
# Response status constants
393
SUCCESS = 'success'
394
FAILURE = 'failure'
395
CANCEL = 'cancel'
396
SETUP_NEEDED = 'setup_needed'
397
398
# Exception types
399
class ProtocolError(ValueError):
400
"""
401
OpenID protocol violation exception.
402
403
Raised when a message violates the OpenID protocol specification.
404
This is caught internally and converted to FailureResponse objects.
405
"""
406
407
class DiscoveryFailure(Exception):
408
"""
409
Discovery process failed exception.
410
411
Raised when OpenID discovery fails for a given identifier URL.
412
This can happen due to network issues, invalid URLs, or missing
413
OpenID service information.
414
"""
415
416
class SetupNeededError(Exception):
417
"""
418
Setup needed in immediate mode exception.
419
420
Internally-used exception that indicates an immediate-mode request
421
was cancelled because user setup is required.
422
"""
423
424
def __init__(self, user_setup_url=None):
425
"""
426
Initialize setup needed error.
427
428
Parameters:
429
- user_setup_url: str or None, URL for user setup
430
"""
431
432
class TypeURIMismatch(ProtocolError):
433
"""
434
Type URI mismatch protocol error.
435
436
Raised when expected OpenID type URIs don't match discovered
437
service endpoint type URIs during verification.
438
"""
439
440
def __init__(self, expected, endpoint):
441
"""
442
Initialize type URI mismatch error.
443
444
Parameters:
445
- expected: str, expected type URI
446
- endpoint: OpenIDServiceEndpoint, discovered endpoint
447
"""
448
449
class ServerError(Exception):
450
"""
451
Server-side error in OpenID response.
452
453
Raised when the OpenID server returns a 400 response code
454
to a direct request, indicating a server-side error condition.
455
"""
456
457
def __init__(self, error_text, error_code, message):
458
"""
459
Initialize server error.
460
461
Parameters:
462
- error_text: str, error message text
463
- error_code: str or None, error code from server
464
- message: Message, full OpenID message containing error
465
"""
466
467
@classmethod
468
def fromMessage(cls, message):
469
"""
470
Generate ServerError from OpenID error message.
471
472
Parameters:
473
- message: Message, OpenID message containing error information
474
475
Returns:
476
ServerError instance
477
"""
478
```