Skip to content

Phase 3: Rust Backend — Authentication and Authorization System #3

Description

@Christiantyemele

Objective

Implement a secure authentication and authorization system using JWT tokens, password hashing, role-based access control (RBAC), and middleware-protected routes.

Authentication Flow

Registration

  1. Client sends POST /api/auth/register with email, password, first_name, last_name
  2. Server validates input (email format, password strength, uniqueness)
  3. Server hashes password with Argon2id
  4. Server creates user record with role = 'member'
  5. Server sends verification email (optional, can be stubbed for v1)
  6. Server returns JWT access token + refresh token

Login

  1. Client sends POST /api/auth/login with email and password
  2. Server looks up user by email
  3. Server verifies password hash with Argon2id
  4. Server checks is_active flag
  5. Server updates last_login_at
  6. Server returns JWT access token + refresh token

Token Refresh

  1. Client sends POST /api/auth/refresh with refresh token
  2. Server validates refresh token signature and expiry
  3. Server issues new access token + refresh token
  4. Old refresh token is invalidated

Logout

  1. Client sends POST /api/auth/logout with refresh token
  2. Server invalidates refresh token
  3. Server clears any server-side session state

JWT Implementation

Token Structure

  • Access Token: Short-lived (15 minutes), contains user ID, role, email
  • Refresh Token: Long-lived (7 days), stored in HTTP-only secure cookie or database

Claims

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Claims {
    pub sub: Uuid,        // User ID
    pub email: String,
    pub role: UserRole,
    pub iat: i64,         // Issued at
    pub exp: i64,         // Expiration
}

Middleware

  • AuthMiddleware — Extracts and validates JWT from Authorization: Bearer <token> header
  • RoleMiddleware — Checks if user has required role for the route
  • OwnerMiddleware — Verifies user owns the resource being accessed

Password Security

Hashing

  • Use Argon2id with OWASP-recommended parameters:
    • Memory: 64 MB
    • Iterations: 3
    • Parallelism: 4
  • Use argon2 crate

Validation

  • Minimum 8 characters
  • At least one uppercase letter
  • At least one number
  • At least one special character
  • Check against common password breach list (optional: integrate HaveIBeenPwned API)

RBAC Implementation

Roles and Permissions

Role Projects Items Comments Users Audit Logs
admin CRUD CRUD CRUD CRUD Read
manager CRUD (own) CRUD CRUD Read Read
member Read (invited) CRUD (assigned) CRUD Read None
viewer Read (invited) Read Read Read None

Permission Checking

  • Implement as Axum extractors
  • Use #[derive(FromRequest)] for CurrentUser extractor
  • Check permissions at the service layer, not just the route level

API Endpoints

Authentication

POST   /api/auth/register          — Register new user
POST   /api/auth/login             — Login and get tokens
POST   /api/auth/logout            — Logout and invalidate tokens
POST   /api/auth/refresh           — Refresh access token
POST   /api/auth/forgot-password   — Request password reset
POST   /api/auth/reset-password    — Reset password with token
POST   /api/auth/verify-email      — Verify email address
GET    /api/auth/me                — Get current user profile
PUT    /api/auth/me                — Update current user profile
PUT    /api/auth/me/password       — Change password

Error Responses

pub struct AuthError {
    pub code: String,      // e.g., "INVALID_CREDENTIALS", "TOKEN_EXPIRED"
    pub message: String,   // Human-readable message
    pub details: Option<serde_json::Value>,
}

Request/Response Types

Register Request

#[derive(Debug, Deserialize, Validate)]
pub struct RegisterRequest {
    #[validate(email)]
    pub email: String,
    #[validate(length(min = 8))]
    pub password: String,
    #[validate(length(min = 1, max = 100))]
    pub first_name: String,
    #[validate(length(min = 1, max = 100))]
    pub last_name: String,
}

Login Request

#[derive(Debug, Deserialize)]
pub struct LoginRequest {
    pub email: String,
    pub password: String,
}

Auth Response

#[derive(Debug, Serialize)]
pub struct AuthResponse {
    pub user: UserResponse,
    pub access_token: String,
    pub refresh_token: String,
    pub token_type: String,  // "Bearer"
    pub expires_in: i64,     // seconds
}

Security Considerations

  • Rate Limiting: Implement rate limiting on auth endpoints using governor crate
  • Brute Force Protection: Lock account after 5 failed attempts for 15 minutes
  • Token Storage: Refresh tokens in HTTP-only, Secure, SameSite=Strict cookies
  • CORS: Configure strict CORS policy for frontend origin only
  • Headers: Set security headers (HSTS, X-Content-Type-Options, etc.)
  • Logging: Log all auth events (login, logout, failed attempts) without sensitive data

Testing Requirements

Unit Tests

  • Password hashing and verification
  • JWT token generation and validation
  • Claims serialization/deserialization
  • Role permission checks
  • Input validation

Integration Tests

  • Registration flow (happy path + validation errors)
  • Login flow (correct credentials + incorrect credentials)
  • Token refresh flow
  • Logout flow
  • Protected route access with valid/invalid/expired tokens
  • Role-based route access

Acceptance Criteria

  • User can register with valid credentials
  • User cannot register with duplicate email
  • Password is hashed with Argon2id before storage
  • User can login with correct credentials
  • User cannot login with incorrect credentials
  • Access token expires after 15 minutes
  • Refresh token can be used to get new access token
  • Expired refresh tokens are rejected
  • Logout invalidates refresh tokens
  • Protected routes reject unauthenticated requests
  • Role-based access control works correctly
  • Rate limiting prevents brute force attacks
  • All auth endpoints return proper error codes and messages
  • Password change requires current password verification
  • CORS is configured for frontend origin only
  • Security headers are set on all responses
  • All tests pass

Notes

  • Use tower-http for CORS, compression, and security headers
  • Use axum-extra for cookie extraction
  • Consider using jsonwebtoken crate for JWT handling
  • Store refresh tokens in database for revocation capability
  • Use secrecy crate for handling sensitive data (passwords, tokens)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions