oauth
js/security/oauth.ts
fino:security/oauth - OAuth/OIDC client helpers for application middleware.
Useful references:
- OAuth 2.1 draft: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1
- PKCE: https://www.rfc-editor.org/rfc/rfc7636
- Authorization server metadata: https://www.rfc-editor.org/rfc/rfc8414
- OpenID Connect Core: https://openid.net/specs/openid-connect-core-1_0.html
This module implements the application-client side of OAuth: PKCE material, authorization URLs, code exchange, refresh, sealed-cookie login state, and JWT bearer validation. It is not an identity provider and intentionally does not implement opaque-token introspection, DPoP, mTLS, device code, or dynamic client registration.
import { oauthLogin, oauthCallback } from 'fino:security/oauth';
const provider = {
authorizationEndpoint: 'https://issuer.example/authorize',
tokenEndpoint: 'https://issuer.example/token',
clientId: 'client',
redirectUri: 'https://app.example/callback',
};
Interfaces
interface OAuthProvider {
Static client configuration for one OAuth or OpenID Connect provider.
Properties
authorizationEndpoint: string
Authorization endpoint used to start the browser redirect flow.
tokenEndpoint: string
Token endpoint used for authorization-code and refresh-token grants.
clientId: string
Client identifier registered with the provider.
clientSecret?: string
Optional confidential-client secret. Public PKCE clients omit this.
redirectUri: string
Redirect URI registered with the provider and sent during code exchange.
interface OAuthDiscoveryOptions {
Options for OAuth/OIDC discovery requests.
Properties
fetch?: typeof fetch
Fetch implementation used to load provider metadata.
interface PkceMaterial {
PKCE verifier and challenge pair for an authorization-code flow.
Properties
verifier: string
High-entropy verifier retained server-side until the callback.
challenge: string
Base64url SHA-256 challenge sent to the authorization endpoint.
method: 'S256'
PKCE challenge method. Fino currently emits only S256.
interface PkceOptions {
Options for createPkce().
Properties
verifier?: string
Optional verifier to validate and derive instead of generating one.
interface AuthorizationUrlOptions {
Inputs used to build an authorization-code redirect URL.
Properties
authorizationEndpoint: string
Provider authorization endpoint.
clientId: string
Client identifier registered with the provider.
redirectUri: string
Redirect URI that will receive the callback.
scope?: string | readonly string[]
Optional scopes, either pre-joined or supplied as individual tokens.
state: string
CSRF token that must match on callback.
nonce?: string
Optional OIDC nonce to bind an ID token to this login attempt.
codeChallenge: string
PKCE S256 challenge derived from the retained verifier.
interface ExchangeAuthorizationCodeOptions {
Options for exchanging an authorization code.
Properties
provider: OAuthProvider
Provider configuration that supplies the token endpoint and client id.
code: string
Authorization code received from the callback request.
codeVerifier: string
PKCE verifier originally paired with the authorization redirect.
fetch?: typeof fetch
Fetch implementation used to call the provider token endpoint.
interface RefreshAccessTokenOptions {
Options for refreshing a provider access token.
Properties
provider: OAuthProvider
Provider configuration that supplies the token endpoint and client id.
refreshToken: string
Refresh token previously issued by the provider.
fetch?: typeof fetch
Fetch implementation used to call the provider token endpoint.
interface OAuthLoginOptions {
Options for oauthLogin().
Properties
provider: OAuthProvider
Provider configuration for redirect URL construction.
secret: BufferLike
Cookie sealing secret used to protect state, nonce, and verifier data.
scope?: string | readonly string[]
Optional scopes requested from the provider.
cookie?: string
Transaction cookie name. Defaults to fino_oauth.
cookieOptions?: CookieOptions
Additional attributes for the transaction cookie.
state?: string
Optional fixed state value, mostly useful for tests.
nonce?: string
Optional fixed OIDC nonce, mostly useful for tests.
codeVerifier?: string
Optional fixed PKCE verifier, mostly useful for tests.
maxAgeSeconds?: number
Transaction lifetime in seconds. Defaults to 600.
interface OAuthCallbackResult {
Result passed to an OAuth callback success hook.
Properties
tokens: Record<string, unknown>
Token response returned by the provider.
transaction: Record<string, unknown>
Unsealed transaction state saved by oauthLogin().
interface OAuthCallbackOptions {
Options for oauthCallback().
Properties
provider: OAuthProvider
Provider configuration for token exchange.
secret: BufferLike
Cookie sealing secret used to unseal transaction data.
cookie?: string
Transaction cookie name. Defaults to fino_oauth.
cookieOptions?: CookieOptions
Additional attributes used when clearing the transaction cookie.
fetch?: typeof fetch
Fetch implementation used to call the provider token endpoint.
onSuccess?: (result: OAuthCallbackResult) => Response | Promise<Response>
Optional hook that builds the final response after token exchange.
Types
type OAuthMetadata = Record<string, unknown> & {
authorization_endpoint?: string;
token_endpoint?: string;
jwks_uri?: string;
issuer?: string;
}
Provider metadata returned by OAuth/OIDC discovery endpoints.
Functions
async function discoverOAuthMetadata(
issuer: string | URL,
options: OAuthDiscoveryOptions = {
}
): Promise<OAuthMetadata>
Fetch RFC 8414 OAuth authorization-server metadata for an issuer URL.
The issuer is resolved against /.well-known/oauth-authorization-server.
Non-success HTTP responses reject with an error that includes the response
status code.
async function discoverOpenIdProvider(
issuer: string | URL,
options: OAuthDiscoveryOptions = {
}
): Promise<OAuthMetadata>
Fetch OpenID Provider metadata for an issuer URL.
The issuer is resolved against /.well-known/openid-configuration. The
returned object is intentionally loose because providers commonly include
extension metadata alongside the standard OIDC fields.
async function createPkce(options: PkceOptions = {}): Promise<PkceMaterial>
Create RFC 7636 S256 PKCE verifier and challenge material.
Generated verifiers use 32 random bytes encoded as base64url. Supplied verifiers must satisfy the RFC 7636 character set and 43-128 character length constraints.
function authorizationUrl(options: AuthorizationUrlOptions): URL
Build an OAuth authorization-code redirect URL with PKCE parameters.
The returned URL includes response_type=code, the provided state, and an
S256 PKCE challenge. The function only constructs the URL; callers remain
responsible for storing the verifier until callback handling.
async function exchangeAuthorizationCode(
options: ExchangeAuthorizationCodeOptions
): Promise<Record<string, unknown>>
Exchange an authorization code for provider tokens.
The request uses the authorization_code grant and
application/x-www-form-urlencoded body encoding. Confidential clients send
client_secret when provider.clientSecret is present.
async function refreshAccessToken(
options: RefreshAccessTokenOptions
): Promise<Record<string, unknown>>
Refresh an access token with a refresh token.
The request uses the refresh_token grant and returns the provider's token
response as a plain record so provider-specific fields are preserved.
function oauthLogin(options: OAuthLoginOptions)
Create a login handler that redirects to the provider authorization URL.
The handler stores OAuth transaction state in a sealed HTTP-only cookie and
returns a 302 response with a Location header pointing at the provider.
function oauthCallback(options: OAuthCallbackOptions)
Create a callback handler that validates sealed state and exchanges code.
The returned handler rejects missing parameters, state mismatches, expired
transactions, and malformed transaction cookies with 400 responses. On
success it clears the transaction cookie and returns either onSuccess()
or a JSON response containing the provider tokens.
async function verifyIdToken(token: string, keys: JwtKeyInput, options: JwtVerifyOptions = {})
Verify an OIDC ID token using the existing JWT/JWKS verifier.
The helper defaults typ to JWT/jwt and otherwise forwards options to
jwtVerify(), including issuer, audience, algorithm, and clock settings.
async function verifyBearerJwt(
header: string | null,
keys: JwtKeyInput,
options: JwtVerifyOptions = {
}
)
Verify an HTTP Authorization: Bearer <jwt> header.
Missing or non-bearer headers reject before JWT verification. The returned
value is the decoded verification result from jwtVerify().
function bearerAuth(keys: JwtKeyInput, options: JwtVerifyOptions = {})
App middleware that validates a JWT bearer token and stores it on ctx.user.
The middleware returns 401 Unauthorized when verification fails. On
success it writes the verified JWT result to ctx.user and calls next().