Configuration
The IAM service is initialized by calling configuration() with a single typed object. The schema is validated at startup with Zod and any missing or invalid field throws immediately, preventing the service from starting with a broken config.
import { configuration } from '@riavzon/auth'
await configuration({
store: { /* ... */ },
password: { pepper: process.env.PEPPER! },
botDetector: { enableBotDetector: true },
htmlSanitizer: { IrritationCount: 50, maxAllowedInputLength: 50000 },
magic_links: { /* ... */ },
jwt: { /* ... */ },
email: { resend_key: process.env.RESEND_KEY!, email: '[email protected]' },
})
configuration() once before mounting any routes. The service reads the resolved config on every request: calling it more than once replaces the previous config globally.store
Database connection pools for the main application database and the rate-limiter store. Both pools accept any valid mysql2 PoolOptions object.
store: {
main: { host: 'localhost', user: 'root', password: 'secret', database: 'auth' },
rate_limiters_pool: {
store: { host: 'localhost', user: 'root', password: 'secret', database: 'auth_limiters' },
dbName: 'auth_limiters',
},
}
service
Runtime service settings for proxy trust, port binding, and optional HMAC inter-service authentication. This entire section is optional.
service is provided.300000 (5 minutes). Requests with a timestamp outside this window are rejected.X-Forwarded-* headers from the upstream proxy. Set to true when running behind a reverse proxy such as Nginx or Caddy.X-Forwarded-* headers from this IP are accepted.password
Controls Argon2id password hashing parameters. The pepper value is combined with the user's password before hashing: rotate it to invalidate all existing hashes.
50. Output hash length in bytes.4. Argon2 time cost (number of iterations). Higher values increase resistance to brute-force attacks at the cost of slower hashing.262144 (256 MiB). Memory usage in KiB. Higher values make GPU-based attacks more expensive.pepper in an environment variable or a secrets manager. Never commit it to version control.botDetector
Controls whether the Bot Detector module runs during authentication flows. When enabled, IP geolocation and device fingerprinting data feed directly into anomaly detection. This is a discriminated union keyed on enableBotDetector.
true to enable the Bot Detector middleware with active scoring and blocking. Set to false to switch to passive mode (see below).enableBotDetector is true. Optional custom configuration passed directly to the Bot Detector module. See the Bot Detector Configuration for the full reference.// Passive mode
botDetector: { enableBotDetector: false }
// Enabled with defaults
botDetector: { enableBotDetector: true }
// Enabled with custom settings
botDetector: {
enableBotDetector: true,
settings: { banScore: 75, checkers: { enableTorAnalysis: { enable: false } } },
}
Passive mode
Setting enableBotDetector to false does not shut the Bot Detector down. The middleware still runs and maintains its database connection, but it switches to a passive configuration that disables all active scoring:
- All 17 security checkers are disabled (IP checks, geo checks, TOR analysis, browser/device checks, session coherence, velocity fingerprinting, and so on).
maxScoreis raised from100to300, making it virtually impossible for any request to reach the ban threshold.restoredReputationPointsdrops from10to1, so scores heal much more slowly across requests.logLevelchanges frominfotowarn, reducing noise to only warnings.
The bot detector still tracks requests and maintains reputation data in the database. This means you can switch back to active mode at any time without losing historical context. Passive mode is useful during development, initial deployment, or when you want to observe traffic patterns before enforcing scoring rules.
htmlSanitizer
Controls the multi-pass XSS sanitization pipeline applied to all user-supplied strings before they reach the database. See XSS Protection for full details on the sanitization process.
50. Number of sanitization loop iterations. Each pass strips one layer of encoded or obfuscated HTML. Keep this high enough to catch layered obfuscation but not so high that it becomes a CPU exhaustion vector under load.50000. Maximum number of bytes accepted in a single input string. Inputs exceeding this length are rejected before sanitization begins.magic_links
Configuration for signed temporary JWT links used in email MFA and password-reset flows. See Magic Links and MFA for usage details.
"20m") or number of seconds (1200). Mutually exclusive with expiresInMs.expiresIn."https://localhost/accounts". The URL the user is redirected to when they click a password-reset magic link.thresholds
Each threshold object controls how many GET requests (page loads) and POST requests (form submissions) a user can make to a specific magic link flow before the service stops issuing new links.
5. Maximum page loads allowed for the adaptive MFA verification page.3. Maximum form submissions allowed for the adaptive MFA verification page.5. Maximum page loads for the password-reset verification page.3. Maximum form submissions for the password-reset verification page.5. Maximum page loads for custom MFA and email-change flows.3. Maximum form submissions for custom MFA and email-change flows.emailImages
URLs for images embedded in outgoing emails. All fields have default values pointing to the Riavzon media CDN.
paths
Route paths that magic link URLs resolve to on your frontend. All defaults point to /auth/bounce.
"/auth/bounce". Path used for custom MFA flow magic links."/auth/bounce". Path used for password-reset magic links."/auth/bounce". Path used for adaptive MFA magic links.notificationEmail
Branding and navigation links included in all system notification emails (login alerts, password-change alerts, etc.).
"Security Service". Display name shown in the email header and subject line.providers
Defines the OAuth social login providers the service accepts. Each entry maps an incoming OAuth profile to the internal user schema. This field is optional: omit it entirely if your application does not use social login.
Each provider is defined using one of two approaches:
Custom Zod schema: Full control over validation and transformation.
providers: [
{
name: 'github',
schema: z.object({
id: z.number(),
login: z.string(),
email: z.string().email(),
avatar_url: z.string().url(),
}),
},
]
Field-type map: A shorthand that builds the schema automatically from a record of field names to type tokens.
providers: [
{
name: 'google',
useStandardProfile: true,
fields: {
sub: 'string',
email: 'email',
name: 'safeString',
picture: 'url?',
},
},
]
FieldToken is one of: 'string', 'string?', 'email', 'email?', 'boolean', 'boolean?', 'url', 'url?', 'number', 'number?', 'int', 'int?', 'safeString', 'safeString?'. Append ? to mark a field optional.
See OAuth for a full provider definition example.
trustUserDeviceOnAuth
false. When true, a successful login marks the device as trusted and skips adaptive MFA when the canary cookie is missing on the next session. This reduces friction for users who log in from the same device frequently but weakens the anomaly detection layer.jwt
Controls both access token and refresh token behavior.
access_tokens
"15m") or number of seconds. Mutually exclusive with expiresInMs.expiresIn.HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512.aud claim set on every access token.iss claim set on every access token.sub claim set on every access token.refresh_tokens
"example.com") so the cookie is sent on all subdomains.See Tokens for full token lifecycle details.
email
Resend API credentials used for all outgoing system and MFA emails.
From address for all outgoing emails (e.g. "[email protected]"). This address must be verified in your Resend account.rate_limiters
Fine-grained rate-limiter configurations for every sensitive endpoint. This entire section is optional, and every individual limiter group within it is also optional. When the section or any group is omitted, the service falls back to built-in defaults. Rate limiting is always active. Every individual limiter within each group shares the same shape:
duration window.See Rate Limiting for detailed usage examples, union limiter patterns, and the full schema for each group.
linkVerificationLimiter
Protects /auth/verify-mfa and /auth/reset-password endpoints.
loginLimiters
Protects POST /login.
oauthLimiters
Protects POST /auth/OAuth/:providerName.
signupLimiters
Protects POST /signup.
tempPostRoutesLimiters
Protects temporary POST routes such as email update and custom MFA initiation.
tokenLimiters
Protects the /auth/user/refresh-session rotation route and the /auth/logout route.
initPasswordResetLimiters
Protects POST /auth/forgot-password.
emailMfaLimiters
Protects email MFA sending endpoints.
logLevel
'debug' during development to see detailed request processing. Set 'warn' or 'error' in production to reduce log volume.