0
# Authentication
1
2
Multiple authentication methods including Basic Auth and OAuth2 integration with various providers for securing Flower web interface and API access.
3
4
## Capabilities
5
6
### Authentication Functions
7
8
```python { .api }
9
def authenticate(pattern, email):
10
"""
11
Check if email matches authentication pattern.
12
13
Args:
14
pattern (str): Authentication pattern (regex or email list)
15
email (str): User email to validate
16
17
Returns:
18
bool: True if email is authorized
19
20
Supports regex patterns and comma-separated email lists.
21
"""
22
23
def validate_auth_option(pattern):
24
"""
25
Validate authentication pattern syntax.
26
27
Args:
28
pattern (str): Authentication pattern to validate
29
30
Returns:
31
bool: True if pattern is valid
32
33
Validates regex syntax and email format patterns.
34
"""
35
```
36
37
### OAuth2 Providers
38
39
#### Google OAuth2 Handler
40
41
```python { .api }
42
class GoogleAuth2LoginHandler(BaseHandler, tornado.auth.GoogleOAuth2Mixin):
43
"""
44
Google OAuth2 authentication handler with profile and email scope access.
45
"""
46
47
_OAUTH_SETTINGS_KEY = 'oauth'
48
49
async def get(self):
50
"""
51
Handle OAuth2 authentication flow.
52
53
Processes both authorization redirect and callback phases:
54
- Without code: Redirects to Google OAuth2 authorization
55
- With code: Processes callback and authenticates user
56
"""
57
58
async def _on_auth(self, user):
59
"""
60
Process authentication result from Google.
61
62
Args:
63
user (dict): OAuth2 user data containing access_token
64
65
Raises:
66
tornado.web.HTTPError: 403 if authentication fails or user unauthorized
67
68
Retrieves user email from Google API and validates against auth pattern.
69
Sets secure cookie and redirects to requested page on success.
70
"""
71
```
72
73
#### GitHub OAuth2 Handler
74
75
```python { .api }
76
class GithubLoginHandler(BaseHandler, tornado.auth.OAuth2Mixin):
77
"""
78
GitHub OAuth2 authentication handler with support for GitHub Enterprise.
79
"""
80
81
_OAUTH_DOMAIN = os.getenv("FLOWER_GITHUB_OAUTH_DOMAIN", "github.com")
82
_OAUTH_AUTHORIZE_URL = f'https://{_OAUTH_DOMAIN}/login/oauth/authorize'
83
_OAUTH_ACCESS_TOKEN_URL = f'https://{_OAUTH_DOMAIN}/login/oauth/access_token'
84
_OAUTH_NO_CALLBACKS = False
85
_OAUTH_SETTINGS_KEY = 'oauth'
86
87
async def get_authenticated_user(self, redirect_uri, code):
88
"""
89
Exchange authorization code for access token.
90
91
Args:
92
redirect_uri (str): OAuth2 redirect URI
93
code (str): Authorization code from GitHub
94
95
Returns:
96
dict: Token response containing access_token
97
98
Raises:
99
tornado.auth.AuthError: If token exchange fails
100
"""
101
102
async def get(self):
103
"""
104
Handle OAuth2 authentication flow for GitHub.
105
106
Supports both github.com and GitHub Enterprise instances.
107
Uses 'user:email' scope to access verified email addresses.
108
"""
109
110
async def _on_auth(self, user):
111
"""
112
Process authentication result from GitHub.
113
114
Args:
115
user (dict): OAuth2 user data containing access_token
116
117
Raises:
118
tornado.web.HTTPError: 403 if no verified emails match auth pattern
119
120
Retrieves all verified email addresses and validates against auth pattern.
121
Uses first matching verified email for authentication.
122
"""
123
```
124
125
#### GitLab OAuth2 Handler
126
127
```python { .api }
128
class GitLabLoginHandler(BaseHandler, tornado.auth.OAuth2Mixin):
129
"""
130
GitLab OAuth2 authentication handler with group-based authorization support.
131
"""
132
133
_OAUTH_GITLAB_DOMAIN = os.getenv("FLOWER_GITLAB_OAUTH_DOMAIN", "gitlab.com")
134
_OAUTH_AUTHORIZE_URL = f'https://{_OAUTH_GITLAB_DOMAIN}/oauth/authorize'
135
_OAUTH_ACCESS_TOKEN_URL = f'https://{_OAUTH_GITLAB_DOMAIN}/oauth/token'
136
_OAUTH_NO_CALLBACKS = False
137
138
async def get_authenticated_user(self, redirect_uri, code):
139
"""
140
Exchange authorization code for access token.
141
142
Args:
143
redirect_uri (str): OAuth2 redirect URI
144
code (str): Authorization code from GitLab
145
146
Returns:
147
dict: Token response containing access_token
148
149
Raises:
150
tornado.auth.AuthError: If token exchange fails
151
"""
152
153
async def get(self):
154
"""
155
Handle OAuth2 authentication flow for GitLab.
156
157
Uses 'read_api' scope to access user information and group memberships.
158
Supports both gitlab.com and self-hosted GitLab instances.
159
"""
160
161
async def _on_auth(self, user):
162
"""
163
Process authentication result from GitLab.
164
165
Args:
166
user (dict): OAuth2 user data containing access_token
167
168
Environment Variables:
169
FLOWER_GITLAB_AUTH_ALLOWED_GROUPS: Comma-separated list of allowed groups
170
FLOWER_GITLAB_MIN_ACCESS_LEVEL: Minimum access level (default: 20)
171
172
Raises:
173
tornado.web.HTTPError: 403 if user email or group membership unauthorized
174
175
Validates both email pattern and group membership if groups are configured.
176
"""
177
```
178
179
#### Okta OAuth2 Handler
180
181
```python { .api }
182
class OktaLoginHandler(BaseHandler, tornado.auth.OAuth2Mixin):
183
"""
184
Okta OAuth2 authentication handler with state validation for security.
185
"""
186
187
_OAUTH_NO_CALLBACKS = False
188
_OAUTH_SETTINGS_KEY = 'oauth'
189
190
@property
191
def base_url(self):
192
"""
193
Okta base URL from environment.
194
195
Returns:
196
str: Base URL from FLOWER_OAUTH2_OKTA_BASE_URL environment variable
197
"""
198
199
@property
200
def _OAUTH_AUTHORIZE_URL(self):
201
"""OAuth2 authorization endpoint URL."""
202
return f"{self.base_url}/v1/authorize"
203
204
@property
205
def _OAUTH_ACCESS_TOKEN_URL(self):
206
"""OAuth2 token endpoint URL."""
207
return f"{self.base_url}/v1/token"
208
209
@property
210
def _OAUTH_USER_INFO_URL(self):
211
"""OAuth2 user info endpoint URL."""
212
return f"{self.base_url}/v1/userinfo"
213
214
async def get_access_token(self, redirect_uri, code):
215
"""
216
Exchange authorization code for access token.
217
218
Args:
219
redirect_uri (str): OAuth2 redirect URI
220
code (str): Authorization code from Okta
221
222
Returns:
223
dict: Token response containing access_token
224
225
Raises:
226
tornado.auth.AuthError: If token exchange fails
227
"""
228
229
async def get(self):
230
"""
231
Handle OAuth2 authentication flow for Okta.
232
233
Implements state validation for CSRF protection.
234
Uses 'openid email' scope for authentication.
235
"""
236
237
async def _on_auth(self, access_token_response):
238
"""
239
Process authentication result from Okta.
240
241
Args:
242
access_token_response (dict): Token response containing access_token
243
244
Raises:
245
tornado.web.HTTPError: 403 if email not verified or unauthorized
246
247
Retrieves user info from Okta userinfo endpoint and validates email.
248
Requires verified email address matching auth pattern.
249
"""
250
```
251
252
#### Login Handler Factory
253
254
```python { .api }
255
class LoginHandler(BaseHandler):
256
"""
257
Factory class that instantiates the appropriate OAuth2 handler.
258
259
Uses the auth_provider option to determine which handler to create.
260
Returns NotFoundErrorHandler if no provider is configured.
261
"""
262
263
def __new__(cls, *args, **kwargs):
264
"""
265
Create appropriate login handler instance.
266
267
Returns:
268
BaseHandler: OAuth2 provider handler or NotFoundErrorHandler
269
"""
270
```
271
272
## Configuration Options
273
274
### Basic Authentication
275
276
```bash
277
# Single user
278
--basic-auth=admin:password
279
280
# Multiple users (comma-separated)
281
--basic-auth=admin:secret,user:pass
282
283
# Environment variable
284
export FLOWER_BASIC_AUTH=admin:secret
285
```
286
287
### Email-based Authentication
288
289
```bash
290
# Specific emails
291
--auth=user@domain.com,admin@company.com
292
293
# Domain-based (regex)
294
--auth=.*@company\.com
295
296
# OAuth2 provider with email filtering
297
--auth=google --auth=.*@company\.com
298
```
299
300
### OAuth2 Configuration
301
302
```bash
303
# Google OAuth2
304
--auth=google
305
--oauth2-key=your-client-id
306
--oauth2-secret=your-client-secret
307
--oauth2-redirect-uri=https://flower.example.com/login
308
309
# GitHub OAuth2
310
--auth=github
311
--oauth2-key=github-client-id
312
--oauth2-secret=github-client-secret
313
314
# Environment variables
315
export FLOWER_OAUTH2_KEY=client-id
316
export FLOWER_OAUTH2_SECRET=client-secret
317
export FLOWER_OAUTH2_REDIRECT_URI=https://flower.example.com/login
318
319
# GitLab OAuth2 with custom domain
320
--auth=gitlab
321
export FLOWER_GITLAB_OAUTH_DOMAIN=gitlab.company.com
322
export FLOWER_GITLAB_AUTH_ALLOWED_GROUPS=dev-team,admin-team
323
export FLOWER_GITLAB_MIN_ACCESS_LEVEL=30
324
325
# GitHub Enterprise
326
export FLOWER_GITHUB_OAUTH_DOMAIN=github.company.com
327
328
# Okta OAuth2
329
--auth=okta
330
export FLOWER_OAUTH2_OKTA_BASE_URL=https://company.okta.com/oauth2/default
331
```
332
333
## Usage Examples
334
335
### Basic Auth Setup
336
337
```python
338
from flower.app import Flower
339
from tornado.options import options
340
341
options.basic_auth = ['admin:secret', 'viewer:readonly']
342
flower_app = Flower(options=options)
343
```
344
345
### OAuth2 Setup
346
347
```python
348
options.auth = ['google']
349
options.oauth2_key = 'your-google-client-id'
350
options.oauth2_secret = 'your-google-client-secret'
351
options.oauth2_redirect_uri = 'https://flower.company.com/login'
352
353
flower_app = Flower(options=options)
354
```
355
356
### Custom Authentication
357
358
```python
359
from flower.views.auth import authenticate
360
361
# Custom authentication logic
362
def custom_auth_check(email):
363
# Custom validation logic
364
return email in allowed_users or is_admin(email)
365
366
# Override authenticate function
367
original_authenticate = authenticate
368
def authenticate(pattern, email):
369
return custom_auth_check(email) or original_authenticate(pattern, email)
370
```
371
372
## Authentication Flow
373
374
### Basic Auth Flow
375
1. User accesses protected endpoint
376
2. Browser prompts for username/password
377
3. Credentials validated against configured basic_auth
378
4. Access granted/denied based on validation
379
380
### OAuth2 Flow
381
1. User accesses login URL
382
2. Redirected to OAuth2 provider
383
3. User authenticates with provider
384
4. Provider redirects back with authorization code
385
5. Flower exchanges code for access token
386
6. User email retrieved from provider API
387
7. Email validated against auth pattern
388
8. Session established if authorized
389
390
## Security Considerations
391
392
- Use HTTPS in production for all authentication methods
393
- Store OAuth2 secrets securely (environment variables)
394
- Regularly rotate authentication credentials
395
- Use strict email patterns for OAuth2 filtering
396
- Monitor authentication logs for suspicious activity
397
- Consider session timeout configuration