0
# Authentication Support
1
2
HTTP authentication mechanisms including Basic Auth with integration into the Agent architecture for secure credential handling. treq provides both high-level parameter support and low-level agent wrapping for authentication.
3
4
## Capabilities
5
6
### Basic Authentication Agent
7
8
Creates an agent wrapper that automatically adds HTTP Basic Authentication headers to all requests.
9
10
```python { .api }
11
def add_basic_auth(agent, username, password):
12
"""
13
Add HTTP Basic Authentication to an agent.
14
15
Creates a wrapper agent that automatically includes Basic Auth
16
headers for all requests made through it.
17
18
Parameters:
19
- agent: IAgent - Twisted agent to wrap
20
- username: str or bytes - Username for authentication
21
- password: str or bytes - Password for authentication
22
23
Returns:
24
IAgent - Wrapped agent with Basic Auth support
25
"""
26
```
27
28
### Generic Authentication Configuration
29
30
Adds authentication to an agent based on configuration tuple, currently supporting HTTP Basic Auth.
31
32
```python { .api }
33
def add_auth(agent, auth_config):
34
"""
35
Add authentication to an agent based on configuration.
36
37
Currently supports HTTP Basic Authentication via tuple format.
38
39
Parameters:
40
- agent: IAgent - Twisted agent to wrap
41
- auth_config: tuple - Authentication configuration (username, password)
42
43
Returns:
44
IAgent - Agent with authentication configured
45
46
Raises:
47
UnknownAuthConfig - If auth_config format is not recognized
48
"""
49
```
50
51
### Request Header Setting Agent
52
53
Internal utility class for wrapping agents to set custom headers on all requests.
54
55
```python { .api }
56
class _RequestHeaderSetterAgent:
57
"""
58
Wrap an agent to set request headers on all requests.
59
60
This is used internally by authentication functions but can be
61
used directly for custom header requirements.
62
"""
63
64
def __init__(self, agent, headers):
65
"""
66
Initialize header-setting agent wrapper.
67
68
Parameters:
69
- agent: IAgent - Agent to wrap
70
- headers: Headers - Headers to add to each request
71
"""
72
73
def request(self, method, uri, headers=None, bodyProducer=None):
74
"""
75
Make request with automatic header injection.
76
77
Merges the configured headers with any headers provided
78
in the request, with request headers taking precedence.
79
"""
80
```
81
82
### Authentication Exceptions
83
84
```python { .api }
85
class UnknownAuthConfig(Exception):
86
"""
87
Exception raised when authentication config cannot be interpreted.
88
89
Raised by add_auth() when the auth_config parameter is not
90
in a recognized format.
91
"""
92
```
93
94
## Usage Examples
95
96
### Basic Authentication with Request Parameters
97
98
The simplest way to use authentication is through the `auth` parameter:
99
100
```python
101
import treq
102
from twisted.internet import defer
103
104
@defer.inlineCallbacks
105
def basic_auth_requests():
106
# Using auth parameter (recommended for simple cases)
107
response = yield treq.get(
108
'https://httpbin.org/basic-auth/user/pass',
109
auth=('user', 'pass')
110
)
111
112
# Verify authentication worked
113
data = yield response.json()
114
print("Authenticated user:", data['user'])
115
116
# POST with authentication
117
response = yield treq.post(
118
'https://httpbin.org/basic-auth/api/key',
119
auth=('api', 'key'),
120
json={'data': 'sensitive information'}
121
)
122
```
123
124
### Custom Agent with Authentication
125
126
For applications needing persistent authentication across many requests:
127
128
```python
129
from twisted.web.client import Agent
130
from treq.auth import add_basic_auth
131
from treq.client import HTTPClient
132
from twisted.internet import reactor
133
134
@defer.inlineCallbacks
135
def persistent_auth():
136
# Create base agent
137
base_agent = Agent(reactor)
138
139
# Wrap with authentication
140
auth_agent = add_basic_auth(base_agent, 'username', 'password')
141
142
# Create client using authenticated agent
143
client = HTTPClient(auth_agent)
144
145
# All requests through this client will be authenticated
146
response1 = yield client.get('https://api.example.com/profile')
147
response2 = yield client.post('https://api.example.com/data', json={'key': 'value'})
148
response3 = yield client.put('https://api.example.com/resource/123')
149
150
# No need to specify auth for each request
151
```
152
153
### Multiple Authentication Schemes
154
155
Handling different authentication requirements:
156
157
```python
158
from treq.auth import add_basic_auth, add_auth
159
from twisted.web.client import Agent
160
161
@defer.inlineCallbacks
162
def multiple_auth_schemes():
163
base_agent = Agent(reactor)
164
165
# API with Basic Auth
166
api_agent = add_basic_auth(base_agent, 'api_user', 'api_key')
167
api_client = HTTPClient(api_agent)
168
169
# Admin interface with different credentials
170
admin_agent = add_auth(base_agent, ('admin', 'admin_password'))
171
admin_client = HTTPClient(admin_agent)
172
173
# Use appropriate client for each service
174
api_data = yield api_client.get('https://api.service.com/data')
175
admin_data = yield admin_client.get('https://admin.service.com/users')
176
```
177
178
### Custom Header Authentication
179
180
For APIs using custom authentication headers:
181
182
```python
183
from treq.auth import _RequestHeaderSetterAgent
184
from twisted.web.http_headers import Headers
185
from twisted.web.client import Agent
186
187
@defer.inlineCallbacks
188
def custom_header_auth():
189
# Create headers for API key authentication
190
auth_headers = Headers({
191
'Authorization': ['Bearer your-api-token'],
192
'X-API-Key': ['your-api-key']
193
})
194
195
# Wrap agent with custom headers
196
base_agent = Agent(reactor)
197
auth_agent = _RequestHeaderSetterAgent(base_agent, auth_headers)
198
199
# Create client
200
client = HTTPClient(auth_agent)
201
202
# All requests include authentication headers
203
response = yield client.get('https://api.example.com/protected-resource')
204
```
205
206
### Error Handling
207
208
```python
209
from treq.auth import UnknownAuthConfig
210
211
@defer.inlineCallbacks
212
def handle_auth_errors():
213
try:
214
# This will raise UnknownAuthConfig
215
agent = add_auth(base_agent, "invalid-config")
216
except UnknownAuthConfig as e:
217
print(f"Authentication configuration error: {e}")
218
# Fall back to no authentication or different config
219
agent = base_agent
220
221
# Handle authentication failures
222
try:
223
response = yield treq.get(
224
'https://httpbin.org/basic-auth/user/pass',
225
auth=('wrong', 'credentials')
226
)
227
if response.code == 401:
228
print("Authentication failed - invalid credentials")
229
elif response.code == 403:
230
print("Authentication succeeded but access forbidden")
231
except Exception as e:
232
print(f"Request failed: {e}")
233
```
234
235
### Session-Based Authentication
236
237
Combining authentication with cookie-based sessions:
238
239
```python
240
from http.cookiejar import CookieJar
241
242
@defer.inlineCallbacks
243
def session_auth():
244
# Client with cookie support
245
cookiejar = CookieJar()
246
client = HTTPClient(Agent(reactor), cookiejar=cookiejar)
247
248
# Login with credentials
249
login_response = yield client.post(
250
'https://example.com/login',
251
data={'username': 'user', 'password': 'pass'}
252
)
253
254
if login_response.code == 200:
255
# Session cookie automatically stored
256
print("Login successful")
257
258
# Subsequent requests use session cookie
259
profile = yield client.get('https://example.com/profile')
260
data = yield profile.json()
261
262
# Logout
263
yield client.post('https://example.com/logout')
264
else:
265
print("Login failed")
266
```
267
268
### Advanced Authentication Patterns
269
270
```python
271
@defer.inlineCallbacks
272
def advanced_auth_patterns():
273
# Token refresh pattern
274
class TokenRefreshAgent:
275
def __init__(self, base_agent, get_token_func):
276
self.base_agent = base_agent
277
self.get_token = get_token_func
278
self.current_token = None
279
280
@defer.inlineCallbacks
281
def request(self, method, uri, headers=None, bodyProducer=None):
282
# Refresh token if needed
283
if not self.current_token:
284
self.current_token = yield self.get_token()
285
286
# Add token to headers
287
if headers is None:
288
headers = Headers()
289
else:
290
headers = headers.copy()
291
292
headers.addRawHeader('Authorization', f'Bearer {self.current_token}')
293
294
response = yield self.base_agent.request(method, uri, headers, bodyProducer)
295
296
# Handle token expiration
297
if response.code == 401:
298
self.current_token = yield self.get_token()
299
headers.setRawHeaders('Authorization', [f'Bearer {self.current_token}'])
300
response = yield self.base_agent.request(method, uri, headers, bodyProducer)
301
302
defer.returnValue(response)
303
```
304
305
## Types
306
307
Authentication-related types:
308
309
```python { .api }
310
# Basic auth configuration
311
AuthConfig = Tuple[Union[str, bytes], Union[str, bytes]]
312
313
# Agent interface
314
from twisted.web.iweb import IAgent
315
316
# Headers type
317
from twisted.web.http_headers import Headers
318
319
# Username/password types
320
Username = Union[str, bytes]
321
Password = Union[str, bytes]
322
```
323
324
## Security Best Practices
325
326
### Credential Handling
327
328
- **Environment variables**: Store credentials in environment variables, not code
329
- **Secure transmission**: Always use HTTPS for authenticated requests
330
- **Password rotation**: Implement credential rotation for long-running applications
331
- **Least privilege**: Use credentials with minimal required permissions
332
333
### SSL/TLS Configuration
334
335
- **Certificate validation**: Ensure proper SSL certificate validation
336
- **Strong ciphers**: Configure agents to use strong cipher suites
337
- **TLS versions**: Use modern TLS versions (1.2+)
338
- **HSTS**: Respect HTTP Strict Transport Security headers
339
340
### Error Handling
341
342
- **Status codes**: Check response status codes for authentication failures
343
- **Retry logic**: Implement appropriate retry logic for temporary failures
344
- **Logging**: Log authentication events while protecting sensitive data
345
- **Rate limiting**: Respect API rate limits to avoid account lockouts
346
347
### Token Management
348
349
- **Expiration**: Handle token expiration gracefully
350
- **Refresh**: Implement automatic token refresh when possible
351
- **Storage**: Securely store tokens (avoid plain text files)
352
- **Scope**: Use appropriately scoped tokens for different operations