Files
skills/docs/identity/auth/oauth-client/src/utils/url-builder.md
2026-05-29 08:20:56 +01:00

4.1 KiB

url-builder

Purpose

Provides pure URL-building and body-encoding utilities used internally by all OAuth 2.0 grant flows. Keeping these helpers in a single module avoids duplication across the authorization-code, client-credentials, and token-refresh modules while keeping each flow module focused on business logic rather than HTTP serialization details.

These utilities are deliberately stateless and side-effect-free so they can be tested in complete isolation from network calls.

Features

  • buildAuthorizationUrl — constructs a complete authorization endpoint URL with PKCE, state, scopes, and optional OIDC parameters (nonce, prompt, login_hint).
  • buildTokenRequestBody — serializes a flat string record to application/x-www-form-urlencoded using encodeURIComponent.
  • normalizeTokenResponse — maps a raw token-endpoint JSON body to a TokenSet-compatible shape and derives expiresAt from expires_in.

Usage: Basic Example

import { buildAuthorizationUrl, buildTokenRequestBody } from "@suaveplan/oauth-client/utils/url-builder";

const url = buildAuthorizationUrl(
  { clientId: "my-app", authorizationUrl: "https://auth.example.com/authorize", tokenUrl: "…" },
  { state: "abc", codeChallenge: "xyz", codeChallengeMethod: "S256" },
);

const body = buildTokenRequestBody({
  grant_type: "authorization_code",
  code: "AUTH_CODE",
  redirect_uri: "https://app.example.com/callback",
  client_id: "my-app",
  code_verifier: "VERIFIER",
});

Usage: Advanced Example

import {
  buildAuthorizationUrl,
  normalizeTokenResponse,
} from "@suaveplan/oauth-client/utils/url-builder";

// OIDC authorization request with nonce and prompt
const url = buildAuthorizationUrl(
  {
    clientId: "my-app",
    authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
    tokenUrl: "https://oauth2.googleapis.com/token",
    redirectUri: "https://app.example.com/callback",
    scopes: ["openid", "profile", "email"],
  },
  {
    state: "state123",
    codeChallenge: "challenge456",
    codeChallengeMethod: "S256",
    nonce: "nonce789",
    prompt: "consent",
    loginHint: "user@example.com",
    extra: { access_type: "offline" },
  },
);

// Normalize raw token response
const raw = { access_token: "at", token_type: "Bearer", expires_in: 3600 };
const tokenSet = normalizeTokenResponse(raw, Date.now());
// tokenSet.expiresAt is set ~1 hour from now

API Reference

buildAuthorizationUrl(config, params): string

Builds a full authorization URL.

  • config — OAuthConfig providing clientId, authorizationUrl, optional redirectUri and scopes.
  • params.state — CSRF-protection state value.
  • params.codeChallenge — PKCE code challenge.
  • params.codeChallengeMethod — "S256" or "plain".
  • params.scope? — overrides config.scopes for this request.
  • params.nonce? — OIDC nonce.
  • params.prompt? — UI prompt hint.
  • params.loginHint? — pre-fill login hint.
  • params.extra? — additional query parameters.

buildTokenRequestBody(params: Record<string, string>): string

Returns a percent-encoded application/x-www-form-urlencoded string. Both keys and values are encoded with encodeURIComponent.

normalizeTokenResponse(raw: Record<string, unknown>, now: number): TokenSet

Maps a raw JSON body to { accessToken, tokenType, expiresIn?, expiresAt?, refreshToken?, idToken?, scope? }. The now parameter (milliseconds since epoch) is used to compute expiresAt = now + expiresIn * 1000.

Implementation Notes

buildAuthorizationUrl uses the platform URL constructor and URLSearchParams for correct percent-encoding of complex values. The URL constructor is universally available in all targeted runtimes (Node 10+, browsers, Bun, Deno, edge workers). buildTokenRequestBody uses encodeURIComponent directly rather than URLSearchParams to produce a simple string body that can be passed to fetch without additional wrappers. normalizeTokenResponse is intentionally defensive — it uses typeof guards rather than Zod for performance in hot paths, leaving schema validation to the caller.