Authentication Module (app.auth)¶
The authentication module handles user login, logout, registration, and session management with multi-user support.
Overview¶
The app.auth
module provides:
- Multi-user authentication system
- Session management with "remember me" functionality
- User registration for admins
- User switching for administrative purposes
- Administrator single-password mode
Blueprint Routes¶
Authentication Routes¶
All authentication routes are prefixed with /auth
:
Route | Method | Description |
---|---|---|
/auth/login |
GET, POST | User login page and handler |
/auth/logout |
GET | Logout handler |
/auth/register |
GET, POST | User registration (admin only) |
/auth/switch-user/<username> |
GET | Switch user context (admin only) |
/auth/switch-back |
GET | Return to admin context |
Route Handlers¶
login()¶
@auth_bp.route("/login", methods=["GET", "POST"])
def login() -> Union[str, Response]:
"""
Handle user login.
GET: Display the login form.
POST: Process login credentials and authenticate user.
Supports both administrator single-password mode and multi-user mode.
Returns:
Union[str, Response]: Either a redirect response on successful login
or rendered login template.
"""
Features:
- Multi-user authentication with username and password
- Administrator single-password mode (username field left blank)
- "Remember me" functionality
- Session management
- Flash message feedback
POST Data:
username
(optional) - Username for multi-user modepassword
(required) - User passwordremember
(optional) - "Remember me" checkbox
Authentication Flow:
1. If username provided: Multi-user authentication via UserManager
2. If no username: Admin mode using TRUNK8_ADMIN_PASSWORD
3. Set session variables on success
4. Configure session permanence based on "remember me"
logout()¶
@auth_bp.route("/logout")
def logout() -> Response:
"""
Handle user logout.
Clears the user's session and redirects to the login page.
Returns:
Response: Redirect response to the login page.
"""
Features:
- Clears all session data
- Provides logout confirmation message
- Redirects to login page
register()¶
@auth_bp.route("/register", methods=["GET", "POST"])
def register() -> Union[str, Response]:
"""
Handle user registration (admin only).
GET: Display the registration form (admin only).
POST: Process user registration (admin only).
Returns:
Union[str, Response]: Either a redirect response or rendered registration template.
"""
Features:
- Admin-only access (requires admin authentication)
- User creation via UserManager
- Input validation and sanitization
- Password confirmation
- Admin privilege assignment
POST Data:
username
(required) - Unique username (3+ chars, alphanumeric + _ -)password
(required) - Password (4+ chars minimum)confirm_password
(required) - Password confirmationdisplay_name
(optional) - Human-readable nameis_admin
(optional) - Admin privileges checkbox
Validation Rules:
- Username: 3+ characters, alphanumeric with hyphens and underscores only
- Password: 4+ characters minimum
- Passwords must match
- Username must be unique
switch_user()¶
@auth_bp.route("/switch-user/<username>")
def switch_user(username: str) -> Response:
"""
Switch to another user context (admin only).
Args:
username: Username to switch to.
Returns:
Response: Redirect response.
"""
Features:
- Admin-only functionality
- Temporary user context switching
- Preserves admin session
- User existence validation
switch_back()¶
@auth_bp.route("/switch-back")
def switch_back() -> Response:
"""
Switch back to admin user (clear user switching).
Returns:
Response: Redirect response.
"""
Features:
- Returns to original admin context
- Clears user switching session data
- Admin-only access
Decorators Module¶
login_required¶
def login_required(f):
"""
Decorator to require authentication for routes.
Checks if user is authenticated and redirects to login if not.
"""
Usage:
from app.auth.decorators import login_required
@app.route('/protected')
@login_required
def protected_route():
return "This requires authentication"
Features:
- Checks session authentication status
- Redirects to login page if not authenticated
- Preserves original URL for post-login redirect
admin_required¶
def admin_required(f):
"""
Decorator to require admin privileges for routes.
Checks if user is authenticated and has admin privileges.
"""
Usage:
from app.auth.decorators import admin_required
@app.route('/admin-only')
@admin_required
def admin_route():
return "This requires admin privileges"
User Context Functions¶
get_current_user()¶
def get_current_user() -> Optional[str]:
"""
Get the current active username.
Returns the switched user if admin is switching, otherwise the logged-in user.
"""
Returns:
- Active user (if admin is switching)
- Logged-in user (normal case)
- None (if not authenticated)
get_user_context()¶
def get_user_context() -> Dict[str, Any]:
"""
Get user context for templates.
Returns dictionary with user information for template rendering.
"""
Returns context with:
current_user
- Current usernameis_admin
- Admin statusdisplay_name
- User display nameis_switching
- Whether admin is switching users
Session Structure¶
Session variables used by the authentication system:
session = {
'authenticated': bool, # Whether user is logged in
'username': str, # Original logged-in username
'is_admin': bool, # Admin privileges
'display_name': str, # User display name
'active_user': str, # Current active user (for switching)
'active_display_name': str # Active user display name
}
Authentication Modes¶
Multi-User Mode¶
Standard authentication with username and password:
# Login with username and password
user_data = user_manager.authenticate_user(username, password)
if user_data:
# Set session variables
session['authenticated'] = True
session['username'] = username
session['is_admin'] = user_data.get('is_admin', False)
Administrator Mode¶
Administrator authentication with single password:
# Login with password only (no username)
admin_password = os.environ.get('TRUNK8_ADMIN_PASSWORD', 'admin')
if password == admin_password:
# Set session for admin user
session['authenticated'] = True
session['username'] = 'admin'
session['is_admin'] = True
User Management Integration¶
The authentication module integrates with the UserManager:
# Initialize user manager
user_manager = UserManager()
# Authenticate user
user_data = user_manager.authenticate_user(username, password)
# Create new user (admin only)
success = user_manager.create_user(username, password, display_name, is_admin)
# Check if user exists
user_data = user_manager.get_user(username)
Security Features¶
Password Handling¶
- Admin password: Environment variable only (never stored)
- User passwords: SHA-256 hashed storage
- Password validation during registration
- Secure session key generation
Session Security¶
- Configurable session lifetime
- Secure session cookie settings
- Session data clearing on logout
- CSRF protection (built into Flask-WTF when forms are used)
Access Control¶
- Route-level authentication requirements
- Admin privilege checking
- User context isolation
- Secure user switching
Error Handling¶
Common error scenarios and responses:
# Invalid credentials
flash("Invalid username or password.", "error")
# Admin access required
flash("Admin access required to register new users.", "error")
# User not found
flash(f"User '{username}' not found.", "error")
# Registration validation errors
flash("Username must be at least 3 characters.", "error")
flash("Passwords do not match.", "error")
Flash Message Categories¶
The module uses these flash message categories:
success
- Successful operationserror
- Error conditionsinfo
- Informational messageswarning
- Warning messages
Testing Support¶
The authentication module supports testing with:
# Test authentication
def test_login(client):
response = client.post('/auth/login', data={
'username': 'testuser',
'password': 'testpass'
})
assert response.status_code == 302
# Test admin registration
def test_admin_register(authenticated_admin_client):
response = authenticated_admin_client.post('/auth/register', data={
'username': 'newuser',
'password': 'newpass',
'confirm_password': 'newpass',
'display_name': 'New User'
})
assert response.status_code == 302
Configuration¶
Authentication configuration is handled via:
- Environment variables:
TRUNK8_ADMIN_PASSWORD
,TRUNK8_SECRET_KEY
- Session configuration:
permanent_lifetime_days
in config.toml - User data: Stored in
users/users.toml
Next Steps¶
- Links Module - Link management with user context
- User Manager - User management utilities
- Main Routes - User management interface