Module: routes/auth

Authentication routes for email/password and OAuth (GitHub, Google).

Endpoints (INF-005: all under /api/v1/auth/)

Method Path Description
POST /api/v1/auth/register Email/password registration
POST /api/v1/auth/login Email/password sign-in
POST /api/v1/auth/logout Token revocation + cookie clear
POST /api/v1/auth/refresh Refresh session (extend cookie TTL)
GET /api/v1/auth/me Return current user from cookie
GET /api/v1/auth/export Export user-owned account data (SEC-003)
DELETE /api/v1/auth/account Delete account + owned data (SEC-003)
GET /api/v1/auth/verify Verify email via token (SEC-001)
POST /api/v1/auth/resend-verification Resend verification email (SEC-001)
POST /api/v1/auth/forgot-password Request a password reset token
POST /api/v1/auth/reset-password Reset password using a valid token
GET /api/v1/auth/github/callback GitHub OAuth token exchange
GET /api/v1/auth/google/callback Google OAuth token exchange

Security measures

  • Passwords hashed with scrypt (64-byte key, 16-byte random salt)
  • JWT stored in HttpOnly; Secure; SameSite=Strict cookie — never in localStorage
  • A companion token_exp cookie (Non-HttpOnly) exposes only the exp timestamp so the frontend can proactively warn before expiry without ever touching the JWT
  • JWT signed with HS256, 8-hour expiry
  • Rate limiting: separate per-endpoint buckets (login: 10, forgot/reset: 5 per IP per 15 min)
  • Revoked tokens kept in an in-memory Map (production: use Redis — see ENH-002)
  • Password reset tokens persisted in DB table password_reset_tokens (migration 003)
  • Input validation and sanitisation on every endpoint
  • OAuth state parameter validated on the frontend to prevent CSRF
  • CSRF double-submit cookie protection on all mutating endpoints (via appSetup.js)
  • No sensitive data (passwords, raw OAuth tokens, JWT strings) returned to client
Source:

Members

Expiry hint cookie — Non-HttpOnly so the frontend can read the exp timestamp.

Source:

(static, constant) JWT_TTL_SEC

JWT TTL in seconds (8 hours). Must match signJwt default.

Source:

(static, constant) requireAuth

Backward-compatible alias. All files that do import { requireAuth } from "./routes/auth.js" continue to work — requireUser is the same JWT cookie → bearer → query middleware that requireAuth used to be.

Source:

Methods

(static) setAuthCookie(res, token, expSec)

Set the HttpOnly auth cookie + a readable expiry hint cookie on a response. Called after every successful authentication (login, OAuth, refresh, workspace switch).

Parameters:
Name Type Description
res Object

Express response object.

token string

The signed JWT string.

expSec number

Unix timestamp of token expiry (seconds).

Source:

(inner) checkRateLimit(bucket, ip) → {Object}

Check rate limit for a specific bucket.

Parameters:
Name Type Description
bucket string

— key in rateBuckets (e.g. "login", "forgotPassword")

ip string
Source:
Returns:
Type
Object

(inner) clearAuthCookies(res)

Clear both auth cookies, effectively logging the user out client-side.

Parameters:
Name Type Description
res Object

Express response object.

Source:

(inner) ensureUserWorkspace(user)

Ensure the user belongs to at least one workspace, creating a personal workspace if needed. Called from every auth path (login, OAuth) so no user can end up without a workspace.

Parameters:
Name Type Description
user Object

— User row from the database.

Source:

(inner) isOAuthOnlyUser(user) → {boolean}

Check whether a user registered via OAuth only (no password set).

Parameters:
Name Type Description
user Object
Source:
Returns:
Type
boolean

(inner) validatePasswordStrength(password) → {string|null}

Validate password strength.

Parameters:
Name Type Description
password string
Source:
Returns:

Error message, or null if valid.

Type
string | null

(async, inner) verifyAccountPassword(user, password) → {Promise.<boolean>}

Verify the authenticated user's password for sensitive account actions. For OAuth-only users (no passwordHash), password verification is skipped — the OAuth session itself serves as proof of identity.

Parameters:
Name Type Description
user Object
password string
Source:
Returns:
Type
Promise.<boolean>