Routes Reference

Complete reference for every HTTP route in the IAM service. Covers six Express routers, two standalone endpoints, middleware chains, request bodies, and response shapes.

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().

server/app.ts
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.

Returns 400 if the canary_id cookie is absent.

handleSignUp

The signup controller.

Request body

email
string required
The user's email address. Validated for format, disposable provider check, and MX record lookup.
password
string required
The password. Validated against the configured password policy (minimum length, complexity). Checked against the Have I Been Pwned breach database.
confirmedPassword
string required
Must match password exactly.
name
string required
The user's display name.
termsConsent
string required
Must be the literal string "on" to indicate acceptance of terms and privacy policy. Transformed to a boolean internally.
rememberUser
string
When set to "on", issues a longer-lived refresh token using the configured rememberMe TTL. Transformed to a boolean internally. Defaults to false when omitted.

Responses

StatusMeaning
201User created, access and refresh tokens issued
400Validation error, password mismatch, or passwords found in data breaches
403XSS attempt detected or empty body
409Email already registered
429Rate 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.

Returns 400 if the canary_id cookie is absent.

handleLogin

The login controller.

Request body

email
string required
The user's email address.
password
string required
The user's password.

Responses

StatusMeaning
200Authentication successful, access and refresh tokens issued
400Validation error
401Invalid credentials
403XSS attempt detected, user banned, or empty body
429Rate 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.

Returns 400 if the canary_id cookie is absent.

OAuthHandler

The OAuth controller.

URL parameters

providerName
string required
The OAuth provider name. Must match a provider configured with configureOauthProviders() (for example, google, github).

Responses

StatusMeaning
201Authentication successful, access and refresh tokens issued
400Bad request or schema validation errors
404Unknown provider
403XSS attempt detected or empty body
409E-mail already registered
429Rate limit exceeded
500Server 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

CookiePurpose
sessionThe current refresh token
canary_idThe canary cookie for anomaly detection

Responses

StatusMeaning
201Tokens rotated, new access and refresh tokens issued
202Anomaly detected, MFA challenge email sent (no rotation performed)
400Body, query string, or Content-Type present
401Refresh token missing, invalid, expired, or session exceeded MAX_SESSION_LIFE
429Rate 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

CookiePurpose
sessionThe current refresh token
canary_idThe canary cookie

Headers required

HeaderValue
AuthorizationBearer <access_token>

Responses

StatusMeaning
200Logout successful, refresh token revoked, cookies cleared
400Body, query string, or Content-Type present
401Access token or refresh token missing

See Logout for the full logout flow.


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

token
string required
The temporary JWT token from the magic link URL.
random
string required
The random hash for cryptographic verification.
reason
string required
The link purpose (for example, MAGIC_LINK_MFA_CHECKS).
visitor
string required
The visitor identifier.

Responses

StatusBodyMeaning
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

code
string required
The 7-digit OTP code from the MFA email.

Responses

StatusMeaning
200MFA verified, new access and refresh tokens issued
400Malformed input or purpose/subject mismatch
401Invalid or expired code
403User banned or XSS detected
500Internal 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

reason
string required
The custom MFA reason. Identifies the sensitive action being protected.

Headers required

HeaderValue
AuthorizationBearer <access_token>

Cookies required

CookiePurpose
sessionThe current refresh token
canary_idThe canary cookie

Responses

StatusMeaning
200MFA flow initiated, email sent
401Not authenticated
429Rate 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

token
string required
The temporary JWT token from the magic link URL.
random
string required
The random hash for cryptographic verification.
reason
string required
The custom MFA reason.
visitor
string required
The visitor identifier.

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

code
string required
The 7-digit OTP code from the custom MFA verification email.

Responses

StatusMeaning
200Custom MFA verified, action completed, new tokens issued
400Malformed input or purpose/subject mismatch
401Invalid or expired code
403User banned or XSS attempt detected
500Internal 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

code
string required
The 7-digit OTP code from the custom MFA verification email.
newEmail
string required
The new email address to change to. Validated for format, disposable provider check, and MX record lookup.

Responses

StatusMeaning
200Email address updated successfully
400Validation error, invalid session, or email already in use
401Invalid or expired MFA code
403User banned or XSS attempt detected
500Internal 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

