next-api-layerNext API Layer
DocumentationAPI ReferenceExamples
next-api-layerNext API Layer

Production-grade API layer for Next.js with external JWT backends.

Documentation

  • Introduction
  • Installation
  • Quick Start
  • API Reference

Resources

  • Examples
  • Proxy
  • API Client
  • AuthProvider

Community

  • GitHub
  • Issues
  • Discussions
  • Contact

© 2026 Next API Layer. All rights reserved.

Created by
Documentation

Getting Started

  • Introduction
  • Installation
  • Quick Start

Core Concepts

  • How It Works
  • Token Management
  • Guest Tokens

Configuration

  • Auth Proxy
  • Proxy Handler
  • API Client
  • Security
  • i18n Integration

Client Side

  • AuthProvider
  • useAuth Hook

API Reference

  • API Reference
  • Types

Examples

  • Examples
  • Authentication Patterns
  • Role-Based Access
  • API Routes
  • Forms
  • Data Fetching
Changelog

Getting Started

  • Introduction
  • Installation
  • Quick Start

Core Concepts

  • How It Works
  • Token Management
  • Guest Tokens

Configuration

  • Auth Proxy
  • Proxy Handler
  • API Client
  • Security
  • i18n Integration

Client Side

  • AuthProvider
  • useAuth Hook

API Reference

  • API Reference
  • Types

Examples

  • Examples
  • Authentication Patterns
  • Role-Based Access
  • API Routes
  • Forms
  • Data Fetching
Changelog

Changelog

All notable changes to next-api-layer are documented here.


v0.4.0 - July 16, 2026#

A token refresh & session-lifecycle release for backends that rotate jti server-side and detect refresh-token reuse (RFC 9700). Every feature is opt-in and backward compatible — with no new configuration, behaviour is identical to 0.3.0.

Added#

  • Concurrent refresh single-flight (refresh.singleFlight, default true): Parallel requests (navigation + SWR polling + RSC fetches) that hit an expired token are coalesced into a single auth/refresh call; the rest await its result. This eliminates the orphan/bounce that server-side jti rotation causes under concurrency. Guaranteed within a single runtime instance. Set false to disable.
  • Refresh-failure reasons + refresh.onRefreshFail hook: A failed refresh is classified as 'expired' | 'revoked' | 'reuse' | 'network' | 'unknown' (RefreshResult.reason), and refresh.onRefreshFail(reason, req) fires for security telemetry / client notifications. Defaults: 409 or a body { code: 'token_reuse' } → reuse; 401 → expired; 403 → revoked; transport error → network. Configurable via refresh.reuseStatusCodes, refresh.reuseCodes, and a custom refresh.classifyFail.
  • Reuse-aware fail-closed (RFC 9700): A detected token reuse never silently downgrades to a guest session — it clears all auth cookies and redirects to login (or 401 for API routes) and emits an auth:reuse audit event. A new auth:refresh:fail audit event is emitted for other failures.
  • access.guestFallbackOnUserRefreshFail (default true): When false, a failed user refresh never downgrades to a guest token on any route (always a terminal login / 401). The fail-closed switch for admin panels.
  • Proactive (pre-expiry) refresh (refresh.proactive, refresh.proactiveWindow): Optionally renew a still-valid token when it is within proactiveWindow seconds (default 120) of expiry instead of waiting for a 401. Best-effort: on failure the still-valid token keeps working (a detected reuse stays terminal).
  • Local JWT validation (validate.mode: 'local'): Verify the token's signature + exp in the proxy instead of calling auth/me every request, restoring stateless auth. Built-in HMAC (HS256/HS384/HS512) via the Web Crypto API (no dependencies) with validate.secret / validate.algorithms; supply validate.verify for RS256 / JWKS (e.g. jose). Optional validate.revalidateInterval re-checks the backend every N seconds (revocation / allowlist). Defaults to mode: 'backend' (unchanged).
  • Dual-token mode (OAuth2 access + refresh): Set cookies.refresh (and optional cookies.refreshOptions, e.g. path: '/api/auth/refresh') to run a short-lived access token plus a separate, long-lived refresh token that is only sent to the refresh endpoint and rotates on use (parseNewRefreshToken mapper).
  • New exported types: RefreshConfig, ValidateConfig, RefreshFailReason, RefreshFailContext.

