# Authentication & Role-Based Access Control (RBAC) Complete guide to the authentication and authorization system powering the multi-tenant platform. ## Overview The platform uses a JWT-based authentication system combined with role-based access control (RBAC) to secure all interfaces: - **Admin** interface - **Vendor** dashboard - **Shop** storefront - **REST API** endpoints ## Authentication System ### Technology Stack - **JWT (JSON Web Tokens)**: Stateless authentication - **bcrypt**: Secure password hashing - **Jose**: JWT encoding/decoding library - **FastAPI Security**: OAuth2 password bearer flow ### Authentication Flow ```mermaid sequenceDiagram participant Client participant API participant AuthManager participant Database Client->>API: POST /api/v1/auth/login
{username, password} API->>AuthManager: authenticate_user() AuthManager->>Database: Query user by username/email Database-->>AuthManager: User record AuthManager->>AuthManager: verify_password() AuthManager-->>API: User object API->>AuthManager: create_access_token() AuthManager-->>API: JWT token API-->>Client: {access_token, token_type, expires_in} Note over Client: Store token Client->>API: GET /api/v1/resource
Authorization: Bearer API->>AuthManager: verify_token() AuthManager->>AuthManager: Decode JWT AuthManager->>Database: Query user by ID Database-->>AuthManager: User object AuthManager-->>API: Current user API->>API: Process request API-->>Client: Resource data ``` ## User Roles The platform has three distinct user roles, each with specific permissions and access levels: ### Customer Role **Access**: Public shop and own account space **Capabilities**: - Browse vendor shops - Place orders - Manage their own account and order history - View order status - Update profile information - Can register directly from shop frontend **Account Creation**: Self-registration via shop frontend (email verification required) **Authentication**: Standard JWT authentication ### Vendor Role **Access**: Vendor area based on permissions **Types**: - **Vendor Owner**: Full access to vendor dashboard and settings - **Vendor Team Members**: Access based on assigned permissions **Capabilities**: - Manage products and inventory - Process orders - View analytics and reports - Configure shop settings (owners only) - Manage team members (owners only) - Access vendor-specific APIs **Account Creation**: - Owners: Created automatically when admin creates a vendor - Team members: Invited by vendor owner via email **Permissions System**: Team members can have granular permissions for different areas ### Admin Role **Access**: Full platform administration **Capabilities**: - Manage all vendors - Create/manage vendor accounts - Access system settings - View all data across the platform - Manage users of all types - Access audit logs - Platform-wide analytics **Account Creation**: Created by super admins on the backend **Super Privileges**: Admins can access all areas including vendor and customer sections ## Application Areas & Access Control The platform has three distinct areas with different access requirements: | Area | URL Pattern | Access | Purpose | |------|-------------|--------|---------| | **Admin** | `/admin/*` or `admin.platform.com` | Admin users only | Platform administration and vendor management | | **Vendor** | `/vendor/*` | Vendor owners and team members | Vendor dashboard and shop management | | **Shop** | `/shop/*`, custom domains, subdomains | Customers and public | Public-facing eCommerce storefront | | **API** | `/api/*` | All authenticated users (role-based) | REST API for all operations | ## Account Registration Flow ### Admin Accounts - ❌ Cannot register from frontend - ✅ Created by super admins on the backend - Used for: Platform administration ### Vendor Accounts - ❌ Cannot register from frontend - ✅ **Vendor Owners**: Automatically created when admin creates a new vendor - ✅ **Team Members**: Invited by vendor owner via email invitation - Activation: Upon clicking email verification link ### Customer Accounts - ✅ Can register directly on vendor shop - Activation: Upon clicking registration email link - Used for: Shopping and order management ## Role Enforcement Methods The `AuthManager` class provides several methods for role-based access control: ### require_admin() Restricts access to admin users only. **Usage**: ```python from fastapi import Depends from models.database.user import User from middleware.auth import auth_manager @app.get("/admin/dashboard") async def admin_dashboard( current_user: User = Depends(auth_manager.require_admin) ): return {"message": "Admin access"} ``` **Raises**: `AdminRequiredException` if user is not admin ### require_vendor() Allows access to vendor users and admins. **Usage**: ```python @app.get("/vendor/products") async def vendor_products( current_user: User = Depends(auth_manager.require_vendor) ): return {"products": [...]} ``` **Raises**: `InsufficientPermissionsException` if user is not vendor or admin ### require_customer() Allows access to customer users and admins. **Usage**: ```python @app.get("/shop/orders") async def customer_orders( current_user: User = Depends(auth_manager.require_customer) ): return {"orders": [...]} ``` **Raises**: `InsufficientPermissionsException` if user is not customer or admin ### require_role() Custom role enforcement for specific roles. This method returns a decorator factory that creates role-checking decorators for any role name. **Method Signature**: ```python def require_role(self, required_role: str) -> Callable ``` **Parameters**: - `required_role` (str): The exact role name required (e.g., "admin", "vendor", "custom_role") **Returns**: A decorator function that: 1. Accepts a function as input 2. Returns a wrapper that validates the current user's role 3. Raises `HTTPException(403)` if the role doesn't match **Usage Example**: ```python from fastapi import Depends, APIRouter from middleware.auth import auth_manager from models.database.user import User router = APIRouter() @router.get("/moderator-only") @auth_manager.require_role("moderator") async def moderator_endpoint(current_user: User): """Only users with role='moderator' can access this.""" return {"message": "Moderator access granted"} # Can also be used with custom roles @router.get("/special-access") @auth_manager.require_role("special_user") async def special_endpoint(current_user: User): return {"data": "special content"} ``` **Error Response**: ```json { "detail": "Required role 'moderator' not found. Current role: 'vendor'" } ``` **Note**: For standard roles (admin, vendor, customer), prefer using the dedicated methods (`require_admin()`, `require_vendor()`, `require_customer()`) as they provide better error handling and custom exceptions. ### create_default_admin_user() Creates a default admin user if one doesn't already exist. This is typically used during initial application setup or database seeding. **Method Signature**: ```python def create_default_admin_user(self, db: Session) -> User ``` **Parameters**: - `db` (Session): SQLAlchemy database session **Returns**: `User` object (either the existing admin user or the newly created one) **Behavior**: 1. Checks if a user with username "admin" already exists 2. If not found, creates a new admin user with: - Username: `admin` - Email: `admin@example.com` - Password: `admin123` (hashed with bcrypt) - Role: `admin` - Status: Active 3. If found, returns the existing user without modification **Usage Example**: ```python from app.core.database import SessionLocal from middleware.auth import auth_manager # During application startup or database initialization db = SessionLocal() try: admin_user = auth_manager.create_default_admin_user(db) print(f"Admin user ready: {admin_user.username}") finally: db.close() ``` **Security Warning**: ⚠️ The default credentials (`admin` / `admin123`) should be changed immediately after first login in production environments. Consider using environment variables for initial admin credentials: ```python # Example: Custom admin creation with env variables import os def create_admin_from_env(db: Session): admin_username = os.getenv("ADMIN_USERNAME", "admin") admin_password = os.getenv("ADMIN_PASSWORD", "admin123") admin_email = os.getenv("ADMIN_EMAIL", "admin@example.com") # Check if admin exists admin = db.query(User).filter(User.username == admin_username).first() if not admin: admin = User( username=admin_username, email=admin_email, hashed_password=auth_manager.hash_password(admin_password), role="admin", is_active=True ) db.add(admin) db.commit() return admin ``` **Typical Use Cases**: - Initial database setup scripts - Application bootstrap/initialization - Development environment setup - Testing fixtures ## JWT Token Structure ### Token Payload ```json { "sub": "123", // User ID (JWT standard claim) "username": "testuser", // Username for display "email": "user@example.com", // User email "role": "vendor", // User role "exp": 1700000000, // Expiration timestamp (JWT standard) "iat": 1699999000 // Issued at timestamp (JWT standard) } ``` ### Token Configuration | Variable | Description | Default | |----------|-------------|---------| | `JWT_SECRET_KEY` | Secret key for JWT signing | Development key (change in production!) | | `JWT_EXPIRE_MINUTES` | Token expiration time in minutes | 30 | **Environment Configuration**: ```bash # .env JWT_SECRET_KEY=your-super-secret-key-change-in-production JWT_EXPIRE_MINUTES=30 ``` ## Permission Hierarchy ```mermaid graph TD A[Admin] --> B[Full Platform Access] A --> C[Can Access All Areas] D[Vendor Owner] --> E[Vendor Dashboard] D --> F[Team Management] D --> G[Shop Settings] D --> H[All Vendor Data] I[Vendor Team Member] --> E I --> J[Limited Based on Permissions] K[Customer] --> L[Shop Access] K --> M[Own Orders] K --> N[Own Profile] ``` **Admin Override**: Admin users have implicit access to all areas, including vendor and customer sections. This allows admins to provide support and manage the platform effectively. ## Security Features ### Password Security **Hashing**: - Algorithm: bcrypt - Automatic salt generation - Configurable work factor **Example**: ```python from middleware.auth import auth_manager # Hash password hashed = auth_manager.hash_password("user_password") # Verify password is_valid = auth_manager.verify_password("user_password", hashed) ``` ### Token Security **Features**: - Signed with secret key (prevents tampering) - Includes expiration time - Stateless (no server-side session storage) - Short-lived (30 minutes default) **Best Practices**: - Use HTTPS in production - Store tokens securely on client - Implement token refresh mechanism - Clear tokens on logout ### Protection Against Common Attacks **SQL Injection**: - ✅ SQLAlchemy ORM with parameterized queries - ✅ Input validation with Pydantic **XSS (Cross-Site Scripting)**: - ✅ Jinja2 auto-escaping - ✅ Content Security Policy headers **CSRF (Cross-Site Request Forgery)**: - ✅ JWT tokens in Authorization header (not cookies) - ✅ SameSite cookie attribute for session cookies **Brute Force**: - ✅ Rate limiting on auth endpoints - ✅ Account lockout after failed attempts (future) ## Authentication Endpoints ### Register User ```http POST /api/v1/auth/register Content-Type: application/json { "email": "user@example.com", "username": "testuser", "password": "securepassword123" } ``` **Response**: ```json { "id": 123, "username": "testuser", "email": "user@example.com", "role": "customer", "is_active": true } ``` ### Login ```http POST /api/v1/auth/login Content-Type: application/json { "username": "testuser", "password": "securepassword123" } ``` **Response**: ```json { "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...", "token_type": "bearer", "expires_in": 1800 } ``` ### Using Authentication Include the JWT token in the Authorization header: ```http GET /api/v1/resource Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... ``` ## Error Handling ### Authentication Errors | Error | Status Code | Description | |-------|-------------|-------------| | `InvalidCredentialsException` | 401 | Username/password incorrect | | `InvalidTokenException` | 401 | JWT token invalid or malformed | | `TokenExpiredException` | 401 | JWT token has expired | | `UserNotActiveException` | 403 | User account is inactive | ### Authorization Errors | Error | Status Code | Description | |-------|-------------|-------------| | `AdminRequiredException` | 403 | Endpoint requires admin role | | `InsufficientPermissionsException` | 403 | User lacks required permissions | ## Testing Authentication ### Unit Tests ```python import pytest from middleware.auth import AuthManager def test_password_hashing(): auth_manager = AuthManager() password = "test_password" hashed = auth_manager.hash_password(password) assert auth_manager.verify_password(password, hashed) assert not auth_manager.verify_password("wrong_password", hashed) def test_create_token(): auth_manager = AuthManager() user = create_test_user(role="vendor") token_data = auth_manager.create_access_token(user) assert "access_token" in token_data assert "token_type" in token_data assert token_data["token_type"] == "bearer" ``` ### Integration Tests ```python def test_login_flow(client): # Register user response = client.post("/api/v1/auth/register", json={ "username": "testuser", "email": "test@example.com", "password": "password123" }) assert response.status_code == 200 # Login response = client.post("/api/v1/auth/login", json={ "username": "testuser", "password": "password123" }) assert response.status_code == 200 token = response.json()["access_token"] # Access protected endpoint response = client.get( "/api/v1/profile", headers={"Authorization": f"Bearer {token}"} ) assert response.status_code == 200 ``` ## Best Practices ### For Developers 1. **Always hash passwords**: Never store plain text passwords 2. **Use dependency injection**: Leverage FastAPI's `Depends` for auth 3. **Validate tokens**: Always validate tokens on protected endpoints 4. **Check permissions**: Verify user has required role/permissions 5. **Log auth events**: Track login, logout, failed attempts ### For Operations 1. **Strong secret keys**: Use long, random JWT secret keys 2. **HTTPS only**: Never send tokens over HTTP 3. **Token expiration**: Keep token lifetimes short 4. **Rotate secrets**: Periodically rotate JWT secret keys 5. **Monitor auth logs**: Watch for suspicious activity ### For Security 1. **Rate limiting**: Limit auth endpoint requests 2. **Account lockout**: Implement after N failed attempts 3. **Email verification**: Require email confirmation 4. **Password policies**: Enforce strong password requirements 5. **2FA support**: Consider adding two-factor authentication ## Examples ### Protecting an Endpoint ```python from fastapi import Depends, APIRouter from sqlalchemy.orm import Session from middleware.auth import auth_manager from app.core.database import get_db from models.database.user import User router = APIRouter() @router.get("/vendors") async def get_vendors( current_user: User = Depends(auth_manager.require_admin), db: Session = Depends(get_db) ): """Only admins can list all vendors.""" vendors = db.query(Vendor).all() return {"vendors": vendors} ``` ### Multi-Role Access ```python @router.get("/dashboard") async def dashboard( current_user: User = Depends(auth_manager.get_current_user), db: Session = Depends(get_db) ): """Accessible by all authenticated users, but returns different data.""" if current_user.role == "admin": # Admin sees everything data = get_admin_dashboard(db) elif current_user.role == "vendor": # Vendor sees their data only data = get_vendor_dashboard(db, current_user.id) else: # Customer sees their orders data = get_customer_dashboard(db, current_user.id) return data ``` ## Related Documentation - [Middleware Stack](middleware.md) - System-wide request processing - [Error Handling](../api/error-handling.md) - Exception handling - [Backend API Reference](../backend/middleware-reference.md) - Technical AuthManager docs - [Testing Guide](../testing/testing-guide.md) - Testing authentication ## Technical Reference For detailed API documentation of authentication classes and methods: - [AuthManager API Reference](../backend/middleware-reference.md#authentication-authorization)