0
# Authentication System
1
2
JupyterHub's authentication system provides a pluggable architecture for user authentication supporting multiple backends including PAM, OAuth, LDAP, and custom implementations. The system handles user login, session management, and authorization for notebook server access.
3
4
## Capabilities
5
6
### Base Authenticator Class
7
8
The foundation class for all authentication providers in JupyterHub.
9
10
```python { .api }
11
class Authenticator(LoggingConfigurable):
12
"""
13
Base class for authenticating users to JupyterHub.
14
15
Subclass this to implement custom authentication schemes.
16
"""
17
18
# Configuration attributes
19
admin_users: Set[str] # Set of admin usernames
20
blocked_users: Set[str] # Set of blocked usernames
21
allowed_users: Set[str] # Set of allowed usernames
22
auto_login: bool # Whether to automatically login users
23
username_pattern: str # Regex pattern for valid usernames
24
25
async def authenticate(self, handler, data):
26
"""
27
Authenticate a user with login form data.
28
29
Args:
30
handler: The current request handler
31
data: Dictionary of login form data (username, password, etc.)
32
33
Returns:
34
Username string if authentication succeeds, None if it fails,
35
or a dictionary with additional user info
36
"""
37
38
async def pre_spawn_start(self, user, spawner):
39
"""
40
Hook called before spawning a user's server.
41
42
Args:
43
user: The User object
44
spawner: The Spawner instance
45
"""
46
47
def pre_spawn_hook(self, spawner):
48
"""
49
Deprecated hook called before spawning (use pre_spawn_start).
50
51
Args:
52
spawner: The Spawner instance
53
"""
54
55
def normalize_username(self, username):
56
"""
57
Normalize a username for consistent handling.
58
59
Args:
60
username: The username to normalize
61
62
Returns:
63
Normalized username string
64
"""
65
66
def check_blocked_users(self, username, authentication=None):
67
"""
68
Check if a user is blocked.
69
70
Args:
71
username: Username to check
72
authentication: Authentication result
73
74
Returns:
75
True if user is blocked
76
"""
77
78
def check_allowed_users(self, username, authentication=None):
79
"""
80
Check if a user is allowed.
81
82
Args:
83
username: Username to check
84
authentication: Authentication result
85
86
Returns:
87
True if user is allowed
88
"""
89
```
90
91
### Local System Authenticators
92
93
Authenticators that work with local system users.
94
95
```python { .api }
96
class LocalAuthenticator(Authenticator):
97
"""
98
Base class for authenticators that work with local system users.
99
100
Provides functionality for creating and managing local user accounts.
101
"""
102
103
create_system_users: bool # Whether to create system users if they don't exist
104
105
def system_user_exists(self, user):
106
"""
107
Check if a user exists on the system.
108
109
Args:
110
user: User object or username string
111
112
Returns:
113
True if user exists on system
114
"""
115
116
def add_system_user(self, user):
117
"""
118
Create a new system user account.
119
120
Args:
121
user: User object or username string
122
"""
123
124
class PAMAuthenticator(LocalAuthenticator):
125
"""
126
Authenticate users with PAM (Pluggable Authentication Modules).
127
128
Uses the system's PAM configuration for authentication.
129
"""
130
131
service: str # PAM service name (default: 'login')
132
encoding: str # Text encoding (default: 'utf8')
133
134
async def authenticate(self, handler, data):
135
"""
136
Authenticate using PAM.
137
138
Args:
139
handler: Current request handler
140
data: Login form data with 'username' and 'password'
141
142
Returns:
143
Username if authentication succeeds, None otherwise
144
"""
145
```
146
147
### Development and Testing Authenticators
148
149
Simple authenticators for development and testing scenarios.
150
151
```python { .api }
152
class DummyAuthenticator(Authenticator):
153
"""
154
Dummy authenticator for testing.
155
156
Any username/password combination will succeed, with the password
157
set as an attribute on the returned user object.
158
"""
159
160
password: str # Optional fixed password
161
162
async def authenticate(self, handler, data):
163
"""
164
Authenticate any username/password combination.
165
166
Args:
167
handler: Current request handler
168
data: Login form data
169
170
Returns:
171
Dictionary with username and authentication info
172
"""
173
174
class NullAuthenticator(Authenticator):
175
"""
176
No-op authenticator that allows any username without a password.
177
178
Useful for completely open JupyterHub installations.
179
"""
180
181
auto_login: bool = True # Automatically login users
182
183
async def authenticate(self, handler, data):
184
"""
185
Accept any username without password validation.
186
187
Args:
188
handler: Current request handler
189
data: Login form data
190
191
Returns:
192
Username from the form data
193
"""
194
```
195
196
### Shared Password Authenticator
197
198
Simple shared password authentication for small deployments.
199
200
```python { .api }
201
class SharedPasswordAuthenticator(Authenticator):
202
"""
203
Authenticator that uses a single shared password for all users.
204
205
Useful for workshops, classes, or small private deployments.
206
"""
207
208
shared_password: str # The shared password for all users
209
210
async def authenticate(self, handler, data):
211
"""
212
Authenticate users with shared password.
213
214
Args:
215
handler: Current request handler
216
data: Login form data with 'username' and 'password'
217
218
Returns:
219
Username if password matches, None otherwise
220
"""
221
```
222
223
## Usage Examples
224
225
### PAM Authentication Setup
226
227
```python
228
# jupyterhub_config.py
229
c = get_config()
230
231
# Use PAM authenticator (default)
232
c.JupyterHub.authenticator_class = 'pam'
233
234
# Configure admin users
235
c.Authenticator.admin_users = {'admin', 'teacher'}
236
237
# Create system users automatically
238
c.LocalAuthenticator.create_system_users = True
239
240
# Set allowed users (optional)
241
c.Authenticator.allowed_users = {'student1', 'student2', 'student3'}
242
```
243
244
### Dummy Authenticator for Development
245
246
```python
247
# Development configuration
248
c.JupyterHub.authenticator_class = 'dummy'
249
250
# Set admin users
251
c.Authenticator.admin_users = {'admin'}
252
253
# Optional: Set a fixed password for all users
254
c.DummyAuthenticator.password = 'test123'
255
```
256
257
### Custom Authenticator Implementation
258
259
```python
260
from jupyterhub.auth import Authenticator
261
262
class CustomAuthenticator(Authenticator):
263
"""Custom authenticator example"""
264
265
async def authenticate(self, handler, data):
266
"""Custom authentication logic"""
267
username = data.get('username')
268
password = data.get('password')
269
270
# Implement your authentication logic here
271
if self.validate_credentials(username, password):
272
return {
273
'name': username,
274
'admin': username in self.admin_users,
275
'auth_model': {
276
'custom_field': 'custom_value'
277
}
278
}
279
return None
280
281
def validate_credentials(self, username, password):
282
"""Custom credential validation"""
283
# Your validation logic here
284
return True
285
286
# Register the authenticator
287
c.JupyterHub.authenticator_class = CustomAuthenticator
288
```
289
290
### OAuth Integration Pattern
291
292
```python
293
# For OAuth-based authenticators (requires additional packages)
294
class OAuthenticator(Authenticator):
295
"""Base OAuth authenticator pattern"""
296
297
client_id: str # OAuth client ID
298
client_secret: str # OAuth client secret
299
oauth_callback_url: str # OAuth callback URL
300
301
def login_url(self, base_url):
302
"""Generate OAuth login URL"""
303
pass
304
305
async def token_to_user(self, token_info):
306
"""Convert OAuth token to user info"""
307
pass
308
```
309
310
### Pre-spawn Hooks
311
312
```python
313
class CustomAuthenticator(Authenticator):
314
"""Authenticator with pre-spawn customization"""
315
316
async def pre_spawn_start(self, user, spawner):
317
"""Customize spawner before starting"""
318
# Set environment variables
319
spawner.environment.update({
320
'USER_ROLE': 'student' if user.name != 'admin' else 'teacher',
321
'JUPYTER_ENABLE_LAB': 'yes'
322
})
323
324
# Set resource limits based on user
325
if user.name in self.admin_users:
326
spawner.mem_limit = '2G'
327
spawner.cpu_limit = 2
328
else:
329
spawner.mem_limit = '1G'
330
spawner.cpu_limit = 1
331
```
332
333
## Configuration Patterns
334
335
### User Management Configuration
336
337
```python
338
# User access controls
339
c.Authenticator.admin_users = {'admin1', 'admin2'}
340
c.Authenticator.allowed_users = {'user1', 'user2', 'user3'}
341
c.Authenticator.blocked_users = {'blocked_user'}
342
343
# Username normalization
344
c.Authenticator.username_pattern = r'^[a-z][a-z0-9\-_]{1,31}$'
345
346
# Automatic login (for some authenticators)
347
c.Authenticator.auto_login = True
348
```
349
350
### Integration with External Systems
351
352
```python
353
# Example: LDAP-style configuration pattern
354
class LDAPAuthenticator(Authenticator):
355
"""LDAP authenticator configuration example"""
356
357
server_address: str = 'ldap://ldap.example.com'
358
bind_dn_template: str = 'uid={username},ou=users,dc=example,dc=com'
359
allowed_groups: Set[str] = set()
360
361
async def authenticate(self, handler, data):
362
"""LDAP authentication implementation"""
363
# LDAP authentication logic would go here
364
pass
365
```