Authentication
This document explains the authentication system used in the Rhesis frontend application.
Authentication Architecture
The Rhesis frontend uses NextAuth.js to manage authentication sessions. The backend provides a native authentication system with support for:
- Email/password login and registration
- OAuth login (Google, GitHub)
- Magic link (passwordless) login
- Automatic access token refresh via refresh token rotation
All sensitive tokens (refresh tokens) are stored inside NextAuth’s httpOnly cookie and are never exposed to client-side JavaScript. Only the short-lived access token (15 minutes) is accessible to frontend components for API calls.
Authentication Flow
Email/Password Login
- User submits credentials via the
AuthFormcomponent - Frontend calls
POST /auth/login/emailon the backend - Backend validates credentials and returns an access token and refresh token
- Frontend calls
signIn('credentials', \{ session_token, refresh_token \})to establish the session - NextAuth stores both tokens in an httpOnly cookie
OAuth Login (Google, GitHub)
- User clicks “Sign in with Google” or “Sign in with GitHub”
- Frontend redirects to
GET /auth/login/\{provider\} - Backend redirects to the OAuth provider
- After authentication, provider redirects to
GET /auth/callback - Backend wraps the tokens in a short-lived auth code (60 seconds) and redirects to the frontend
- Frontend exchanges the auth code via
POST /auth/exchange-code - Frontend calls
signIn('credentials', \{ session_token, refresh_token \})to establish the session
Magic Link Login
- User enters their email address
- Frontend calls
POST /auth/magic-link - Backend sends a single-use login link via email
- User clicks the link, frontend calls
POST /auth/magic-link/verify - Backend returns tokens, frontend establishes session via
signIn()
Session Management
httpOnly Cookie Security
NextAuth stores its internal JWT (containing the access token, refresh token, and user data) in an httpOnly cookie:
Automatic Token Refresh
The NextAuth jwt callback handles automatic access token refresh:
- On every request, NextAuth checks if the access token is within 60 seconds of expiry
- If so, it calls
POST /auth/refreshwith the stored refresh token - The new access token and rotated refresh token replace the old values in the cookie
- This is transparent to the user — sessions are maintained for up to 7 days
If the refresh fails, token.error = 'RefreshTokenError' is set, which downstream components use to trigger re-authentication.
Route Protection
Routes are protected using middleware in src/middleware.ts:
- Public routes:
/auth/*, Quick Start landing page - Protected routes: All routes under
/(protected)/require a valid session - Onboarding redirect: Users without an organization are redirected to the onboarding flow
The middleware reads the NextAuth session cookie, verifies the session token with the backend via GET /auth/verify, and enforces route protection.
Authentication Components
AuthForm
The AuthForm component (components/auth/AuthForm.tsx) handles both login and registration:
- Email/password form with validation
- OAuth provider buttons (Google, GitHub) — shown only when providers are enabled
- Magic link option
- Toggle between login and registration modes
Provider Discovery
The frontend queries GET /auth/providers at startup to discover which authentication providers are enabled. OAuth buttons are only shown when the corresponding provider is configured on the backend.
Session Establishment Pattern
Every place that establishes a session uses NextAuth’s signIn() function:
This calls NextAuth’s server-side authorize callback, which:
- Sends
POST /auth/verifywith the access token to the backend - Backend validates the JWT and returns user info
- NextAuth stores both tokens in the httpOnly cookie
Files that use this pattern:
components/auth/AuthForm.tsx— Email/password login and registrationapp/auth/signin/page.tsx— OAuth callback (exchanges auth code for tokens)app/auth/magic-link/page.tsx— Magic link verificationapp/auth/verify-email/page.tsx— Email verification
Environment Variables
The frontend requires these authentication-related variables:
Security Considerations
- httpOnly cookies: Refresh tokens are never exposed to client-side JavaScript
- Short-lived access tokens: Access tokens expire in 15 minutes, limiting the impact of XSS
- HTTPS: Always use HTTPS in production to protect cookies in transit
- Token refresh: Automatic refresh ensures seamless sessions without long-lived tokens
- CORS: Backend CORS configuration restricts which origins can make API requests
- Error handling: Generic error messages prevent information leakage
- Auth code pattern: OAuth callbacks use a short-lived JWT auth code instead of exposing raw tokens in redirect URLs