14 KiB
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
sequenceDiagram
participant Client
participant API
participant AuthManager
participant Database
Client->>API: POST /api/v1/auth/login<br/>{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<br/>Authorization: Bearer <token>
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:
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:
@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:
@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.
Usage:
@app.get("/custom-endpoint")
@auth_manager.require_role("custom_role")
async def custom_endpoint(current_user: User):
return {"message": "Custom role access"}
Returns: Decorator function that validates role
JWT Token Structure
Token Payload
{
"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:
# .env
JWT_SECRET_KEY=your-super-secret-key-change-in-production
JWT_EXPIRE_MINUTES=30
Permission Hierarchy
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:
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
POST /api/v1/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"username": "testuser",
"password": "securepassword123"
}
Response:
{
"id": 123,
"username": "testuser",
"email": "user@example.com",
"role": "customer",
"is_active": true
}
Login
POST /api/v1/auth/login
Content-Type: application/json
{
"username": "testuser",
"password": "securepassword123"
}
Response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"token_type": "bearer",
"expires_in": 1800
}
Using Authentication
Include the JWT token in the Authorization header:
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
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
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
- Always hash passwords: Never store plain text passwords
- Use dependency injection: Leverage FastAPI's
Dependsfor auth - Validate tokens: Always validate tokens on protected endpoints
- Check permissions: Verify user has required role/permissions
- Log auth events: Track login, logout, failed attempts
For Operations
- Strong secret keys: Use long, random JWT secret keys
- HTTPS only: Never send tokens over HTTP
- Token expiration: Keep token lifetimes short
- Rotate secrets: Periodically rotate JWT secret keys
- Monitor auth logs: Watch for suspicious activity
For Security
- Rate limiting: Limit auth endpoint requests
- Account lockout: Implement after N failed attempts
- Email verification: Require email confirmation
- Password policies: Enforce strong password requirements
- 2FA support: Consider adding two-factor authentication
Examples
Protecting an Endpoint
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
@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 - System-wide request processing
- Error Handling - Exception handling
- Backend API Reference - Technical AuthManager docs
- Testing Guide - Testing authentication
Technical Reference
For detailed API documentation of authentication classes and methods: