AuthService
The AuthService contains the server-side core logic of the authentication system: it orchestrates the providers, encrypts/decrypts the JWE session tokens, and syncs the authenticated server context. It is registered by the AuthModule and available via dependency injection; the AuthController is a thin HTTP layer over it.
import { AuthService, USER_CLAIM } from '@archibald/auth';
USER_CLAIM ('user') is the token claim holding the (filtered) user object; each provider's tokens are stored under a claim named after the provider.
Flow methods
Each flow method returns a LoginResult<User, State> ({ token, tokenExpiresAt, refresh, refreshExpiresAt, user, redirectUrl?, state?, exception? }) — on failure the token is cleared and exception is set instead of throwing.
| Method | Description |
|---|---|
login(credentials) | Password login: UserAuthProvider.login() → system providers → loadUser → sign & set tokens. Claims are stamped authProtocol: 'password'. |
token(credentials) | OIDC code exchange (native flow): identical pipeline via UserAuthProvider.token(), claims stamped authProtocol: 'oidc'. |
loginUrl() | Returns { loginUrl } from UserAuthProvider.loginUrl() — the IdP authorize URL (web OIDC flow, step 1). |
redirectCallback() | Handles the IdP redirect: UserAuthProvider.redirectCallback() → system providers → loadUser → sign & set tokens → returns redirectUrl. |
refresh(refreshToken) | Refreshes the session. Concurrent calls for the same refresh token are de-duplicated; the original authProtocol is preserved, so password- and OIDC-sessions refresh identically. |
logout() | No arguments (since v9 — tokens come from the request context). Logs out all system providers, then the user provider with both access and refresh token. Returns { isLoggedOut }. |
check(token?) | Boolean logged-in check for the current request. |
loadUser() / getUser() | Loads the user through the UserAuthProvider API. |
Lifecycle hooks
loginSuccess(result), loginError(exception, result?), refreshSuccess, refreshError, redirectCallbackSuccess, redirectCallbackError — each delegates to the same-named hook on the UserAuthProvider when implemented. The default success shaping: header strategy returns { token, tokenExpiresAt, refresh, refreshExpiresAt, user }; cookie strategy returns only { user } (tokens never leave the server).
Token handling
Session tokens are JWE (encrypted, not just signed): alg: 'dir', enc: 'A256GCM', key derived from the configured secret — which therefore must be exactly 32 characters. The payload is the claim map built by TokenPayload plus sub ('login' or 'refresh'), iat, exp, and iss (= app.canonicalBaseUrl, validated on decrypt). Optional raw-deflate compression via the token.compress option.
| Method | Description |
|---|---|
getToken(type?) | Reads the current request's token — type is 'token' (default) or 'refreshToken'. Cookie strategy: from the nct/ncr cookie; header strategy: from Authorization: Bearer …. Prefers freshly renewed tokens from session.artifacts. |
decodeToken(token?) | Decrypts and validates. Returns the payload, { exp: 0 } for an expired token (distinguishable from a broken one), or null. |
isTokenValid(decoded) | true when the decoded payload's exp is in the future. |
checkSignAndSetToken(payloads, subject, options?) | Signs the token payloads into JWE tokens and calls syncAuthenticatedContext() — flips the server context to authenticated and, in the cookie strategy, sets the nct/ncr cookies. |
clearToken() | Clears the session tokens/cookies. |
getCookieOptions(type) | Cookie options for 'token' or 'refresh', from the module options plus computed expires. |
getAuthHeaders() | Auth headers for outgoing backend requests based on the current session. |
Secret rotation: when token.secret_rotation / refresh.secret_rotation is configured, decryption transparently retries with the rotation secret, allowing zero-downtime secret changes.
Provider management
| Method | Description |
|---|---|
registerProvider(provider) / registerProviders(providers) | Called by the AuthModule during startup. |
getProviders() / getStaticProviders() | Access registered providers. |
initializeProviders() | Runs each provider's initialize() (on server start, in server context). |
refreshStatic() / getStaticClaim() | Re-acquire / read static (guest) provider tokens. |
Options & defaults
AuthService.options are the resolved AuthModule options, deep-merged over these defaults:
{
strategy: { type: 'cookie' },
token: {
expirationTime: '5m', secret: '', secret_rotation: '', compress: false,
filter: (user) => user,
cookie: { expiresIn: '10m', sameSite: 'lax' }
},
refresh: {
expirationTime: '1y', secret: '', secret_rotation: '',
cookie: { expiresIn: '1y', sameSite: 'lax' }
}
}
token.filter controls which user fields are embedded in the token (DefaultTokenUser — keep it small; the full user is loaded through the API when needed).
Errors
Exported error classes thrown/returned by the service and providers: CredentialsInvalidError, TokenMissingError, TokenCreationError, TokenDecryptionError, TokenInvalidError, UserUnauthorizedError, ClaimMissingError, RedirectUrlMissingError, MultipleProviderError.
Relates to
AuthModule— registers this service, the controller, routes, and Hapi auth strategies.getSession()— read the authenticated session anywhere in the backend.- Secure Token Handling — conceptual view of the token lifecycle.