A multi-user server for Jupyter notebooks that provides authentication, spawning, and proxying for multiple users simultaneously
—
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.
The foundation class for all authentication providers in JupyterHub.
class Authenticator(LoggingConfigurable):
"""
Base class for authenticating users to JupyterHub.
Subclass this to implement custom authentication schemes.
"""
# Configuration attributes
admin_users: Set[str] # Set of admin usernames
blocked_users: Set[str] # Set of blocked usernames
allowed_users: Set[str] # Set of allowed usernames
auto_login: bool # Whether to automatically login users
username_pattern: str # Regex pattern for valid usernames
async def authenticate(self, handler, data):
"""
Authenticate a user with login form data.
Args:
handler: The current request handler
data: Dictionary of login form data (username, password, etc.)
Returns:
Username string if authentication succeeds, None if it fails,
or a dictionary with additional user info
"""
async def pre_spawn_start(self, user, spawner):
"""
Hook called before spawning a user's server.
Args:
user: The User object
spawner: The Spawner instance
"""
def pre_spawn_hook(self, spawner):
"""
Deprecated hook called before spawning (use pre_spawn_start).
Args:
spawner: The Spawner instance
"""
def normalize_username(self, username):
"""
Normalize a username for consistent handling.
Args:
username: The username to normalize
Returns:
Normalized username string
"""
def check_blocked_users(self, username, authentication=None):
"""
Check if a user is blocked.
Args:
username: Username to check
authentication: Authentication result
Returns:
True if user is blocked
"""
def check_allowed_users(self, username, authentication=None):
"""
Check if a user is allowed.
Args:
username: Username to check
authentication: Authentication result
Returns:
True if user is allowed
"""Authenticators that work with local system users.
class LocalAuthenticator(Authenticator):
"""
Base class for authenticators that work with local system users.
Provides functionality for creating and managing local user accounts.
"""
create_system_users: bool # Whether to create system users if they don't exist
def system_user_exists(self, user):
"""
Check if a user exists on the system.
Args:
user: User object or username string
Returns:
True if user exists on system
"""
def add_system_user(self, user):
"""
Create a new system user account.
Args:
user: User object or username string
"""
class PAMAuthenticator(LocalAuthenticator):
"""
Authenticate users with PAM (Pluggable Authentication Modules).
Uses the system's PAM configuration for authentication.
"""
service: str # PAM service name (default: 'login')
encoding: str # Text encoding (default: 'utf8')
async def authenticate(self, handler, data):
"""
Authenticate using PAM.
Args:
handler: Current request handler
data: Login form data with 'username' and 'password'
Returns:
Username if authentication succeeds, None otherwise
"""Simple authenticators for development and testing scenarios.
class DummyAuthenticator(Authenticator):
"""
Dummy authenticator for testing.
Any username/password combination will succeed, with the password
set as an attribute on the returned user object.
"""
password: str # Optional fixed password
async def authenticate(self, handler, data):
"""
Authenticate any username/password combination.
Args:
handler: Current request handler
data: Login form data
Returns:
Dictionary with username and authentication info
"""
class NullAuthenticator(Authenticator):
"""
No-op authenticator that allows any username without a password.
Useful for completely open JupyterHub installations.
"""
auto_login: bool = True # Automatically login users
async def authenticate(self, handler, data):
"""
Accept any username without password validation.
Args:
handler: Current request handler
data: Login form data
Returns:
Username from the form data
"""Simple shared password authentication for small deployments.
class SharedPasswordAuthenticator(Authenticator):
"""
Authenticator that uses a single shared password for all users.
Useful for workshops, classes, or small private deployments.
"""
shared_password: str # The shared password for all users
async def authenticate(self, handler, data):
"""
Authenticate users with shared password.
Args:
handler: Current request handler
data: Login form data with 'username' and 'password'
Returns:
Username if password matches, None otherwise
"""# jupyterhub_config.py
c = get_config()
# Use PAM authenticator (default)
c.JupyterHub.authenticator_class = 'pam'
# Configure admin users
c.Authenticator.admin_users = {'admin', 'teacher'}
# Create system users automatically
c.LocalAuthenticator.create_system_users = True
# Set allowed users (optional)
c.Authenticator.allowed_users = {'student1', 'student2', 'student3'}# Development configuration
c.JupyterHub.authenticator_class = 'dummy'
# Set admin users
c.Authenticator.admin_users = {'admin'}
# Optional: Set a fixed password for all users
c.DummyAuthenticator.password = 'test123'from jupyterhub.auth import Authenticator
class CustomAuthenticator(Authenticator):
"""Custom authenticator example"""
async def authenticate(self, handler, data):
"""Custom authentication logic"""
username = data.get('username')
password = data.get('password')
# Implement your authentication logic here
if self.validate_credentials(username, password):
return {
'name': username,
'admin': username in self.admin_users,
'auth_model': {
'custom_field': 'custom_value'
}
}
return None
def validate_credentials(self, username, password):
"""Custom credential validation"""
# Your validation logic here
return True
# Register the authenticator
c.JupyterHub.authenticator_class = CustomAuthenticator# For OAuth-based authenticators (requires additional packages)
class OAuthenticator(Authenticator):
"""Base OAuth authenticator pattern"""
client_id: str # OAuth client ID
client_secret: str # OAuth client secret
oauth_callback_url: str # OAuth callback URL
def login_url(self, base_url):
"""Generate OAuth login URL"""
pass
async def token_to_user(self, token_info):
"""Convert OAuth token to user info"""
passclass CustomAuthenticator(Authenticator):
"""Authenticator with pre-spawn customization"""
async def pre_spawn_start(self, user, spawner):
"""Customize spawner before starting"""
# Set environment variables
spawner.environment.update({
'USER_ROLE': 'student' if user.name != 'admin' else 'teacher',
'JUPYTER_ENABLE_LAB': 'yes'
})
# Set resource limits based on user
if user.name in self.admin_users:
spawner.mem_limit = '2G'
spawner.cpu_limit = 2
else:
spawner.mem_limit = '1G'
spawner.cpu_limit = 1# User access controls
c.Authenticator.admin_users = {'admin1', 'admin2'}
c.Authenticator.allowed_users = {'user1', 'user2', 'user3'}
c.Authenticator.blocked_users = {'blocked_user'}
# Username normalization
c.Authenticator.username_pattern = r'^[a-z][a-z0-9\-_]{1,31}$'
# Automatic login (for some authenticators)
c.Authenticator.auto_login = True# Example: LDAP-style configuration pattern
class LDAPAuthenticator(Authenticator):
"""LDAP authenticator configuration example"""
server_address: str = 'ldap://ldap.example.com'
bind_dn_template: str = 'uid={username},ou=users,dc=example,dc=com'
allowed_groups: Set[str] = set()
async def authenticate(self, handler, data):
"""LDAP authentication implementation"""
# LDAP authentication logic would go here
passInstall with Tessl CLI
npx tessl i tessl/pypi-jupyterhub