# 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<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**:
```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)