Notes#

  • No breaking changes. getTokenInfo / refreshToken keep their existing signatures; all new behaviour is gated behind new opt-in config.
  • Single-flight and local verification act per runtime instance; across separate serverless/edge isolates, concurrent requests may still trigger independent refreshes — pair with idempotent refresh handling on the backend for full coverage.

v0.3.0 - June 17, 2026#

A security-hardening release that closes vulnerabilities across the CSRF layer, the middleware header pipeline, the response sanitizer, the rate limiter, and the proxy error path. Read the Breaking Changes before upgrading.

Security#

  • CSRF tokens are now cryptographically verified (token forgery fixed): The double-submit strategy previously accepted any request whose cookie and header values matched, so an attacker able to plant a cookie on a sibling subdomain could forge a valid pair. Tokens are now HMAC-SHA256 signed (<hmac>.<randomValue>) and the signature is verified on every state-changing request. Forged or tampered tokens are rejected with invalid-token-signature.
  • Constant-time CSRF comparisons: Cookie/header equality and HMAC verification both use a constant-time comparison to remove timing side-channels.
  • Insecure randomness fallback removed (fail-closed): CSRF token and secret generation now require the Web Crypto API and throw if it is unavailable, instead of silently falling back to Math.random(). An insecure token can never be issued.
  • Spoofed internal headers stripped (auth impersonation fixed): Inbound requests carrying x-auth-user, x-refreshed-token, or x-locale could previously impersonate an authenticated user or override the resolved locale. These internal headers are now stripped from every incoming request before the proxy sets its own verified values — on all paths (pass-through, refresh, valid-token, excluded, auth-API) — and before the upstream backend fetch.
  • i18n middleware can no longer bypass an auth redirect (redirect-precedence): When the auth layer produced a terminal response (e.g. a redirect to /login for a protected route, or a 401 JSON), a subsequent i18n next() / rewrite() could discard it and serve the protected page. Terminal auth responses now win over i18n forwards; only the i18n cookies (e.g. NEXT_LOCALE) are carried over.
  • Allow-list sanitizer XSS bypass fixed: In mode: 'allowList', dangerous attributes on otherwise-allowed tags (inline event handlers like onerror, style, and javascript: / data: URLs in href / src) were passed through. Attributes on allow-listed tags are now sanitized, and data: / dangerous-URL detection was broadened.
  • Rate-limit prefetch bypass narrowed: skipPrefetch previously skipped the limiter for any method carrying a prefetch header, so an attacker could evade rate limiting on POST (etc.) by adding Next-Router-Prefetch. Prefetch skipping is now restricted to safe (GET / HEAD) methods.
  • Proxy error responses no longer leak internals: The 502 path no longer returns error.message to the client; it logs the error server-side ([Proxy Error]) and returns a generic message.
  • CSRF secret hygiene warning: When CSRF is enabled without an explicit csrf.secret, the library now logs a warning and uses a per-process ephemeral secret (tokens will not validate across instances/restarts until you set one).

Breaking Changes#

  • createCsrfValidator is now fully async. validateRequest(), generateToken(), and attachCsrfCookie() return promises. If you call the validator directly, you must await the results:

    DIFF
    Loading...

    Using createAuthProxy requires no change — it already awaits internally.

  • CSRF token format changed to <hmac>.<randomValue>. Tokens minted by 0.2.x are not valid in 0.3.0 and vice-versa. Deploy all instances together; clients receive a fresh token automatically on their next safe request, so no user action is required.

  • Web Crypto is now required for CSRF. crypto.subtle and crypto.getRandomValues must be available (Node.js 18+ or any Edge runtime). The library throws a clear error instead of degrading to insecure randomness.

  • Set csrf.secret explicitly in production. Without it, tokens are signed with a per-process random secret and will fail to validate across multiple instances or after a restart.

Migration#

No code changes are required if you use createAuthProxy — it awaits the CSRF validator internally. If you call createCsrfValidator directly, add await to validateRequest(), generateToken(), and attachCsrfCookie(). In production, set a stable csrf.secret (e.g. from an environment variable) so signed tokens validate across instances and restarts.


v0.2.5 - June 8, 2026#

