Routes Reference
The IAM service registers 26 HTTP endpoints across six express.Router
instances plus two standalone endpoints. When using bootstrapApp(), all
routes are mounted automatically in the correct order. When building a custom
Express app, mount each router with app.use().
import express from 'express'
import cookieParser from 'cookie-parser'
import {
authenticationRoutes,
tokenRotationRoutes,
magicLinks,
bffAccessRoute,
apiVerificationRoute,
apiProtectedRoutes,
sendOperationalConfig,
} from '@riavzon/auth'
const app = express()
app.use(apiVerificationRoute())
app.use(cookieParser())
app.use(authenticationRoutes)
app.use(tokenRotationRoutes)
app.use(magicLinks)
app.use(bffAccessRoute)
app.use(apiProtectedRoutes())
app.use('/operational/config', sendOperationalConfig)
cookie-parser must be registered before any router that reads req.cookies.
The public API verification route does not use cookies, but the
authentication, token rotation, magic link, BFF, and API management routers do.For the full middleware stack applied by bootstrapApp(), see the Middleware Reference.
authenticationRoutes
Core signup, login, and OAuth entry points. Every route in this router enforces Content-Type: application/json, rejects empty request bodies, and requires the canary_id cookie.
POST /signup
Registers a new user account with email and password. Validates the request body against the signup Zod schema, checks for disposable email providers, verifies the domain's MX record, hashes the password with Argon2id, and creates the user record. On success, issues an access token and a refresh token.
Middleware chain
validateContentType('application/json')
Rejects requests without a JSON content type.
express.json({ limit: '1kb' })
Parses the JSON body. Rejects empty bodies with HTTP 403.
Canary cookie check
Returns 400 if the canary_id cookie is absent.
handleSignUp
The signup controller.
Request body
password exactly."on" to indicate acceptance of terms and privacy policy. Transformed to a boolean internally."on", issues a longer-lived refresh token using the configured rememberMe TTL. Transformed to a boolean internally. Defaults to false when omitted.Responses
| Status | Meaning |
|---|---|
201 | User created, access and refresh tokens issued |
400 | Validation error, password mismatch, or passwords found in data breaches |
403 | XSS attempt detected or empty body |
409 | Email already registered |
429 | Rate limit exceeded |
See Signup for the full signup flow documentation.
POST /login
Authenticates a user with email and password. Verifies the password against the stored Argon2id hash, runs rate limiting with consecutive failure tracking, and issues tokens on success.
Middleware chain
validateContentType('application/json')
Rejects requests without a JSON content type.
express.json({ limit: '1kb' })
Parses the JSON body. Rejects empty bodies with HTTP 403.
Canary cookie check
Returns 400 if the canary_id cookie is absent.
handleLogin
The login controller.
Request body
Responses
| Status | Meaning |
|---|---|
200 | Authentication successful, access and refresh tokens issued |
400 | Validation error |
401 | Invalid credentials |
403 | XSS attempt detected, user banned, or empty body |
429 | Rate limit exceeded |
See Login for the full login flow documentation.
POST /auth/OAuth/:providerName
Authenticates a user via a configured OAuth provider. The :providerName parameter must match a provider registered with configureOauthProviders(). Validates the provider profile against the provider's Zod schema.
Middleware chain
validateContentType('application/json')
Rejects requests without a JSON content type.
express.json({ limit: '4kb' })
Larger body limit to accommodate OAuth profile data. Rejects empty bodies with HTTP 403.
Canary cookie check
Returns 400 if the canary_id cookie is absent.
OAuthHandler
The OAuth controller.
URL parameters
configureOauthProviders() (for example, google, github).Responses
| Status | Meaning |
|---|---|
201 | Authentication successful, access and refresh tokens issued |
400 | Bad request or schema validation errors |
404 | Unknown provider |
403 | XSS attempt detected or empty body |
409 | E-mail already registered |
429 | Rate limit exceeded |
500 | Server error during user creation or token issuance. |
See OAuth for the full OAuth flow documentation.
tokenRotationRoutes
Manages the access token and refresh token lifecycle after initial authentication. Both routes in this router operate exclusively through cookies. They do not accept request bodies, query strings, or Content-Type headers.
POST /auth/user/refresh-session
Consumes the current refresh token and issues a new access token and refresh token pair. Validates the session against the canary_id cookie, runs the anomaly detection pipeline, checks the session lifetime against MAX_SESSION_LIFE, and revokes the old refresh token before issuing fresh credentials.
Middleware chain
requireRefreshToken
Validates that the session cookie is present.
acceptCookieOnly
Rejects any request body, query string, or Content-Type header.
getFingerPrint
Collects device, browser, and geo fingerprint data.
checkForActiveMfa
Checks if the session have an active anomaly associated with it
rotateCredentials
The token rotation controller.
Cookies required
| Cookie | Purpose |
|---|---|
session | The current refresh token |
canary_id | The canary cookie for anomaly detection |
Responses
| Status | Meaning |
|---|---|
201 | Tokens rotated, new access and refresh tokens issued |
202 | Anomaly detected, MFA challenge email sent (no rotation performed) |
400 | Body, query string, or Content-Type present |
401 | Refresh token missing, invalid, expired, or session exceeded MAX_SESSION_LIFE |
429 | Rate limit exceeded |
See Refresh Tokens for the full rotation flow documentation.
POST /auth/logout
Revokes the current refresh token and clears the session cookies. Requires both the access token (in the Authorization header) and the refresh token (in the session cookie).
Middleware chain
requireRefreshToken
Validates that the session cookie is present.
requireAccessToken
Extracts the Bearer token from the Authorization header.
acceptCookieOnly
Rejects any request body, query string, or Content-Type header.
handleLogout
The logout controller.
Cookies required
| Cookie | Purpose |
|---|---|
session | The current refresh token |
canary_id | The canary cookie |
Headers required
| Header | Value |
|---|---|
Authorization | Bearer <access_token> |
Responses
| Status | Meaning |
|---|---|
200 | Logout successful, refresh token revoked, cookies cleared |
400 | Body, query string, or Content-Type present |
401 | Access token or refresh token missing |
See Logout for the full logout flow.
magicLinks
Handles MFA verification, custom MFA flows, email update, and password reset. Every POST route enforces Content-Type: application/json and rejects empty bodies. GET routes read the magic link token from query parameters.
GET /auth/verify-mfa
Previews an MFA magic link. Validates the signed token from the query parameters and returns the link metadata. Limited to a configurable number of GET previews before the link expires.
Middleware chain
linkMfaVerification
Validates the magic link token, random hash, visitor identity, and enforces single-use semantics.
Query parameters
MAGIC_LINK_MFA_CHECKS).Responses
| Status | Body | Meaning |
|---|---|---|
200 | { ok: true, date: string, data: { link: 'MFA Code', reason: string } } | Link is valid |
400 | { error: string } | Invalid, expired, or already-used link |
POST /auth/verify-mfa
Submits the MFA code to complete authentication. Consumes the magic link (single-use) and verifies the OTP code. On success, issues new access and refresh tokens.
Middleware chain
linkMfaVerification
Validates and consumes the magic link token.
validateContentType('application/json')
Enforces JSON content type.
express.json({ limit: '1kb' })
Parses the JSON body.
detectBots
Runs bot detection on the request.
getFingerPrint
Collects device fingerprint data.
verifyMFA
Verifies the MFA code and issues tokens.
Request body
Responses
| Status | Meaning |
|---|---|
200 | MFA verified, new access and refresh tokens issued |
400 | Malformed input or purpose/subject mismatch |
401 | Invalid or expired code |
403 | User banned or XSS detected |
500 | Internal error |
See MFA for the full adaptive MFA flow.
POST /custom/mfa/:reason
Initiates a custom MFA flow for a sensitive action. Generates a temporary magic link and OTP code, sends the email to the authenticated user, and returns flow metadata. The :reason parameter identifies the action being protected (for example, PAYMENT_CONFIRM, ACCOUNT_DELETE).
Middleware chain
validateContentType('application/json')
Enforces JSON content type.
requireAccessToken
Extracts the Bearer token.
requireRefreshToken
Validates the refresh token cookie.
getFingerPrint
Collects device fingerprint data.
checkForActiveMfa
Checks if the session have an active anomaly associated with it
protectRoute
Full JWT verification and anomaly detection.
express.json({ limit: '1kb' })
Parses the JSON body.
initCustomMfaFlow
The custom MFA initiation controller.
URL parameters
Headers required
| Header | Value |
|---|---|
Authorization | Bearer <access_token> |
Cookies required
| Cookie | Purpose |
|---|---|
session | The current refresh token |
canary_id | The canary cookie |
Responses
| Status | Meaning |
|---|---|
200 | MFA flow initiated, email sent |
401 | Not authenticated |
429 | Rate limit exceeded |
See Magic Links for the full custom MFA flow documentation.
GET /auth/verify-custom-mfa
Previews a custom MFA magic link. Validates the token and returns the link metadata. Requires full authentication.
Middleware chain
requireAccessToken
Extracts the Bearer token.
requireRefreshToken
Validates the refresh token cookie.
getFingerPrint
Collects device fingerprint data.
checkForActiveMfa
Checks if the session have an active anomaly associated with it
protectRoute
Full JWT verification and anomaly detection.
customMfaFlowsVerification
Validates the custom MFA magic link token, random hash, and visitor identity.
Query parameters
POST /auth/verify-custom-mfa
Submits the custom MFA code to complete a protected action. Requires full authentication plus magic link verification.
Middleware chain
validateContentType('application/json')
Enforces JSON content type.
requireAccessToken
Extracts the Bearer token.
requireRefreshToken
Validates the refresh token cookie.
getFingerPrint
Collects device fingerprint data.
checkForActiveMfa
Checks if the session have an active anomaly associated with it
protectRoute
Full JWT verification and anomaly detection.
express.json({ limit: '1kb' })
Parses the JSON body.
customMfaFlowsVerification
Validates and consumes the custom MFA magic link.
detectBots
Runs bot detection on the request.
verifyCustomMfa
Verifies the custom MFA code and completes the action.
Request body
Responses
| Status | Meaning |
|---|---|
200 | Custom MFA verified, action completed, new tokens issued |
400 | Malformed input or purpose/subject mismatch |
401 | Invalid or expired code |
403 | User banned or XSS attempt detected |
500 | Internal error |
POST /update/email
Requests an email address change. Requires full authentication plus custom MFA verification. The new email is validated and the change is applied after MFA verification completes.
Middleware chain
validateContentType('application/json')
Enforces JSON content type.
requireAccessToken
Extracts the Bearer token.
requireRefreshToken
Validates the refresh token cookie.
getFingerPrint
Collects device fingerprint data.
checkForActiveMfa
Checks if the session have an active anomaly associated with it
protectRoute
Full JWT verification and anomaly detection.
express.json({ limit: '1kb' })
Parses the JSON body.
customMfaFlowsVerification
Validates and consumes the custom MFA magic link.
detectBots
Runs bot detection on the request.
updateEmailController
The email update controller.
Request body
Responses
| Status | Meaning |
|---|---|
200 | Email address updated successfully |
400 | Validation error, invalid session, or email already in use |
401 | Invalid or expired MFA code |
403 | User banned or XSS attempt detected |
500 | Internal error |
POST /auth/forgot-password
Initiates a password reset flow by sending a magic link email to the provided address. Does not require authentication. Uses timing normalization to prevent email enumeration.
Middleware chain
validateContentType('application/json')
Enforces JSON content type.
express.json({ limit: '1kb' })
Parses the JSON body.
initPasswordReset
The password reset initiation controller.
Request body
Responses
| Status | Meaning |
|---|---|
200 | Password reset email sent (always returns success to prevent enumeration) |
429 | Rate limit exceeded |
See Password Reset for the full flow.
GET /auth/reset-password
Previews a password reset magic link. Validates the signed token from the query parameters and returns link metadata.
Middleware chain
linkPasswordVerification
Validates the password reset magic link token, random hash, and visitor identity.
Query parameters
Same as the MFA GET routes: token, random, reason, visitor.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | { ok: true, date: string, data: { link: 'Password Reset', reason: string } } | Link is valid |
400 | { error: string } | Invalid, expired, or already-used link |
POST /auth/reset-password
Submits the new password to complete the reset flow. Validates the magic link token, checks the new password against the Zod schema and the Have I Been Pwned breach database, hashes it with Argon2id, and updates the user record.
Middleware chain
linkPasswordVerification
Validates and consumes the password reset magic link.
validateContentType('application/json')
Enforces JSON content type.
express.json({ limit: '1kb' })
Parses the JSON body.
detectBots
Runs bot detection on the request.
getFingerPrint
Collects device fingerprint data.
verifyNewPassword
Validates, hashes, and updates the password.
Request body
password exactly.Responses
| Status | Meaning |
|---|---|
200 | Password updated |
400 | Validation error, password mismatch, or password found in data breaches |
403 | XSS attempt detected |
429 | Rate limit exceeded |
bffAccessRoute
Backend-for-Frontend authorization endpoints. These routes verify the current session and return user data or token metadata to the BFF layer. Both routes require full authentication.
GET /secret/data
Returns authenticated user data to the BFF layer. Verifies that the user and visitor exist in the database and responds with an authorization status.
Middleware chain
requireAccessToken
Extracts the Bearer token.
requireRefreshToken
Validates the refresh token cookie.
getFingerPrint
Collects device fingerprint data.
checkForActiveMfa
Checks if the session have an active anomaly associated with it
protectRoute
Full JWT verification and anomaly detection.
allowBffAccess
The BFF authorization controller.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | { userId, authorized: true, ipAddress, userAgent, date, roles } | Authorized |
401 | { authorized: false, reason: 'Not authenticated', ... } | req.user missing |
404 | { authorized: false, reason: 'Not found', ... } | User or visitor not found |
GET /secret/accesstoken/metadata
Returns the decoded access token payload with TTL information. Useful for the BFF layer to check token freshness and determine when to trigger a rotation.
Middleware chain
requireAccessToken
Extracts the Bearer token.
requireRefreshToken
Validates the refresh token cookie.
getFingerPrint
Collects device fingerprint data.
checkForActiveMfa
Checks if the session have an active anomaly associated with it
protectRoute
Full JWT verification and anomaly detection.
acceptCookieOnly
Rejects any body, query string, or Content-Type header.
getAccessTokenPayload
The metadata controller.
Responses
| Status | Body | Meaning |
|---|---|---|
200 | { authorized: true, payload, msUntilExp, refreshThreshold, shouldRotate, roles, ... } | Authorized with token metadata |
401 | { authorized: false, reason: 'Not authenticated', ... } | Not authenticated |
404 | { authorized: false, reason: 'Not found', ... } | User or visitor not found |
The refreshThreshold field indicates 25% of the access token TTL in milliseconds, and shouldRotate is true when the remaining lifetime (msUntilExp) falls below that threshold. The BFF client uses these fields to proactively refresh tokens before they expire.
apiVerificationRoute()
This factory returns the public API-token verification router. In
bootstrapApp(), the service mounts it before express.json(),
cookieParser(), and the bot-detector middleware because it only reads
headers, query parameters, and the resolved client IP.
GET /api/public/verify
Verifies a raw API token against the requested privilege without requiring a
user session. The route reads the token from the x-api-key header and the
required privilege from the privilege query parameter.
Route-level middleware
This endpoint has no route-level middleware. It goes straight to
verifyApiTokenController, so only the service-wide guards from
bootstrapApp() apply.
Headers required
| Header | Value |
|---|---|
x-api-key | The raw API token to verify |
Query parameters
demo, restricted,
protected, full, or custom.Responses
| Status | Meaning |
|---|---|
200 | Token verified successfully |
400 | Invalid privilege query value or unresolved client IP |
401 | Missing or malformed x-api-key header, or token verification failed |
403 | XSS input detected in the privilege query |
429 | Rate limit exceeded |
See Verifying Tokens for the full verification flow and response shapes.
apiProtectedRoutes()
This factory returns the authenticated API-token management router. It exposes a
shared POST /api/manage/:action pipeline for mutating token actions and a
shared GET /api/manage/:action pipeline for token listing.
POST /api/manage/:action
Handles token creation and the manager-backed token actions. Supported :action
values are new-token, revoke, metadata, rotate,
ip-restriction-update, and privilege-update.
Middleware chain
requireAccessToken
Extracts the Bearer token from the Authorization header.
requireRefreshToken
Validates the refresh token cookie.
getFingerPrint
Collects device and geolocation data for the request.
checkForActiveMfa
Short-circuits sessions that already have an unresolved MFA or re-login state.
protectRoute
Runs JWT verification and anomaly detection.
contentType('application/json')
Rejects non-JSON requests.
express.json({ limit: '1kb' })
Parses the body and rejects empty payloads.
apiTokensController
Dispatches the requested action.
Supported actions
| Path | Body shape | Success | See |
|---|---|---|---|
POST /api/manage/new-token | privilege, name, optional prefix, expires, ipv4 | 201 | Creating Tokens |
POST /api/manage/revoke | tokenId, publicIdentifier, name | 200 | Revocation |
POST /api/manage/metadata | tokenId, publicIdentifier, name | 200 | Metadata |
POST /api/manage/rotate | tokenId, publicIdentifier, name | 200 | Rotation |
POST /api/manage/ip-restriction-update | tokenId, publicIdentifier, name, optional ipv4 | 200 | IP Restriction |
POST /api/manage/privilege-update | tokenId, publicIdentifier, name, newPrivilege | 200 | Privileges |
GET /api/manage/:action
This route currently exposes the listing branch only. The built-in supported
value is list-metadata, which returns the current valid token inventory for
the authenticated user.
Middleware chain
requireAccessToken
Extracts the Bearer token from the Authorization header.
requireRefreshToken
Validates the refresh token cookie.
getFingerPrint
Collects device and geolocation data for the request.
checkForActiveMfa
Short-circuits sessions that already have an unresolved MFA or re-login state.
protectRoute
Runs JWT verification and anomaly detection.
apiTokensController
Dispatches the listing action.
Supported action
| Path | Body | Success | See |
|---|---|---|---|
GET /api/manage/list-metadata | No body | 200 | Token Listing |
Standalone Endpoints
GET /operational/config
Returns a minimal operational configuration payload to a trusted client IP. Used by the Auth H3 Client to coordinate cookie domains and token TTLs. Rejects all requests from untrusted IP addresses.
Access control
This endpoint uses IP-based access control rather than token authentication. Only the IP address configured in service.clientIp or service.proxy.ipToTrust is allowed.
Response (200)
{
"domain": ".example.com",
"accessTokenTTL": 900000
}
| Field | Description |
|---|---|
domain | The cookie domain from jwt.refresh_tokens.domain |
accessTokenTTL | Access token time-to-live in milliseconds (defaults to 15 minutes) |
Responses on failure
| Status | Body |
|---|---|
403 | { error: 'Forbidden' } |
GET /health
A basic health check endpoint registered directly on the Express app. Returns 200 OK as plain text. This route is exempt from HMAC verification when called from a local address.
Request Prerequisites
Every route that accepts a JSON body enforces the following rules:
- Content-Type: Must be
application/json. The service returns403otherwise. - Non-empty body: The body must not be empty. Empty payloads return
403. - Body size limit:
1kbfor most routes,4kbfor the OAuth route. - Canary cookie: The
canary_idcookie must be present on signup, login, and OAuth routes. Returns400if missing.
The canary_id cookie is set by the Bot Detector during the first visit. It ties the session to the originating device.
/auth/user/refresh-session, /auth/logout, /secret/accesstoken/metadata) reject any request body, query string, or Content-Type header via the acceptCookieOnly middleware.Route Summary
| Method | Path | Router | Description |
|---|---|---|---|
POST | /signup | authenticationRoutes | Register a new user account |
POST | /login | authenticationRoutes | Authenticate with email and password |
POST | /auth/OAuth/:providerName | authenticationRoutes | Authenticate via an OAuth provider |
POST | /auth/user/refresh-session | tokenRotationRoutes | Rotate tokens and refresh the session |
POST | /auth/logout | tokenRotationRoutes | Revoke the refresh token and end the session |
GET | /auth/verify-mfa | magicLinks | Preview an MFA magic link |
POST | /auth/verify-mfa | magicLinks | Submit the MFA code to complete authentication |
POST | /custom/mfa/:reason | magicLinks | Initiate a custom MFA flow for a protected action |
GET | /auth/verify-custom-mfa | magicLinks | Preview a custom MFA magic link |
POST | /auth/verify-custom-mfa | magicLinks | Submit the custom MFA code |
POST | /update/email | magicLinks | Request an email address change |
POST | /auth/forgot-password | magicLinks | Initiate a password reset |
GET | /auth/reset-password | magicLinks | Preview a password reset magic link |
POST | /auth/reset-password | magicLinks | Submit the new password |
GET | /secret/data | bffAccessRoute | BFF authorization check |
GET | /secret/accesstoken/metadata | bffAccessRoute | Return decoded access token payload and TTL hints |
GET | /api/public/verify | apiVerificationRoute() | Verify an API token against a requested privilege |
POST | /api/manage/new-token | apiProtectedRoutes() | Create a new API token |
GET | /api/manage/list-metadata | apiProtectedRoutes() | List the user's valid API tokens |
POST | /api/manage/revoke | apiProtectedRoutes() | Revoke an API token |
POST | /api/manage/metadata | apiProtectedRoutes() | Return metadata for one API token |
POST | /api/manage/rotate | apiProtectedRoutes() | Rotate an API token |
POST | /api/manage/ip-restriction-update | apiProtectedRoutes() | Update a token IP whitelist |
POST | /api/manage/privilege-update | apiProtectedRoutes() | Update a token privilege |
GET | /operational/config | Standalone | Return operational configuration to trusted client |
GET | /health | Built-in | Health check (returns 200 OK) |