0
# OAuth 1.0 Implementation
1
2
Complete OAuth 1.0 implementation following RFC 5849 with support for all signature methods (HMAC-SHA1, RSA-SHA1, PLAINTEXT) and signature types (header, query, body). Provides both client and server implementations with comprehensive support for temporary credentials and token credentials.
3
4
## Capabilities
5
6
### OAuth 1.0 Client
7
8
High-level OAuth 1.0 client implementation for performing the complete authorization flow with automatic signature generation and request signing.
9
10
```python { .api }
11
class OAuth1Client:
12
"""OAuth 1.0 client implementation."""
13
14
def __init__(self, client_key: str, client_secret: str = None, token: str = None, token_secret: str = None, redirect_uri: str = None, rsa_key=None, verifier: str = None, signature_method: str = 'HMAC-SHA1', signature_type: str = 'AUTH_HEADER', force_include_body: bool = False, **kwargs) -> None:
15
"""
16
Initialize OAuth 1.0 client.
17
18
Args:
19
client_key: Client identifier
20
client_secret: Client secret (not needed for RSA-SHA1)
21
token: OAuth token
22
token_secret: OAuth token secret
23
redirect_uri: Callback URI for authorization
24
rsa_key: RSA private key for RSA-SHA1 signature method
25
verifier: OAuth verifier from authorization callback
26
signature_method: Signature method (HMAC-SHA1, RSA-SHA1, PLAINTEXT)
27
signature_type: Where to include signature (AUTH_HEADER, QUERY, BODY)
28
force_include_body: Whether to always include body in signature
29
"""
30
31
def fetch_request_token(self, uri: str, realm: str = None) -> dict:
32
"""
33
Fetch temporary credentials (request token).
34
35
Args:
36
uri: Request token endpoint URI
37
realm: Optional authorization realm
38
39
Returns:
40
Dictionary containing oauth_token and oauth_token_secret
41
"""
42
43
def create_authorization_url(self, uri: str, **request_kwargs) -> str:
44
"""
45
Create authorization URL for user to visit.
46
47
Args:
48
uri: Authorization endpoint URI
49
**request_kwargs: Additional parameters for authorization
50
51
Returns:
52
Authorization URL with embedded token
53
"""
54
55
def fetch_access_token(self, uri: str, verifier: str = None) -> dict:
56
"""
57
Exchange authorization verifier for access token.
58
59
Args:
60
uri: Access token endpoint URI
61
verifier: OAuth verifier from authorization callback
62
63
Returns:
64
Dictionary containing oauth_token and oauth_token_secret
65
"""
66
67
def get_request_token_authorization_url(self, url: str, **request_kwargs) -> str:
68
"""Get authorization URL (alias for create_authorization_url)."""
69
70
def parse_authorization_response(self, url: str) -> dict:
71
"""
72
Parse authorization callback response.
73
74
Args:
75
url: Callback URL with parameters
76
77
Returns:
78
Dictionary with parsed parameters
79
"""
80
```
81
82
### OAuth 1.0 Server Components
83
84
Server-side components for implementing OAuth 1.0 authorization and resource servers.
85
86
```python { .api }
87
class AuthorizationServer:
88
"""OAuth 1.0 authorization server."""
89
90
def __init__(self, query_client: callable, query_token: callable, save_request_token: callable, save_verifier: callable, save_access_token: callable) -> None:
91
"""
92
Initialize authorization server.
93
94
Args:
95
query_client: Function to query client by client_key
96
query_token: Function to query token by token value
97
save_request_token: Function to save temporary credentials
98
save_verifier: Function to save authorization verifier
99
save_access_token: Function to save access token
100
"""
101
102
def create_request_token_response(self, uri: str, http_method: str = 'POST', body: str = None, headers: dict = None) -> tuple:
103
"""
104
Create response for request token endpoint.
105
106
Args:
107
uri: Request URI
108
http_method: HTTP method
109
body: Request body
110
headers: Request headers
111
112
Returns:
113
Tuple of (headers, body, status_code)
114
"""
115
116
def create_authorization_response(self, uri: str, http_method: str = 'GET', body: str = None, headers: dict = None, credentials: dict = None) -> tuple:
117
"""
118
Create response for authorization endpoint.
119
120
Args:
121
uri: Request URI
122
http_method: HTTP method
123
body: Request body
124
headers: Request headers
125
credentials: User credentials dictionary
126
127
Returns:
128
Tuple of (headers, body, status_code)
129
"""
130
131
def create_access_token_response(self, uri: str, http_method: str = 'POST', body: str = None, headers: dict = None, credentials: dict = None) -> tuple:
132
"""
133
Create response for access token endpoint.
134
135
Args:
136
uri: Request URI
137
http_method: HTTP method
138
body: Request body
139
headers: Request headers
140
credentials: Optional user credentials
141
142
Returns:
143
Tuple of (headers, body, status_code)
144
"""
145
146
def validate_request_token_request(self, request: OAuth1Request) -> None:
147
"""Validate request token request."""
148
149
def validate_authorization_request(self, request: OAuth1Request) -> None:
150
"""Validate authorization request."""
151
152
def validate_access_token_request(self, request: OAuth1Request) -> None:
153
"""Validate access token request."""
154
155
class ResourceProtector:
156
"""OAuth 1.0 resource server protection."""
157
158
def __init__(self, query_client: callable, query_token: callable) -> None:
159
"""
160
Initialize resource protector.
161
162
Args:
163
query_client: Function to query client by client_key
164
query_token: Function to query token by token value
165
"""
166
167
def validate_request(self, uri: str, http_method: str, body: str = None, headers: dict = None) -> OAuth1Request:
168
"""
169
Validate OAuth 1.0 signed request.
170
171
Args:
172
uri: Request URI
173
http_method: HTTP method
174
body: Request body
175
headers: Request headers
176
177
Returns:
178
Validated OAuth1Request object
179
"""
180
```
181
182
### Request Wrapper
183
184
OAuth 1.0 request representation with signature validation capabilities.
185
186
```python { .api }
187
class OAuth1Request:
188
"""OAuth 1.0 request wrapper."""
189
190
def __init__(self, uri: str, http_method: str = 'GET', body: str = None, headers: dict = None) -> None:
191
"""
192
Initialize OAuth 1.0 request.
193
194
Args:
195
uri: Request URI
196
http_method: HTTP method
197
body: Request body
198
headers: Request headers
199
"""
200
201
@property
202
def client_key(self) -> str:
203
"""Get client key from request."""
204
205
@property
206
def signature(self) -> str:
207
"""Get signature from request."""
208
209
@property
210
def signature_method(self) -> str:
211
"""Get signature method from request."""
212
213
@property
214
def token(self) -> str:
215
"""Get token from request."""
216
217
def validate_timestamp_and_nonce(self, timestamp_lifetime: int = 600) -> None:
218
"""
219
Validate timestamp and nonce.
220
221
Args:
222
timestamp_lifetime: Maximum age of timestamp in seconds
223
"""
224
225
def validate_signature(self, client_secret: str, token_secret: str = '', rsa_key=None) -> None:
226
"""
227
Validate request signature.
228
229
Args:
230
client_secret: Client secret
231
token_secret: Token secret
232
rsa_key: RSA public key for RSA-SHA1 verification
233
"""
234
```
235
236
### Client Authentication
237
238
OAuth 1.0 client authentication for use with HTTP libraries.
239
240
```python { .api }
241
class ClientAuth:
242
"""OAuth 1.0 client authentication."""
243
244
def __init__(self, client_key: str, client_secret: str = None, token: str = None, token_secret: str = None, signature_method: str = 'HMAC-SHA1', signature_type: str = 'AUTH_HEADER', rsa_key=None, verifier: str = None, **kwargs) -> None:
245
"""
246
Initialize client authentication.
247
248
Args:
249
client_key: Client identifier
250
client_secret: Client secret
251
token: OAuth token
252
token_secret: OAuth token secret
253
signature_method: Signature method
254
signature_type: Signature type
255
rsa_key: RSA private key
256
verifier: OAuth verifier
257
"""
258
259
def __call__(self, request) -> object:
260
"""
261
Apply OAuth 1.0 signature to request.
262
263
Args:
264
request: HTTP request object
265
266
Returns:
267
Modified request with OAuth signature
268
"""
269
```
270
271
### Model Mixins
272
273
Mixins for database models to store OAuth 1.0 credentials.
274
275
```python { .api }
276
class ClientMixin:
277
"""Mixin for OAuth 1.0 client model."""
278
279
client_key: str # Client identifier
280
client_secret: str # Client secret (may be None for RSA-SHA1)
281
default_redirect_uri: str # Default callback URI
282
default_realms: list # Default authorization realms
283
284
def get_default_redirect_uri(self) -> str:
285
"""Get default redirect URI for this client."""
286
287
def get_default_realms(self) -> list:
288
"""Get default realms for this client."""
289
290
def validate_redirect_uri(self, redirect_uri: str) -> bool:
291
"""Validate if redirect URI is allowed for this client."""
292
293
class TemporaryCredentialMixin:
294
"""Mixin for temporary credential (request token) model."""
295
296
client_key: str # Client identifier
297
oauth_token: str # Temporary token
298
oauth_token_secret: str # Temporary token secret
299
oauth_callback: str # Callback URI
300
oauth_verifier: str # Authorization verifier
301
302
def get_redirect_uri(self) -> str:
303
"""Get callback URI for this temporary credential."""
304
305
def get_oauth_verifier(self) -> str:
306
"""Get OAuth verifier for this temporary credential."""
307
308
class TokenCredentialMixin:
309
"""Mixin for token credential (access token) model."""
310
311
client_key: str # Client identifier
312
oauth_token: str # Access token
313
oauth_token_secret: str # Access token secret
314
user_id: str # User identifier
315
316
def get_user_id(self) -> str:
317
"""Get user ID associated with this token."""
318
319
class TemporaryCredential:
320
"""Temporary credential representation."""
321
322
def __init__(self, client_key: str, oauth_token: str, oauth_token_secret: str, oauth_callback: str = None) -> None:
323
"""
324
Initialize temporary credential.
325
326
Args:
327
client_key: Client identifier
328
oauth_token: Temporary token
329
oauth_token_secret: Temporary token secret
330
oauth_callback: Callback URI
331
"""
332
```
333
334
### Constants
335
336
OAuth 1.0 signature methods and types.
337
338
```python { .api }
339
# Signature Methods
340
SIGNATURE_HMAC_SHA1: str = 'HMAC-SHA1'
341
SIGNATURE_RSA_SHA1: str = 'RSA-SHA1'
342
SIGNATURE_PLAINTEXT: str = 'PLAINTEXT'
343
344
# Signature Types
345
SIGNATURE_TYPE_HEADER: str = 'AUTH_HEADER'
346
SIGNATURE_TYPE_QUERY: str = 'QUERY'
347
SIGNATURE_TYPE_BODY: str = 'BODY'
348
```
349
350
## Usage Examples
351
352
### Client Flow
353
354
```python
355
from authlib.oauth1 import OAuth1Client
356
357
# Step 1: Initialize client
358
client = OAuth1Client(
359
client_key='your-client-key',
360
client_secret='your-client-secret',
361
signature_method='HMAC-SHA1'
362
)
363
364
# Step 2: Get request token
365
request_token = client.fetch_request_token('https://provider.com/oauth/request_token')
366
print(f"Request token: {request_token['oauth_token']}")
367
368
# Step 3: Get authorization URL
369
client.token = request_token['oauth_token']
370
client.token_secret = request_token['oauth_token_secret']
371
auth_url = client.create_authorization_url('https://provider.com/oauth/authorize')
372
print(f"Visit: {auth_url}")
373
374
# Step 4: After user authorization, exchange for access token
375
client.verifier = 'verifier-from-callback'
376
access_token = client.fetch_access_token('https://provider.com/oauth/access_token')
377
print(f"Access token: {access_token['oauth_token']}")
378
379
# Step 5: Make authenticated requests
380
client.token = access_token['oauth_token']
381
client.token_secret = access_token['oauth_token_secret']
382
# Use client with requests library or make manual signed requests
383
```
384
385
### Server Implementation
386
387
```python
388
from authlib.oauth1 import AuthorizationServer, ResourceProtector
389
390
# Define callback functions
391
def query_client(client_key):
392
# Return client object or None
393
return get_client_by_key(client_key)
394
395
def query_token(token):
396
# Return token object or None
397
return get_token_by_value(token)
398
399
def save_request_token(token, request):
400
# Save temporary credential
401
store_request_token(token)
402
403
def save_verifier(token, verifier, request):
404
# Save authorization verifier
405
update_token_verifier(token, verifier)
406
407
def save_access_token(token, request):
408
# Save access token
409
store_access_token(token)
410
411
# Create authorization server
412
authorization_server = AuthorizationServer(
413
query_client=query_client,
414
query_token=query_token,
415
save_request_token=save_request_token,
416
save_verifier=save_verifier,
417
save_access_token=save_access_token
418
)
419
420
# Handle request token endpoint
421
headers, body, status = authorization_server.create_request_token_response(
422
uri='/oauth/request_token',
423
http_method='POST',
424
headers=request.headers
425
)
426
427
# Handle authorization endpoint
428
headers, body, status = authorization_server.create_authorization_response(
429
uri='/oauth/authorize',
430
http_method='GET',
431
credentials={'user_id': current_user.id}
432
)
433
434
# Handle access token endpoint
435
headers, body, status = authorization_server.create_access_token_response(
436
uri='/oauth/access_token',
437
http_method='POST',
438
headers=request.headers
439
)
440
```
441
442
### Resource Protection
443
444
```python
445
from authlib.oauth1 import ResourceProtector
446
447
# Create resource protector
448
resource_protector = ResourceProtector(
449
query_client=query_client,
450
query_token=query_token
451
)
452
453
# Protect API endpoints
454
def protected_resource():
455
try:
456
# Validate OAuth 1.0 request
457
oauth_request = resource_protector.validate_request(
458
uri=request.url,
459
http_method=request.method,
460
body=request.get_data(),
461
headers=request.headers
462
)
463
464
# Access token is valid, process request
465
token = oauth_request.token
466
return f"Hello, token: {token}"
467
468
except OAuth1Error as error:
469
return {'error': error.error}, 401
470
```