Fixed#

  • useAuth redirected during render: When useAuth received redirectTo / redirectIfFound — and therefore useRequireAuth and useRedirectIfAuth — it called router.replace() synchronously in the render body. On React 18/19 this threw Cannot update a component (Router) while rendering a different component. Navigation now runs inside a useEffect, firing after commit instead of during render.
  • useRequireAuth threw during render: It called throw new Error('Authentication required') in the render phase, which aborted the component before its redirect effect could commit. The throw was removed; the hook now relies on the effect-driven redirect. Guard your UI on isLoading / isAuthenticated while the redirect settles.

v0.2.4 - June 3, 2026#

Fixed#

  • Rate limiter double-counting bug: createAuthProxy invoked rateLimiter.check() twice per request — once at the gate and again when applying the X-RateLimit-* response headers. Every request was counted twice, effectively halving the configured limit (e.g. a limit of 100 behaved like 50). The check result is now computed once and reused for both gating and header application.

Added#

  • skipPrefetch option (RateLimitConfig.skipPrefetch, default true): Next.js <Link> prefetch requests no longer consume rate-limit tokens. Prefetches are detected via next-router-prefetch, sec-purpose, purpose/x-purpose, and x-moz headers. Set to false to count them.
  • ipHeaders option (RateLimitConfig.ipHeaders): Configure the ordered list of headers used to resolve the real client IP for rate-limit keying. Defaults to ['cf-connecting-ip', 'true-client-ip', 'x-real-ip', 'x-forwarded-for'], adding first-class Cloudflare / proxy support. The x-forwarded-for value correctly uses the first (client) hop.
  • New exported helpers:
    • getClientIp(req, headerPriority?) — resolve the real client IP behind proxies and CDNs.
    • isPrefetchRequest(req) — detect Next.js prefetch requests.
    • DEFAULT_IP_HEADERS — the default IP header priority list.

Notes#

  • The built-in rate limiter remains in-memory (per-instance). For multi-instance / serverless deployments that need a shared counter, a pluggable Redis-backed store is planned for a future release (it requires an async store API and is intentionally deferred to avoid a breaking change).

Migration#

No code changes required. The double-count fix means your real effective limit now matches the configured value — if you previously compensated by doubling your max, you can restore it to the intended number.


v0.2.3 - April 20, 2026#

