Skip to Content
DevelopmentBackendBackend Authentication

Authentication

Overview

The Rhesis backend implements a native authentication system with a pluggable provider architecture. The system supports email/password authentication, OAuth providers (Google and GitHub), magic link login, and token-based API access.

Authentication Methods

Email/Password Authentication

Users can register and log in with email and password:

  1. User submits email and password via the frontend
  2. Backend validates credentials (bcrypt hash comparison)
  3. Backend issues a short-lived access token (JWT, 15 minutes) and a long-lived refresh token (opaque, 7 days)
  4. Frontend stores both tokens in an httpOnly cookie via NextAuth
  5. Access tokens are refreshed automatically before expiry

OAuth Authentication (Google, GitHub)

OAuth login is available when the corresponding provider is configured:

  1. User clicks “Sign in with Google” or “Sign in with GitHub”
  2. Backend redirects to the OAuth provider’s authorization page
  3. Provider redirects back to /auth/callback with an authorization code
  4. Backend exchanges the code, creates or updates the user, and issues tokens
  5. Tokens are wrapped in a short-lived auth code (60 seconds) and passed via redirect
  6. Frontend exchanges the auth code for access and refresh tokens

Passwordless login via email:

  1. User enters their email address
  2. Backend sends a single-use magic link (15-minute expiry, JTI-tracked via Redis)
  3. User clicks the link and is authenticated immediately

Token-Based API Authentication

For programmatic API access:

  1. Client obtains a JWT token through the /tokens/ endpoint
  2. Client includes the token in the Authorization header with each request
  3. Backend validates the token and extracts user information

Provider Architecture

The authentication system uses a pluggable provider registry:

auth/providers/registry.py
# Provider Registry - discovers and manages auth providers at startup
ProviderRegistry.initialize()           # Called at startup
ProviderRegistry.get_provider("email")  # Get provider by name
ProviderRegistry.get_enabled_providers()
ProviderRegistry.get_enabled_oauth_providers()

# Available providers:
# - EmailProvider: email/password login and registration
# - GoogleProvider: Google OAuth (requires GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET)
# - GitHubProvider: GitHub OAuth (requires GH_CLIENT_ID, GH_CLIENT_SECRET)

Each provider implements the AuthProvider interface:

auth/providers/base.py
class AuthProvider(ABC):
    name: str                # "email", "google", "github"
    is_enabled: bool         # Configured via environment variables
    display_name: str        # Human-readable name
    is_oauth: bool           # True for OAuth providers

    authenticate(request, **kwargs) -> AuthUser
    get_authorization_url(request, redirect_uri)  # OAuth only

Enabling OAuth Providers

OAuth providers are automatically enabled when their credentials are configured:

.env
# Google OAuth (optional)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret

# GitHub OAuth (optional)
GH_CLIENT_ID=your-github-client-id
GH_CLIENT_SECRET=your-github-client-secret

If no OAuth credentials are provided, only email/password authentication is available.

Authentication Configuration

.env
# JWT Configuration (required)
JWT_SECRET_KEY=your-jwt-secret-key
JWT_ALGORITHM=HS256
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=15

# Auth feature flags
AUTH_EMAIL_PASSWORD_ENABLED=true
AUTH_REGISTRATION_ENABLED=true

# Frontend URL (for email links and OAuth redirects)
FRONTEND_URL=http://localhost:3000

Token System

The authentication system uses multiple token types:

  • Access token (JWT, 15 minutes): Short-lived token for API requests, refreshed automatically
  • Refresh token (opaque, 7 days): Long-lived token stored as a SHA-256 hash in the database, rotated on every use
  • Auth code (JWT, 60 seconds): Wraps access and refresh tokens during OAuth redirects
  • Email flow tokens (JWT): Used for email verification (24 hours), password reset (1 hour, single-use), and magic link (15 minutes, single-use)

Token Rotation

Refresh tokens implement automatic rotation with reuse detection:

  1. Each refresh token can only be used once
  2. On use, the old token is revoked and a new one is issued in the same family
  3. If a revoked token is reused, the entire token family is revoked (theft detection)
  4. Expired tokens are cleaned up periodically

Authentication Middleware

The application uses a custom route class to enforce authentication requirements:

auth-middleware.py
class AuthenticatedAPIRoute(APIRoute):
    def get_dependencies(self):
        if self.path in public_routes:
            # No auth required
            return []
        elif any(self.path.startswith(route) for route in token_enabled_routes):
            # Both session and token auth accepted
            return [Depends(require_current_user_or_token)]
        # Default to session-only auth
        return [Depends(require_current_user)]

Rate Limiting

Authentication endpoints are rate-limited to prevent abuse:

  • Login: 20 requests/hour per IP
  • Registration: 10 requests/hour per IP
  • Password reset: 5 requests/hour per IP
  • Magic link: 5 requests/hour per IP
  • Email verification resend: 5 requests/hour per IP

Security Considerations

  • HTTPS is enforced for all communications
  • Access tokens are short-lived (15 minutes) to limit the impact of token theft
  • Refresh tokens are stored as SHA-256 hashes (raw token never persisted)
  • Passwords are hashed with bcrypt via passlib
  • Single-use tokens (magic link, password reset) are enforced via Redis JTI tracking
  • All email-sensitive endpoints return HTTP 200 regardless of user existence (prevents email enumeration)
  • OAuth redirect URLs are validated against an allowlist of frontend domains
  • Session cookies use httpOnly, secure, and sameSite flags

Email Flows

The following email flows require SMTP configuration:

  • Email verification: Sent on registration, can be resent
  • Password reset: Sent via forgot-password flow
  • Magic link: Passwordless login link
  • Welcome email: Sent to new users

See Environment Variables for SMTP configuration details.