Base Routes
Like the default routes documented in Default Routes, @rapidrest/auth's route classes are abstract and carry no @Route decorator of their own — you subclass the Mongo/SQL variant that matches your project's datastore and add @Route(path) yourself. Nothing distinguishes them from any other route in your project at runtime.
Auth-flow routes
One per strategy. Each is GET/POST / behind @Auth([strategyName]), and returns an AuthResult on success.
| Class | Strategy | Config |
|---|---|---|
BaseAuthBasicRoute | BasicStrategy | @Config("auth") (JWT signing) |
BaseAuthFIDO2Route | FIDO2Strategy | @Config("auth:fido2") |
BaseAuthMFARoute | MFAStrategy | @Config("auth") |
BaseAuthOIDCRoute | OIDCStrategy | providerConfig: OIDCProvider — an abstract field you must supply, typically via your own @Config("auth:oidc") |
BaseAuthOTPRoute | OTPStrategy | @Config("auth") |
BaseAuthPasskeyRoute | PasskeyStrategy | @Config("auth:passkey") |
BaseAuthTOTPRoute | TOTPStrategy | @Config("auth") |
This is the exact class used by auth-server's Basic strategy route:
import { RouteDecorators } from "@rapidrest/service-core";
import { BaseAuthBasicRouteMongo } from "@rapidrest/auth/mongo";
const { ApiRoute } = RouteDecorators;
@ApiRoute("/auth/password")
export class AuthBasicRoute extends BaseAuthBasicRouteMongo {}
Every other auth-flow route in the table above follows the identical one-line pattern — swap in the matching Base*Mongo/Base*SQL class and a @Route/@ApiRoute path (see auth-server's src/mongo/routes/ for all seven side by side).
BaseAuthOIDCRoute needs a bit more for a second provider: your subclass supplies which one by overriding providerConfig, same as the single-provider case auth-server wires up. But BaseAuthOIDCRoute's login() method is hardcoded behind @Auth(["oauth"]), and every subclass that doesn't override login() inherits that exact decorator, metadata attached to the class that declares a method isn't re-evaluated per subclass. Left alone, a second provider's strategy would register under a different name internally but still be checked against the same "oauth" entry as the first, so whichever provider's strategy loaded last would silently win for both routes. Overriding strategyName alone doesn't fix that; you also need to override login() with a matching @Auth([...]), delegating to super.login(...) for the actual token issuance:
import { RouteDecorators, ObjectDecorators } from "@rapidrest/service-core";
import { BaseAuthOIDCRouteMongo } from "@rapidrest/auth/mongo";
import type { OIDCProvider } from "@rapidrest/auth";
import type { JWTUser } from "@rapidrest/core";
import type { HttpRequest, HttpResponse } from "@rapidrest/service-core";
const { Auth, Route, Request, Response } = RouteDecorators;
const { Config } = ObjectDecorators;
const AuthUser = RouteDecorators.User;
@Route("/auth/oidc/google")
export class AuthGoogleRoute extends BaseAuthOIDCRouteMongo {
protected strategyName = "google";
@Config("auth:oidc:google")
protected providerConfig: OIDCProvider = {
name: "google",
authorizationURL: "https://accounts.google.com/o/oauth2/v2/auth",
clientID: "...",
clientSecret: "...",
tokenURL: "https://oauth2.googleapis.com/token",
redirectURI: "https://my-api.example.com/auth/oidc/google",
protocol: "openid",
scope: ["openid", "email", "profile"],
};
@Auth(["google"])
public override async login(@AuthUser user: JWTUser, @Request req: HttpRequest, @Response res: HttpResponse) {
return super.login(user, req, res);
}
}
A single-provider setup, like auth-server's, doesn't need any of this: strategyName already defaults to "oauth", matching the base class's own login(), so there's nothing to override.
Data routes
| Class | Extends | What it does |
|---|---|---|
BaseUserRoute | CRUDRoute<User> | Standard CRUD over User. |
BaseAliasRoute | CRUDRoute<Alias> | Standard CRUD over Alias. |
BaseProfileRoute | CRUDRoute<Profile> | Standard CRUD over Profile. |
BaseSecretRoute | ModelRoute<Secret> | Full CRUD over Secret, plus registration ceremonies (see below). |
BaseUserRoute, BaseAliasRoute, and BaseProfileRoute are thin, unmodified subclasses of CRUDRoute — see that page for the full endpoint list.
BaseSecretRoute does more, since secrets need type-specific handling and must never leak their raw data:
| Endpoint | What it does |
|---|---|
GET /, GET /:id | Find secrets. data is stripped from every result. |
HEAD /, HEAD /:id | Count / exists. |
POST / | Create a secret. Behavior depends on type: password hashes data with argon2; totp generates/validates a Base32 TOTP secret and returns an otpauth:// provisioning URI (for QR-code enrollment) as data.uri instead of storing it; fido2/passkey verify a WebAuthn registration response against a session-stored challenge and replace data with the resulting credential; recovery-codes discards any client-supplied data, generates a fresh batch of codes, persists only their argon2 hashes, and returns the plaintext codes exactly once in the response (data.codes) — they can never be retrieved again afterward. |
DELETE /:id, DELETE / | Delete one secret (supports ?version=, ?purge=true) or truncate all secrets the caller can access. |
GET /passkey/register | Begins a WebAuthn passkey registration ceremony for the authenticated caller (401 if anonymous), excluding already-registered credentials. |
GET /fido2/register | Same, for FIDO2 hardware keys — a separate relying-party config from passkeys. |
import { RouteDecorators } from "@rapidrest/service-core";
import { BaseSecretRouteMongo } from "@rapidrest/auth/mongo";
const { ApiRoute } = RouteDecorators;
@ApiRoute("/secrets")
export class SecretRoute extends BaseSecretRouteMongo {}
Again taken directly from auth-server — UserRoute, AliasRoute, and ProfileRoute are the same one-liner with the matching class swapped in.
Session & Account Management
Six more base routes round out a login flow beyond the strategies and models above — issuing/refreshing tokens, self-service registration, step-up re-authentication, and account-level actions like "log out everywhere". All but BaseAuthLogoutRoute follow the same Mongo/SQL subclassing pattern as every other route family on this page.
| Class | HTTP | What it does |
|---|---|---|
BaseAccountRoute | GET/DELETE /:id, POST /:id/revokeSessions | Aggregates a user's account data (profile, aliases, secrets with data stripped) behind GET; DELETE removes the account and every associated alias/secret/profile; POST /:id/revokeSessions is the "log out everywhere" action — see Strategies → Security Features. :id accepts the literal me for the caller's own account. Requires @Auth(["jwt"]); revokeSessions also requires @RequiresElevation(60). |
BaseAuthDiscoverRoute | GET /?id= | Anonymous endpoint: given a claimed identifier, returns which sign-in methods (password, totp, passkey, fido2, obfuscated OTP contacts) are configured for it, so a sign-in UI can show only the methods that will work. Always returns the same shape whether or not the identifier resolves to a real account, to resist enumeration. |
BaseAuthElevationRoute | GET /, POST / | Issues a short-lived elevated token after the already-authenticated caller re-proves their identity with one more factor — their own enrolled fido2/otp/totp method (GET lists which are available), or their password if none is enrolled. Backs @RequiresElevation-gated routes such as BaseSecretRoute and BaseAccountRoute.revokeSessions(). Requires @Auth(["jwt"]) and session. |
BaseAuthLogoutRoute | POST / | Clears the authentication cookie (if cookie-based token issuance is enabled) and the session-bound refresh token. Model-agnostic — imported straight from @rapidrest/auth with no Mongo/SQL variant, since logging out doesn't touch any persisted model. Always succeeds, even for a caller that was never issued a cookie. |
BaseAuthRefreshRoute | GET /, POST / | Exchanges a valid refresh token (request body, or the refresh cookie) for a fresh access/refresh pair, via the same AuthResult shape every auth-flow route returns. Rejects a token issued before the account's last revokeSessions() call. |
BaseRegistrationRoute | POST /start, POST /verify | Self-service account creation: POST /start sends an OTP code to a claimed e-mail or phone number; POST /verify checks the code and, on success, creates a new User + verified Alias and returns an elevated AuthResult (elevated so the new account can immediately register MFA secrets without a separate elevation round-trip). |
This is the exact set of classes auth-server wires up (src/mongo/routes/, mirrored under src/sql/routes/):
import { RouteDecorators } from "@rapidrest/service-core";
import { BaseAccountRouteMongo } from "@rapidrest/auth/mongo";
const { ApiRoute } = RouteDecorators;
@ApiRoute("/accounts")
export class AccountRoute extends BaseAccountRouteMongo {}
BaseAuthDiscoverRoute, BaseAuthElevationRoute, and BaseAuthRefreshRoute follow the identical one-line pattern (@ApiRoute("/auth/discover"), @ApiRoute("/auth/elevation"), @ApiRoute("/auth/refresh") respectively), and BaseRegistrationRoute the same at @ApiRoute("/register"). BaseAuthLogoutRoute is the one exception to the Mongo/SQL naming pattern in this table, since it takes no model type parameters:
import { RouteDecorators } from "@rapidrest/service-core";
import { BaseAuthLogoutRoute } from "@rapidrest/auth";
const { ApiRoute } = RouteDecorators;
@ApiRoute("/auth/logout")
export class AuthLogoutRoute extends BaseAuthLogoutRoute {}