0
# Authentication
1
2
Authentication and authorization support for third-party services including OAuth, OAuth2, OpenID, and integration with major providers like Google, Facebook, and Twitter.
3
4
## Capabilities
5
6
### OAuth 1.0/1.0a Support
7
8
Abstract base classes for implementing OAuth 1.0 and 1.0a authentication flows.
9
10
```python { .api }
11
class OAuthMixin:
12
"""Abstract implementation of OAuth 1.0 and 1.0a."""
13
14
def get_auth_http_client(self):
15
"""Get HTTP client for auth requests."""
16
17
def oauth_request_token_url(self) -> str:
18
"""Get OAuth request token URL."""
19
20
def oauth_access_token_url(self) -> str:
21
"""Get OAuth access token URL."""
22
23
def oauth_authorize_url(self) -> str:
24
"""Get OAuth authorization URL."""
25
26
def oauth_consumer_key(self) -> str:
27
"""Get OAuth consumer key."""
28
29
def oauth_consumer_secret(self) -> str:
30
"""Get OAuth consumer secret."""
31
32
def oauth_get_user(self, access_token: str, callback):
33
"""Get user info with access token."""
34
35
def authenticate_redirect(self, callback_uri: str = None):
36
"""Start OAuth authentication flow."""
37
38
def get_authenticated_user(self, callback):
39
"""Complete OAuth authentication."""
40
```
41
42
### OAuth 2.0 Support
43
44
Abstract base class for OAuth 2.0 authentication flows with authorization code grant.
45
46
```python { .api }
47
class OAuth2Mixin:
48
"""Abstract implementation of OAuth 2.0."""
49
50
def get_auth_http_client(self):
51
"""Get HTTP client for auth requests."""
52
53
def oauth2_request_token_url(self) -> str:
54
"""Get OAuth2 token request URL."""
55
56
def oauth2_authorize_url(self) -> str:
57
"""Get OAuth2 authorization URL."""
58
59
def oauth2_client_id(self) -> str:
60
"""Get OAuth2 client ID."""
61
62
def oauth2_client_secret(self) -> str:
63
"""Get OAuth2 client secret."""
64
65
def oauth2_scope(self) -> str:
66
"""Get OAuth2 scope."""
67
68
def oauth2_access_token_url(self) -> str:
69
"""Get OAuth2 access token URL."""
70
71
def authorize_redirect(self, redirect_uri: str = None, client_id: str = None, client_secret: str = None, extra_params=None, scope: str = None, response_type: str = "code"):
72
"""
73
Start OAuth2 authorization flow.
74
75
Args:
76
redirect_uri: Redirect URI after authorization
77
client_id: OAuth2 client ID
78
client_secret: OAuth2 client secret
79
extra_params: Additional parameters
80
scope: OAuth2 scope
81
response_type: OAuth2 response type
82
"""
83
84
def get_authenticated_user(self, redirect_uri: str, client_id: str, client_secret: str, code: str, callback, extra_fields=None):
85
"""
86
Complete OAuth2 authentication.
87
88
Args:
89
redirect_uri: Redirect URI
90
client_id: OAuth2 client ID
91
client_secret: OAuth2 client secret
92
code: Authorization code
93
callback: Completion callback
94
extra_fields: Additional fields to request
95
"""
96
```
97
98
### OpenID Support
99
100
OpenID authentication with Attribute Exchange support.
101
102
```python { .api }
103
class OpenIdMixin:
104
"""Abstract implementation of OpenID and Attribute Exchange."""
105
106
def authenticate_redirect(self, callback_uri: str = None, ax_attrs: List[str] = None):
107
"""
108
Start OpenID authentication.
109
110
Args:
111
callback_uri: Callback URI
112
ax_attrs: Attribute Exchange attributes to request
113
"""
114
115
def get_authenticated_user(self, callback, http_client=None):
116
"""
117
Complete OpenID authentication.
118
119
Args:
120
callback: Completion callback
121
http_client: HTTP client for requests
122
"""
123
124
def get_auth_http_client(self):
125
"""Get HTTP client for auth requests."""
126
```
127
128
### Google OAuth2
129
130
Google-specific OAuth2 implementation with Google API integration.
131
132
```python { .api }
133
class GoogleOAuth2Mixin(OAuth2Mixin):
134
"""Google OAuth2 authentication."""
135
136
_OAUTH_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/auth"
137
_OAUTH_ACCESS_TOKEN_URL = "https://accounts.google.com/o/oauth2/token"
138
_OAUTH_NO_CALLBACKS = False
139
140
def get_google_oauth_settings(self) -> Dict[str, str]:
141
"""
142
Get Google OAuth settings.
143
144
Returns:
145
Dict with google_oauth client_id and client_secret
146
"""
147
148
def oauth2_client_id(self) -> str:
149
"""Get Google OAuth2 client ID."""
150
151
def oauth2_client_secret(self) -> str:
152
"""Get Google OAuth2 client secret."""
153
154
def oauth2_scope(self) -> str:
155
"""Get Google OAuth2 scope."""
156
157
def oauth2_authorize_url(self) -> str:
158
"""Get Google OAuth2 authorization URL."""
159
160
def oauth2_access_token_url(self) -> str:
161
"""Get Google OAuth2 access token URL."""
162
```
163
164
### Facebook Graph API
165
166
Facebook Graph API authentication and user data access.
167
168
```python { .api }
169
class FacebookGraphMixin(OAuth2Mixin):
170
"""Facebook Graph API authentication."""
171
172
_OAUTH_AUTHORIZE_URL = "https://www.facebook.com/dialog/oauth"
173
_OAUTH_ACCESS_TOKEN_URL = "https://graph.facebook.com/oauth/access_token"
174
_OAUTH_NO_CALLBACKS = False
175
176
def facebook_request(self, path: str, callback, access_token: str = None, post_args=None, **args):
177
"""
178
Make Facebook Graph API request.
179
180
Args:
181
path: API path
182
callback: Response callback
183
access_token: Access token
184
post_args: POST arguments
185
**args: Additional arguments
186
"""
187
188
def oauth2_client_id(self) -> str:
189
"""Get Facebook app ID."""
190
191
def oauth2_client_secret(self) -> str:
192
"""Get Facebook app secret."""
193
194
def oauth2_scope(self) -> str:
195
"""Get Facebook OAuth scope."""
196
197
def oauth2_authorize_url(self) -> str:
198
"""Get Facebook OAuth authorization URL."""
199
200
def oauth2_access_token_url(self) -> str:
201
"""Get Facebook OAuth access token URL."""
202
```
203
204
### Twitter OAuth
205
206
Twitter-specific OAuth 1.0a implementation.
207
208
```python { .api }
209
class TwitterMixin(OAuthMixin):
210
"""Twitter OAuth authentication."""
211
212
_OAUTH_REQUEST_TOKEN_URL = "https://api.twitter.com/oauth/request_token"
213
_OAUTH_ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token"
214
_OAUTH_AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize"
215
_OAUTH_AUTHENTICATE_URL = "https://api.twitter.com/oauth/authenticate"
216
_OAUTH_NO_CALLBACKS = False
217
218
def twitter_request(self, path: str, callback, access_token: dict = None, post_args=None, **args):
219
"""
220
Make Twitter API request.
221
222
Args:
223
path: API path
224
callback: Response callback
225
access_token: Access token dict
226
post_args: POST arguments
227
**args: Additional arguments
228
"""
229
230
def oauth_consumer_key(self) -> str:
231
"""Get Twitter consumer key."""
232
233
def oauth_consumer_secret(self) -> str:
234
"""Get Twitter consumer secret."""
235
236
def oauth_request_token_url(self) -> str:
237
"""Get Twitter request token URL."""
238
239
def oauth_access_token_url(self) -> str:
240
"""Get Twitter access token URL."""
241
242
def oauth_authorize_url(self) -> str:
243
"""Get Twitter authorization URL."""
244
```
245
246
## Usage Examples
247
248
### Google OAuth2 Authentication
249
250
```python
251
import tornado.web
252
import tornado.auth
253
254
class GoogleAuth(tornado.web.RequestHandler, tornado.auth.GoogleOAuth2Mixin):
255
def get_google_oauth_settings(self):
256
return {
257
'google_oauth': {
258
'client_id': 'your-client-id',
259
'client_secret': 'your-client-secret'
260
}
261
}
262
263
async def get(self):
264
if self.get_argument('code', False):
265
# Handle OAuth callback
266
user = await self.get_authenticated_user(
267
redirect_uri='http://localhost:8888/auth/google',
268
code=self.get_argument('code')
269
)
270
271
if user:
272
self.write(f"Hello, {user['name']}!")
273
else:
274
self.write("Authentication failed")
275
else:
276
# Start OAuth flow
277
self.authorize_redirect(
278
redirect_uri='http://localhost:8888/auth/google',
279
client_id=self.get_google_oauth_settings()['google_oauth']['client_id'],
280
scope=['profile', 'email'],
281
response_type='code'
282
)
283
284
app = tornado.web.Application([
285
(r"/auth/google", GoogleAuth),
286
])
287
```
288
289
### Facebook Authentication
290
291
```python
292
import tornado.web
293
import tornado.auth
294
295
class FacebookAuth(tornado.web.RequestHandler, tornado.auth.FacebookGraphMixin):
296
@tornado.web.asynchronous
297
def get(self):
298
if self.get_argument("code", False):
299
self.get_authenticated_user(
300
redirect_uri='http://localhost:8888/auth/facebook',
301
client_id='your-app-id',
302
client_secret='your-app-secret',
303
code=self.get_argument("code"),
304
callback=self.on_auth
305
)
306
else:
307
self.authorize_redirect(
308
redirect_uri='http://localhost:8888/auth/facebook',
309
client_id='your-app-id',
310
extra_params={"scope": "read_stream,offline_access"}
311
)
312
313
def on_auth(self, user):
314
if user:
315
self.write(f"Hello, {user['name']}!")
316
else:
317
self.write("Authentication failed")
318
self.finish()
319
320
app = tornado.web.Application([
321
(r"/auth/facebook", FacebookAuth),
322
])
323
```
324
325
### Twitter Authentication
326
327
```python
328
import tornado.web
329
import tornado.auth
330
331
class TwitterAuth(tornado.web.RequestHandler, tornado.auth.TwitterMixin):
332
@tornado.web.asynchronous
333
def get(self):
334
if self.get_argument("oauth_token", None):
335
self.get_authenticated_user(self.on_auth)
336
else:
337
self.authenticate_redirect(callback_uri='http://localhost:8888/auth/twitter')
338
339
def on_auth(self, user):
340
if user:
341
self.write(f"Hello, {user['username']}!")
342
else:
343
self.write("Authentication failed")
344
self.finish()
345
346
app = tornado.web.Application([
347
(r"/auth/twitter", TwitterAuth),
348
])
349
```
350
351
## Types
352
353
```python { .api }
354
# OAuth token types
355
OAuthToken = Dict[str, str]
356
OAuth2Token = Dict[str, Any]
357
358
# User info type
359
UserInfo = Dict[str, Any]
360
361
# OAuth callback type
362
OAuthCallback = Callable[[UserInfo], None]
363
364
# HTTP client type for auth
365
AuthHTTPClient = tornado.httpclient.AsyncHTTPClient
366
```
367
368
## Exceptions
369
370
```python { .api }
371
class AuthError(Exception):
372
"""Base exception for authentication errors."""
373
374
def __init__(self, message: str):
375
"""
376
Initialize auth error.
377
378
Args:
379
message: Error message
380
"""
381
```