email
string required
The email address associated with the account.

Responses

StatusMeaning
200Password reset email sent (always returns success to prevent enumeration)
429Rate 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

StatusBodyMeaning
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
string required
The new password. Validated against the configured password policy and checked for breach exposure.
confirmedPassword
string required
Must match password exactly.

Responses

StatusMeaning
200Password updated
400Validation error, password mismatch, or password found in data breaches
403XSS attempt detected
429Rate 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

StatusBodyMeaning
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

StatusBodyMeaning
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

HeaderValue
x-api-keyThe raw API token to verify

Query parameters

privilege
string required
The required privilege scope. Must be one of demo, restricted, protected, full, or custom.

Responses

StatusMeaning
200Token verified successfully
400Invalid privilege query value or unresolved client IP
401Missing or malformed x-api-key header, or token verification failed
403XSS input detected in the privilege query
429Rate 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

PathBody shapeSuccessSee
POST /api/manage/new-tokenprivilege, name, optional prefix, expires, ipv4201Creating Tokens
POST /api/manage/revoketokenId, publicIdentifier, name200Revocation
POST /api/manage/metadatatokenId, publicIdentifier, name200Metadata
POST /api/manage/rotatetokenId, publicIdentifier, name200Rotation
POST /api/manage/ip-restriction-updatetokenId, publicIdentifier, name, optional ipv4200IP Restriction
POST /api/manage/privilege-updatetokenId, publicIdentifier, name, newPrivilege200Privileges

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

PathBodySuccessSee
GET /api/manage/list-metadataNo body200Token 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
}
FieldDescription
domainThe cookie domain from jwt.refresh_tokens.domain
accessTokenTTLAccess token time-to-live in milliseconds (defaults to 15 minutes)

Responses on failure

StatusBody
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 returns 403 otherwise.
  • Non-empty body: The body must not be empty. Empty payloads return 403.
  • Body size limit: 1kb for most routes, 4kb for the OAuth route.
  • Canary cookie: The canary_id cookie must be present on signup, login, and OAuth routes. Returns 400 if missing.

The canary_id cookie is set by the Bot Detector during the first visit. It ties the session to the originating device.

All cookie-only routes (/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

MethodPathRouterDescription
POST/signupauthenticationRoutesRegister a new user account
POST/loginauthenticationRoutesAuthenticate with email and password
POST/auth/OAuth/:providerNameauthenticationRoutesAuthenticate via an OAuth provider
POST/auth/user/refresh-sessiontokenRotationRoutesRotate tokens and refresh the session
POST/auth/logouttokenRotationRoutesRevoke the refresh token and end the session
GET/auth/verify-mfamagicLinksPreview an MFA magic link
POST/auth/verify-mfamagicLinksSubmit the MFA code to complete authentication
POST/custom/mfa/:reasonmagicLinksInitiate a custom MFA flow for a protected action
GET/auth/verify-custom-mfamagicLinksPreview a custom MFA magic link
POST/auth/verify-custom-mfamagicLinksSubmit the custom MFA code
POST/update/emailmagicLinksRequest an email address change
POST/auth/forgot-passwordmagicLinksInitiate a password reset
GET/auth/reset-passwordmagicLinksPreview a password reset magic link
POST/auth/reset-passwordmagicLinksSubmit the new password
GET/secret/databffAccessRouteBFF authorization check
GET/secret/accesstoken/metadatabffAccessRouteReturn decoded access token payload and TTL hints
GET/api/public/verifyapiVerificationRoute()Verify an API token against a requested privilege
POST/api/manage/new-tokenapiProtectedRoutes()Create a new API token
GET/api/manage/list-metadataapiProtectedRoutes()List the user's valid API tokens
POST/api/manage/revokeapiProtectedRoutes()Revoke an API token
POST/api/manage/metadataapiProtectedRoutes()Return metadata for one API token
POST/api/manage/rotateapiProtectedRoutes()Rotate an API token
POST/api/manage/ip-restriction-updateapiProtectedRoutes()Update a token IP whitelist
POST/api/manage/privilege-updateapiProtectedRoutes()Update a token privilege
GET/operational/configStandaloneReturn operational configuration to trusted client
GET/healthBuilt-inHealth check (returns 200 OK)
Logo