Skip to main content

Strategies

@rapidrest/auth ships seven AuthStrategy implementations. Each registers itself against AuthMiddleware under a name, and that name is what you pass to @Auth([...]) on a route — the same mechanism Authentication already documents for JWTStrategy.

Session requirement

FIDO2Strategy, PasskeyStrategy, OIDCStrategy, OTPStrategy, and MFAStrategy all need session configured — they store challenge/state between the first and second request of a login flow. BasicStrategy and TOTPStrategy don't, since they verify in a single request. See Configuration and HTTP Engine → Sessions for how the underlying session system works.

BasicStrategy (basic)

Simple ID and password authentication via the Authorization: Basic header, JSON body, or form-encoded body. Verifies against a stored Secret of type PASSWORD (argon2-hashed).

FIDO2Strategy (fido2)

Hardware security key authentication (e.g. YubiKey) using WebAuthn/CTAP2. Configured via @Config("auth:fido2"), defaulting to authenticatorAttachment: "cross-platform" and non-discoverable credentials. Two-phase: a challenge step generates and stores WebAuthn assertion options, a verify step validates the signed assertion and enforces signature-counter monotonicity to detect cloned authenticators.

PasskeyStrategy (passkey)

The same WebAuthn protocol as FIDO2Strategy, but for synced/software passkeys rather than hardware keys — supports a discoverable, "usernameless" flow. Configured via @Config("auth:passkey").

TOTPStrategy (totp)

RFC 6238 Time-Based One-Time Password (Google Authenticator, Authy, 1Password, etc.). Payload is {id, token}, checked against every TOTP secret registered to that user.

OTPStrategy (otp)

Password-less login: a one-time code is sent to a verified contact (email or SMS, via MessagingUtils) and the user submits it back. Three phases: optional discovery (obfuscated contact list for a given ID, off by default via allowDiscovery), challenge (send the code), and verify.

MFAStrategy (mfa)

Composable two-factor authentication: ID and password as the first factor, then a second factor chosen from fido2, otp, recovery-code, or totp. require2FA (default true) controls whether users with no registered second factor are rejected outright.

class MFAStrategyOptions {
require2FA = true;
fidoConfig?: PasskeyConfig; // required if fido2 is offered as a second factor
encryptionKey?: string; // decrypts a TOTP secret at rest before verifying — see Security Features below
}

A recovery-code factor (MFAMethodType.RECOVERY_CODE) verifies against a recovery-codes Secret — see BaseSecretRoute's recovery-codes endpoint for how the codes are generated. Each submitted code is checked against every unused entry's argon2 hash; a match is single-use — MFAStrategyOptions.consumeRecoveryCode() must be implemented to mark it spent, otherwise a verified code stays valid indefinitely. Unlike fido2/otp/totp, recovery codes are intentionally excluded from @RequiresElevation step-up (see Security Features below) — they're a break-glass mechanism for being locked out at login, not a routine step-up credential.

OIDCStrategy (default name oauth, configurable)

A generic OAuth 2.0 / OpenID Connect client — not a set of vendor-specific presets. There's no built-in GoogleStrategy or GitHubStrategy; instead, you configure any OAuth2/OIDC-compliant provider via an OIDCProvider object:

interface OIDCProvider {
name: string;
authorizationURL: string;
clientID: string;
clientSecret: string;
tokenURL: string;
redirectURI: string | string[]; // exact-match enforced
scope: string[];
protocol: 'oauth2' | 'openid';
profileURL?: string; // OAuth2 profile fetch
jwksURI?: string; // required for OpenID id_token verification
issuer?: string; // required for OpenID id_token verification
pkce?: boolean | 'S256' | 'plain';
profileMap?: Record<string, string>; // merged over the default field mapping
}

Each route subclass registers its strategy under a name (BaseAuthOIDCRoute.strategyName, defaulting to "oauth"), so you can register multiple providers concurrently under different names, e.g. "google" and "github", each behind its own @Auth([...])-protected route. See Base Routes → Auth-flow routes for the extra override a second provider needs beyond just picking a name.

Implements PKCE (S256/plain), CSRF-protected state, OpenID nonce replay protection, and id_token signature verification via jwks-rsa when jwksURI/issuer are set. On first login from a given provider identity, a local User + Profile (+ Alias records for the provider ID and any verified email/phone) is created automatically.

Security Features

Beyond the login strategies above, @rapidrest/auth ships a handful of account-security mechanisms that apply across every strategy:

FeatureMechanism
Step-up re-authentication@RequiresElevation(seconds) (from @rapidrest/service-core) gates a route behind a recently-issued elevated JWT. BaseAuthElevationRoute re-verifies the caller with one additional factor — their enrolled fido2/otp/totp method, or their password if none is enrolled — and mints a short-lived elevated token. BaseSecretRoute's create/update/delete endpoints and BaseAccountRoute.revokeSessions() are elevation-gated out of the box.
Session revocation ("log out everywhere")BaseAccountRoute.revokeSessions() stamps User.sessionsRevokedAt = Date.now(). BaseAuthRefreshRoute rejects any refresh token whose iat predates that timestamp, so every device is forced to sign in again. This does not invalidate an already-issued access token, which remains valid until its own short natural expiry — there's no server-side access-token revocation list.
Rate limitingRateLimiter throttles every credential-verification endpoint (BasicStrategy, MFAStrategy's password/challenge/verify phases, OTPStrategy, registration, account discovery) with two independent sliding-window counters: one keyed on the claimed identifier (default 5 attempts / 300s) and a more permissive one keyed on source IP (default 100 attempts / 300s, reverse-proxy aware via trusted_proxies). Backed by Redis when a cache datastore is configured (shared across instances), an in-memory store otherwise. Configure via @Config("auth:rateLimit").
TOTP secret encryption at restOptional. Set TOTPConfig.encryption_key (a 64-character hex string, i.e. 32 bytes) and every newly written TOTPSecret.secret is encrypted with AES-256-GCM (fresh random IV per call, stored as "enc:v1:" + base64(iv || authTag || ciphertext)) before it's persisted. Decryption happens transparently on verify and on the one-time setup response. Omit the key to keep storing secrets as plaintext (the default) — a value already stored as plaintext keeps verifying correctly with no migration step if you turn encryption on later.
MFA recovery codesSecretType.RECOVERY_CODES — see the recovery-code factor above and BaseSecretRoute for how a batch is generated and returned exactly once.

@RequiresElevation, rate limiting, and session revocation are all events-instrumented (AuthEventType.ELEVATED, RATELIMIT_EXCEEDED, SESSIONS_REVOKED, MFA_ENROLLED/MFA_REMOVED) via EventUtils.record(), so they show up wherever your project already collects telemetry.