oauth

js/security/oauth.ts

fino:security/oauth - OAuth/OIDC client helpers for application middleware.

Useful references:

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().