0
# OAuth 2.0 Servers
1
2
Complete server-side OAuth 2.0 implementation providing authorization servers, resource servers, and token endpoints. Supports all standard grant types, token introspection, revocation, and comprehensive request validation.
3
4
## Capabilities
5
6
### Authorization Endpoint
7
8
OAuth 2.0 authorization endpoint handling authorization requests and user consent. Manages the authorization code flow by presenting authorization pages to users and issuing authorization codes.
9
10
```python { .api }
11
class AuthorizationEndpoint:
12
def __init__(self, default_response_type: str, default_token_type: str, response_types: dict[str, callable]): ...
13
14
def create_authorization_response(
15
self,
16
uri: str,
17
http_method: str = "GET",
18
body: str | None = None,
19
headers: dict[str, str] | None = None,
20
scopes: list[str] | None = None,
21
credentials: dict[str, str] | None = None,
22
) -> tuple[dict[str, str], str, int]:
23
"""
24
Create authorization response.
25
26
Parameters:
27
- uri: Authorization request URI
28
- http_method: HTTP method
29
- body: Request body
30
- headers: Request headers
31
- scopes: Requested scopes
32
- credentials: User credentials and consent info
33
34
Returns:
35
Tuple of (headers, body, status_code) for authorization response
36
"""
37
38
def validate_authorization_request(
39
self,
40
uri: str,
41
http_method: str = "GET",
42
body: str | None = None,
43
headers: dict[str, str] | None = None,
44
) -> None:
45
"""Validate authorization request parameters."""
46
```
47
48
### Token Endpoint
49
50
OAuth 2.0 token endpoint handling token requests for all grant types. Issues access tokens, refresh tokens, and manages token exchange operations.
51
52
```python { .api }
53
class TokenEndpoint:
54
def __init__(
55
self,
56
default_grant_type=None,
57
default_token_type=None,
58
token_generator=None,
59
refresh_token_generator=None,
60
expires_in=None,
61
): ...
62
63
def create_token_response(
64
self,
65
uri: str,
66
http_method: str = "POST",
67
body: str | None = None,
68
headers: dict[str, str] | None = None,
69
credentials: dict[str, str] | None = None,
70
grant_type_handler=None,
71
**kwargs,
72
) -> tuple[dict[str, str], str, int]:
73
"""
74
Create token response for any grant type.
75
76
Parameters:
77
- uri: Token request URI
78
- http_method: HTTP method
79
- body: Request body
80
- headers: Request headers
81
- credentials: Client credentials
82
- grant_type_handler: Custom grant type handler
83
84
Returns:
85
Tuple of (headers, body, status_code) for token response
86
"""
87
88
def validate_token_request(self, request) -> None:
89
"""Validate token request parameters."""
90
```
91
92
### Resource Endpoint
93
94
OAuth 2.0 resource endpoint for validating access tokens when accessing protected resources. Verifies token validity, scope, and expiration.
95
96
```python { .api }
97
class ResourceEndpoint:
98
def __init__(self, default_token=None, token_generator=None, expires_in=None): ...
99
100
def validate_protected_resource_request(
101
self,
102
uri: str,
103
http_method: str = "GET",
104
body: str | None = None,
105
headers: dict[str, str] | None = None,
106
scopes: list[str] | None = None,
107
) -> tuple[bool, dict]:
108
"""
109
Validate protected resource request.
110
111
Parameters:
112
- uri: Resource request URI
113
- http_method: HTTP method
114
- body: Request body
115
- headers: Request headers
116
- scopes: Required scopes
117
118
Returns:
119
Tuple of (valid, request) where valid indicates if token is valid
120
"""
121
```
122
123
### Revocation Endpoint
124
125
OAuth 2.0 token revocation endpoint (RFC 7009) for invalidating access and refresh tokens. Allows clients to revoke tokens when they're no longer needed.
126
127
```python { .api }
128
class RevocationEndpoint:
129
def __init__(self, request_validator, supported_token_types=None, enable_jsonp=False): ...
130
131
def create_revocation_response(
132
self,
133
uri: str,
134
http_method: str = "POST",
135
body: str | None = None,
136
headers: dict[str, str] | None = None,
137
) -> tuple[dict[str, str], str, int]:
138
"""
139
Create token revocation response.
140
141
Parameters:
142
- uri: Revocation request URI
143
- http_method: HTTP method
144
- body: Request body containing token to revoke
145
- headers: Request headers
146
147
Returns:
148
Tuple of (headers, body, status_code) for revocation response
149
"""
150
151
def validate_revocation_request(self, request) -> None:
152
"""Validate token revocation request."""
153
```
154
155
### Introspection Endpoint
156
157
OAuth 2.0 token introspection endpoint (RFC 7662) for checking token status and metadata. Allows resource servers to query token information.
158
159
```python { .api }
160
class IntrospectEndpoint:
161
def __init__(self, request_validator, supported_token_types=None): ...
162
163
def create_introspect_response(
164
self,
165
uri: str,
166
http_method: str = "POST",
167
body: str | None = None,
168
headers: dict[str, str] | None = None,
169
) -> tuple[dict[str, str], str, int]:
170
"""
171
Create token introspection response.
172
173
Parameters:
174
- uri: Introspection request URI
175
- http_method: HTTP method
176
- body: Request body containing token to introspect
177
- headers: Request headers
178
179
Returns:
180
Tuple of (headers, body, status_code) with token metadata
181
"""
182
183
def validate_introspect_request(self, request) -> None:
184
"""Validate token introspection request."""
185
```
186
187
### Metadata Endpoint
188
189
OAuth 2.0 authorization server metadata endpoint (RFC 8414) for publishing server capabilities and configuration. Enables automatic client configuration.
190
191
```python { .api }
192
class MetadataEndpoint:
193
def __init__(self, endpoints, claims=None, **kwargs): ...
194
195
def create_metadata_response(
196
self,
197
uri: str,
198
http_method: str = "GET",
199
body: str | None = None,
200
headers: dict[str, str] | None = None,
201
) -> tuple[dict[str, str], str, int]:
202
"""
203
Create authorization server metadata response.
204
205
Returns:
206
Tuple of (headers, body, status_code) with server metadata JSON
207
"""
208
```
209
210
### Pre-configured Servers
211
212
Complete OAuth 2.0 server implementations combining multiple endpoints for common deployment scenarios.
213
214
#### Web Application Server
215
216
```python { .api }
217
class WebApplicationServer:
218
def __init__(
219
self,
220
request_validator,
221
token_expires_in=None,
222
token_generator=None,
223
refresh_token_generator=None,
224
**kwargs,
225
):
226
"""
227
Complete OAuth 2.0 server for web applications.
228
229
Combines AuthorizationEndpoint, TokenEndpoint, and ResourceEndpoint
230
to support the authorization code grant flow.
231
"""
232
233
# Inherits methods from AuthorizationEndpoint, TokenEndpoint, ResourceEndPoint
234
def create_authorization_response(self, uri, http_method="GET", body=None, headers=None, scopes=None, credentials=None): ...
235
def create_token_response(self, uri, http_method="POST", body=None, headers=None, credentials=None, **kwargs): ...
236
def validate_protected_resource_request(self, uri, http_method="GET", body=None, headers=None, scopes=None): ...
237
```
238
239
#### Mobile Application Server
240
241
```python { .api }
242
class MobileApplicationServer:
243
def __init__(
244
self,
245
request_validator,
246
token_expires_in=None,
247
token_generator=None,
248
**kwargs,
249
):
250
"""
251
OAuth 2.0 server for mobile applications.
252
253
Supports the implicit grant flow for public clients
254
that cannot securely store credentials.
255
"""
256
```
257
258
#### Legacy Application Server
259
260
```python { .api }
261
class LegacyApplicationServer:
262
def __init__(
263
self,
264
request_validator,
265
token_expires_in=None,
266
token_generator=None,
267
refresh_token_generator=None,
268
**kwargs,
269
):
270
"""
271
OAuth 2.0 server for legacy applications.
272
273
Supports the password credentials grant flow for
274
trusted first-party applications.
275
"""
276
```
277
278
#### Backend Application Server
279
280
```python { .api }
281
class BackendApplicationServer:
282
def __init__(
283
self,
284
request_validator,
285
token_expires_in=None,
286
token_generator=None,
287
**kwargs,
288
):
289
"""
290
OAuth 2.0 server for backend applications.
291
292
Supports the client credentials grant flow for
293
machine-to-machine authentication.
294
"""
295
```
296
297
#### Base Server
298
299
```python { .api }
300
class Server:
301
def __init__(
302
self,
303
request_validator,
304
token_expires_in=None,
305
token_generator=None,
306
refresh_token_generator=None,
307
**kwargs,
308
):
309
"""
310
Base OAuth 2.0 server supporting all grant types.
311
312
Provides a flexible foundation for custom server implementations
313
with support for authorization code, implicit, password credentials,
314
and client credentials grants.
315
"""
316
```
317
318
## Usage Examples
319
320
### Authorization Code Flow Server
321
322
```python
323
from oauthlib.oauth2 import WebApplicationServer, RequestValidator
324
from oauthlib.common import generate_token
325
326
class MyRequestValidator(RequestValidator):
327
def validate_client_id(self, client_id, request, *args, **kwargs):
328
# Check if client_id exists in your database
329
return client_id in ['your-client-id', 'another-client']
330
331
def authenticate_client(self, request, *args, **kwargs):
332
# Authenticate client credentials
333
client_id = getattr(request, 'client_id', None)
334
client_secret = getattr(request, 'client_secret', None)
335
return verify_client_credentials(client_id, client_secret)
336
337
def validate_redirect_uri(self, client_id, redirect_uri, request, *args, **kwargs):
338
# Validate redirect URI is registered for this client
339
return redirect_uri in get_registered_redirect_uris(client_id)
340
341
def get_default_scopes(self, client_id, request, *args, **kwargs):
342
# Return default scopes for client
343
return ['read']
344
345
def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs):
346
# Validate requested scopes
347
allowed_scopes = get_client_scopes(client_id)
348
return all(scope in allowed_scopes for scope in scopes)
349
350
def save_authorization_code(self, client_id, code, request, *args, **kwargs):
351
# Store authorization code in database
352
store_authorization_code(client_id, code, request)
353
354
def validate_code(self, client_id, code, client, request, *args, **kwargs):
355
# Validate authorization code
356
return is_valid_authorization_code(client_id, code)
357
358
def confirm_redirect_uri(self, client_id, code, redirect_uri, client, request, *args, **kwargs):
359
# Confirm redirect URI matches original request
360
return get_code_redirect_uri(code) == redirect_uri
361
362
def save_token(self, token, request, *args, **kwargs):
363
# Store access token in database
364
store_access_token(token, request)
365
366
def validate_bearer_token(self, token, scopes, request):
367
# Validate bearer token and scopes
368
return is_valid_bearer_token(token, scopes)
369
370
def get_default_redirect_uri(self, client_id, request, *args, **kwargs):
371
# Return default redirect URI for client
372
return get_client_default_redirect_uri(client_id)
373
374
# Create server
375
validator = MyRequestValidator()
376
server = WebApplicationServer(validator)
377
378
# Handle authorization request
379
def handle_authorization(request):
380
try:
381
# Extract request details
382
uri = request.url
383
http_method = request.method
384
body = request.body
385
headers = dict(request.headers)
386
387
# Check if user is authenticated and consented
388
if not user_authenticated(request):
389
return redirect_to_login()
390
391
if not user_consented(request):
392
return show_consent_form()
393
394
# Create authorization response
395
headers, body, status = server.create_authorization_response(
396
uri, http_method, body, headers,
397
scopes=request.args.get('scope', '').split(),
398
credentials={'user_id': get_user_id(request)}
399
)
400
401
return Response(body, status=status, headers=headers)
402
403
except OAuth2Error as e:
404
return Response(e.json, status=e.status_code,
405
headers={'Content-Type': 'application/json'})
406
407
# Handle token request
408
def handle_token(request):
409
try:
410
uri = request.url
411
http_method = request.method
412
body = request.body
413
headers = dict(request.headers)
414
415
headers, body, status = server.create_token_response(
416
uri, http_method, body, headers
417
)
418
419
return Response(body, status=status, headers=headers)
420
421
except OAuth2Error as e:
422
return Response(e.json, status=e.status_code,
423
headers={'Content-Type': 'application/json'})
424
```
425
426
### Protected Resource Validation
427
428
```python
429
from oauthlib.oauth2 import ResourceEndpoint
430
from functools import wraps
431
432
# Create resource endpoint
433
resource_endpoint = ResourceEndpoint()
434
435
def require_oauth(*required_scopes):
436
"""Decorator to protect API endpoints with OAuth."""
437
def decorator(f):
438
@wraps(f)
439
def decorated_function(*args, **kwargs):
440
# Extract request details
441
uri = request.url
442
http_method = request.method
443
body = request.body
444
headers = dict(request.headers)
445
446
try:
447
# Validate token and scopes
448
valid, oauth_request = resource_endpoint.validate_protected_resource_request(
449
uri, http_method, body, headers, required_scopes
450
)
451
452
if not valid:
453
return Response('Unauthorized', status=401)
454
455
# Add OAuth info to request context
456
request.oauth = oauth_request
457
458
return f(*args, **kwargs)
459
460
except OAuth2Error as e:
461
return Response(e.json, status=e.status_code,
462
headers={'Content-Type': 'application/json'})
463
464
return decorated_function
465
return decorator
466
467
# Usage in API endpoints
468
@app.route('/api/user/profile')
469
@require_oauth('profile:read')
470
def get_user_profile():
471
user_id = request.oauth.user_id
472
return jsonify(get_user_data(user_id))
473
474
@app.route('/api/user/settings', methods=['POST'])
475
@require_oauth('profile:write')
476
def update_user_settings():
477
user_id = request.oauth.user_id
478
update_user_data(user_id, request.json)
479
return jsonify({'status': 'updated'})
480
```
481
482
### Token Introspection
483
484
```python
485
from oauthlib.oauth2 import IntrospectEndpoint
486
487
# Create introspection endpoint
488
introspect_endpoint = IntrospectEndpoint(validator)
489
490
def handle_introspect(request):
491
"""Handle token introspection requests from resource servers."""
492
try:
493
uri = request.url
494
http_method = request.method
495
body = request.body
496
headers = dict(request.headers)
497
498
headers, body, status = introspect_endpoint.create_introspect_response(
499
uri, http_method, body, headers
500
)
501
502
return Response(body, status=status, headers=headers)
503
504
except OAuth2Error as e:
505
return Response(e.json, status=e.status_code,
506
headers={'Content-Type': 'application/json'})
507
```
508
509
### Authorization Server Metadata
510
511
```python
512
from oauthlib.oauth2 import MetadataEndpoint
513
514
# Create metadata endpoint
515
metadata = MetadataEndpoint([
516
('authorization_endpoint', 'https://auth.example.com/authorize'),
517
('token_endpoint', 'https://auth.example.com/token'),
518
('revocation_endpoint', 'https://auth.example.com/revoke'),
519
('introspection_endpoint', 'https://auth.example.com/introspect'),
520
], claims=[
521
('issuer', 'https://auth.example.com'),
522
('response_types_supported', ['code', 'token']),
523
('grant_types_supported', ['authorization_code', 'implicit', 'client_credentials']),
524
('token_endpoint_auth_methods_supported', ['client_secret_basic', 'client_secret_post']),
525
('scopes_supported', ['read', 'write', 'admin']),
526
])
527
528
def handle_metadata(request):
529
"""Serve authorization server metadata."""
530
headers, body, status = metadata.create_metadata_response(
531
request.url, request.method
532
)
533
return Response(body, status=status, headers=headers)
534
```
535
536
## Server Configuration
537
538
### Token Expiration
539
540
```python
541
# Configure token expiration times
542
server = WebApplicationServer(
543
validator,
544
token_expires_in=3600, # Access tokens expire in 1 hour
545
)
546
547
# Or use a function for dynamic expiration
548
def token_expires_in(request):
549
if 'long_lived' in request.scopes:
550
return 86400 # 24 hours for long-lived tokens
551
return 3600 # 1 hour for regular tokens
552
553
server = WebApplicationServer(validator, token_expires_in=token_expires_in)
554
```
555
556
### Custom Token Generators
557
558
```python
559
from oauthlib.common import generate_token
560
import jwt
561
562
def custom_token_generator(request):
563
"""Generate JWT access tokens."""
564
payload = {
565
'user_id': request.user_id,
566
'client_id': request.client_id,
567
'scopes': request.scopes,
568
'exp': datetime.utcnow() + timedelta(hours=1)
569
}
570
return jwt.encode(payload, 'secret-key', algorithm='HS256')
571
572
server = WebApplicationServer(
573
validator,
574
token_generator=custom_token_generator,
575
refresh_token_generator=generate_token
576
)
577
```