Fixed#

  • Sanitization over-escaping bug: Plain text characters (/, ', `, =) were being HTML-escaped to entities like &#x2F;, &#x27;, &#x3D;, which corrupted user-facing text in React/Vue/Angular apps (e.g. O'Reilly's Books appeared as O&#x27;Reilly&#x27;s Books). Modern frameworks already escape text at render time, so API-level entity escaping is redundant and harmful.

Changed#

  • Default mode is now 'strip' (was 'escape'). Removes HTML tags while preserving plain text characters. Matches the philosophy of DOMPurify and sanitize-html: operate at the tag level, not the character level.
  • escape mode char set minimized to the OWASP minimum: only <, >, &, " are escaped. Apostrophes, slashes, backticks, and equals signs pass through unchanged (safe in text content; double-quoted HTML attributes make ' safe too).
  • strip mode now only removes well-formed tags (<letter...> / </letter...>). Bare <, >, & characters in text like 5 < 10 and 20 > 3 are preserved.
  • SanitizationConfig.mode added as a public, documented option: 'strip' | 'escape' | 'allowList'.

Migration#

No code changes required for most apps — the new defaults produce safer, cleaner output. If you explicitly set mode: 'escape' and relied on the old aggressive char set, tag injection (<script>, <img onerror>, etc.) is still blocked, but /, ', `, = now pass through. This is the correct behavior for data bound to React/Vue/Angular text nodes.

Before / After#

TypeScript
Loading...

v0.2.2 - April 17, 2026#

Added#

  • Enhanced Debug Body Logging: Smart request/response body logging with DX-focused features

    • logRequestBody - Log request payloads separately (default: false)
    • logResponseBody - Log response data separately (default: false)
    • maxStringLength - Per-field string truncation (default: 500)
    • maxArrayItems - Array item limit with "... and N more" indicator (default: 10)
    • maxDepth - Object nesting depth limit (default: 5)
    • autoMask - Enable/disable sensitive field masking (default: true)
    • sensitiveFields - Customize which fields to mask (password, token, secret, cvv, etc.)
  • Smart Binary Detection: Automatically detects and summarizes binary-like data

    • Base64 strings shown as [base64, 45KB]
    • Data URLs shown as [data URL (image/png), 2.3MB]
    • Prevents terminal spam from large payloads
  • Enhanced FormData Logging: Better visibility for file uploads

    • File info: [File: photo.jpg, 2.4MB, image/jpeg]
    • Sensitive fields masked in FormData
    • Field count with "... and N more fields" indicator

Changed#

  • logBody deprecated in favor of logRequestBody/logResponseBody (still works for backward compatibility)
  • bodyPreviewLength deprecated in favor of maxStringLength (still works for backward compatibility)

Example#

TypeScript
Loading...
Terminal
Loading...

v0.2.1 - April 16, 2026#

Fixed#

  • URL field sanitization: URL values in API payloads are now preserved correctly
    • Previously: https://example.com → https&#x2F;&#x2F;example.com
    • Now: URLs with safe protocols (https, http, mailto, tel, ftp) are preserved
    • Relative paths (/callback) are also preserved
    • XSS vectors (javascript:, data:) are still sanitized

Improved#

  • Documentation sync: Fixed mismatches between docs and TypeScript types
    • errorMessages keys corrected: connectionError, serverError, timeout, noToken
    • methodSpoofing object config with fieldName option documented
    • swrConfig full SWRConfiguration support noted
Terminal
Loading...

v0.2.0 - April 15, 2026#

Added#

  • Typed Error Classes: New error hierarchy for better error handling

    • ApiError - Base error class with code and timestamp
    • HttpError - HTTP errors with status code and statusText
    • TimeoutError - Request timeout errors with endpoint and timeout info
    • NetworkError - Network failures with cause tracking
    • AuthError - Authentication errors with reason (no_token, invalid_token, expired_token)
    • ValidationError - Validation errors with field-level error messages
    • RateLimitError - Rate limit errors with retryAfter, limit, remaining info
    • Type guards: isApiError(), isHttpError(), isTimeoutError(), isNetworkError(), isAuthError(), isRateLimitError()
    • Utilities: isRetryableStatus(), isRetryableError()
  • Retry Logic: Automatic retry for failed requests

    • createApiClient({ retry: { enabled: true, maxAttempts: 3 } })
    • Backoff strategies: 'exponential', 'linear', 'fixed'
    • Configurable retry conditions: status codes, network errors
    • Per-request override: api.get('/endpoint', { retry: false })
  • Debug Mode: Development logging for requests/responses

    • createApiClient({ debug: { enabled: true } })
    • Log requests, responses, timing, headers, body preview
    • Custom logger support
  • Request Deduplication: Prevent duplicate in-flight requests

    • createApiClient({ dedupe: { enabled: true, methods: ['GET'] } })
    • Automatically returns same promise for identical concurrent requests
  • Request ID / Correlation: Request tracing headers

    • createApiClient({ requestId: { enabled: true } })
    • Custom header name and generator support
  • Next.js 16+ Support: Documentation and examples now support both:

    • proxy.ts with export const proxy = authProxy (Next.js 16+)
    • middleware.ts with export default authProxy (Next.js 14-15)

Changed#

  • BREAKING: methodSpoofing config: Now accepts boolean | MethodSpoofingConfig
  • CLI: Uses native Node.js readline/promises - zero runtime dependencies
  • CLI: New questions for protected routes and auth routes

Removed#

  • prompts dependency: CLI now uses native Node.js APIs

Migration from v0.1.x#

  1. If using methodSpoofing as object - no changes needed
  2. CLI - regenerate config with npx next-api-layer init (optional)
Terminal
Loading...

v0.1.11 - April 13, 2026#

Fixed#

  • Non-ASCII characters in x-auth-user header: User data with Turkish (ğ, ş, ı, ö, ü, ç), German (ä, ö, ü, ß), or other non-ASCII characters now works correctly
    • HTTP headers only support ISO-8859-1 (0-255), characters like ğ (287) caused TypeError: Cannot convert argument to a ByteString
    • User data is now Base64 encoded in proxy and decoded in getServerUser()
    • This is an internal change - no API changes required

Migration from v0.1.10#

No breaking changes. Simply update your package:

Terminal
Loading...

v0.1.10 - April 10, 2026#

Fixed#

  • login/register success detection: login() and register() functions now correctly return success: true when API responds with success
    • Previously returned success: false when response didn't include user data
    • Now checks res.ok && json.success !== false instead of relying on user data presence
    • User data is now optional - if not in response, library fetches from /me endpoint

Added#

  • parseAuthResponse prop: New optional prop for custom login/register response parsing
    • Allows handling non-standard backend auth response formats
    • Example: parseAuthResponse={(json) => ({ success: json.ok, user: json.result?.user })}
  • AuthResponseParsed type: Exported from next-api-layer/client for TypeScript users

Migration from v0.1.9#

No breaking changes. Simply update your package:

Terminal
Loading...

v0.1.9 - April 10, 2026#

Fixed#

  • i18n route matching: protectedRoutes, authRoutes, and publicRoutes now correctly work with localePrefix: 'always'
    • Routes like /tr/login are now properly matched against config /login
    • Locale prefix is automatically stripped before route matching
    • Works with any locale configured in i18n.locales

Added#

  • New stripLocale() utility function exported from next-api-layer/proxy
    • Strips locale prefix from pathname for custom route comparisons

Migration from v0.1.8#

No breaking changes. Simply update your package:

Terminal
Loading...

v0.1.8 - April 9, 2026#

Fixed#

  • x-locale header loss: Fixed issue where x-locale header was lost when using i18n.middleware option
    • Header is now set as response header instead of request header
    • Ensures locale is available in server components via headers().get('x-locale')

Migration from v0.1.7#

No breaking changes. Simply update your package:

Terminal
Loading...

v0.1.7 - April 8, 2026#

Added#

  • i18n Middleware Integration: New middleware option in I18nConfig for seamless integration with next-intl and similar libraries
    • Library calls your i18n middleware internally and merges responses automatically
    • Preserves critical headers (x-locale, x-auth-user, x-refreshed-token) across middleware chain
    • No more losing locale headers when using custom middleware hooks

Fixed#

  • Header preservation: afterAuth hook no longer loses library-set headers when calling external middleware functions

Example Usage#

TypeScript
Loading...

Migration from v0.1.6#

No breaking changes. To use the new middleware integration, add the middleware option to your i18n config.


v0.1.6 - April 7, 2026#

Added#

  • Per-request sanitization control: New options in RequestOptions for fine-grained sanitization control
    • skipSanitize: boolean - Skip all sanitization for a specific request
    • skipSanitizeFields: string[] - Skip sanitization for specific fields only
  • patch() method now accepts RequestOptions parameter (was missing)

Example Usage#

TypeScript
Loading...

Migration from v0.1.5#

No breaking changes. Simply update your package:

Terminal
Loading...

v0.1.5 - April 4, 2026#

Added#

  • i18n Support: Automatic locale detection and injection for API requests
    • Added i18n config option to createAuthProxy for locale detection from URL path
    • Added i18n config option to createApiClient for auto-appending ?lang={locale} to requests
    • New x-locale header for passing locale from middleware to route handlers
    • Configurable paramName (default: lang), locales, and defaultLocale

Changed#

  • HEADERS constant now includes LOCALE: 'x-locale'
  • Proxy handlers now extract locale from URL pathname and set x-locale header
  • API client reads x-locale header and appends locale query parameter to backend requests

Migration from v0.1.4#

No breaking changes. To enable i18n, add the config:

TypeScript
Loading...

v0.1.4 - April 1, 2026#

Fixed#

  • Empty cookie creation bug: Fixed an issue where cookies.delete() was called on non-existent cookies, causing empty-value cookies to be set in the browser. Now all delete operations check for cookie existence before attempting deletion.

Added#

  • New safeDeleteCookie helper function that only deletes cookies that actually exist in the request.
  • Updated deleteAllAuthCookies to accept req parameter for cookie existence checking.

Changed#

  • All cookie delete operations now verify cookie existence before deletion to prevent phantom cookies.

Migration from v0.1.3#

No breaking changes. Simply update your package:

Terminal
Loading...

v0.1.3 - March 20, 2026#

Added#

  • Initial stable release with proxy and API client functionality
  • Guest token support with automatic creation
  • Token validation and refresh mechanisms
  • Rate limiting support
  • CSRF protection
  • Audit logging capabilities
  • next-intl integration support

Features#

  • createAuthProxy - Main proxy function for Next.js
  • createApiClient - Server-side API client
  • createProxyHandler - Flexible proxy handler for route handlers
  • useAuth - Client-side auth hook
  • AuthProvider - React context provider
  • getServerUser - Server-side user helper