Authentication
Overview
The application implements a comprehensive role-based access control (RBAC) system with three user roles: Admin, Coach, and Runner.
Authentication System
Architecture:
- Provider-based: Extensible authentication provider architecture
- Local Authentication: Bcrypt password hashing (cost factor 12)
- Session Management: Flask-Login for session handling
- Rate Limiting: 50 login attempts per 15 minutes (configurable)
Components:
app/auth/providers/- Authentication provider implementationsapp/auth/user.py- User model with Flask-Login integrationapp/auth/routes.py- Login/logout/profile endpointsapp/auth/permissions.py- Authorization decorators
User Roles & Permissions
| Role | Athletes Dashboard | Admin Dashboard | Runner Access | Create Athletes | User Management |
|---|---|---|---|---|---|
| Admin | Full access, all runners | Full access | All runners | Yes | Full CRUD |
| Coach | Full access, assigned runners | Limited (Workouts & Schemas only) | Assigned runners only | Yes | Cannot manage users |
| Runner | Auto-navigated to own view | No access | Own profile only | No | Profile edit only |
Multi-role Users: Users with multiple roles (e.g., Coach + Runner) receive the highest level of access. A Coach who is also a Runner will have Coach-level access to the Athletes Dashboard.
Runner Auto-Navigation: Pure runner users (those with only the runner role) are automatically redirected to their personal training view (/#/runner/{id}/info/) upon login, bypassing the Athletes Dashboard entirely. They cannot navigate back to the dashboard and do not see the "Add New Athlete" card.
User-Runner Integration
Data Model:
// Users Collection
{
_id: ObjectId,
username: String (unique),
email: String (unique),
password_hash: String (bcrypt),
roles: [String], // ["admin", "coach", "runner"]
runner_id: ObjectId, // Links to runner profile (if runner role)
coached_runners: [ObjectId], // Array of runner IDs (if coach role)
is_active: Boolean,
created_at: DateTime,
last_login: DateTime
}
// Runner Collection
{
_id: ObjectId,
runnerID: String, // Legacy string ID
name: String,
email: String,
profile_complete: Boolean, // Flags incomplete profiles for onboarding
// ... training data fields ...
}
Relationship: One-way link from users.runner_id → runner._id
Onboarding Workflow
New runner users go through a 4-step onboarding wizard:
- Basic Info: Name, age
- Heart Rate Zones: 5 HR zones with automatic calculation
- Personal Bests: Multiple distances with performance metric calculation
- Training Parameters: Physiological model parameters
Implementation:
- First login detects
profile_complete: falseand redirects to/onboarding - Onboarding form matches "Add New Athlete" wizard format
- After completion, redirects to runner detail page via hash route
/#/runner/{id}/info/
User Creation Workflows
Workflow 1: Admin creates runner user
Admin → User Management → Create User (runner role)
↓
User account created
↓
Runner profile auto-created with profile_complete: false
↓
Runner logs in → Redirected to onboarding
Workflow 2: Coach creates athlete
Coach → Add New Athlete → Complete 4-step wizard
↓
Runner profile created
↓
Optional: Create user account (Step 5)
↓
If yes: User account created and linked
↓
Coach auto-assigned to runner
Workflow 3: Migration of existing data
Migration script → Analyze orphaned users/runners
↓
Auto-create missing runner profiles or user accounts
↓
Link by email matching
↓
Flag incomplete profiles for onboarding
Route Protection
Decorators:
@login_required- Requires authenticated user@admin_only- Admin role required@coach_or_admin- Coach or Admin role required@role_required('role_name')- Custom role requirement
Permission Filtering:
/runnersendpoint returns filtered results based on role- Runners only see their own profile
- Coaches only see assigned runners
- Admins see all runners
Security Implementation
-
Password Security
- Bcrypt hashing with cost factor 12
- Password strength validation (8+ chars, uppercase, lowercase, digit, special)
- Password change requires current password verification
- Last admin protection (cannot remove admin role from last admin user)
-
Session Security
- Flask-Login session management
- Secure session cookies
- Rate limiting on login endpoint
-
Input Validation
- Username validation (3-30 chars, alphanumeric + underscore)
- Email validation
- Role validation against allowed roles
-
API Security
- All routes require authentication
- Role-based authorization on sensitive endpoints
- 401/403 error pages for unauthorized access
-
Data Protection
- MongoDB connections via SSL/TLS
- Environment variables for sensitive configuration
- Certificate management via certifi package