Skip to content

Conversation

@brkalow
Copy link
Member

@brkalow brkalow commented Jan 15, 2026

Description

Adds Frontend API proxy support to clerkMiddleware for both Next.js and Express. This enables scenarios where direct communication with Clerk's API is blocked or needs to go through the application server.

API

Next.js

import { clerkMiddleware } from '@clerk/nextjs/server';

export default clerkMiddleware({
  // Enable proxy with defaults (path: '/__clerk')
  frontendApiProxy: {
    enabled: true,
  },
});

// Or with multi-domain support using a function
export default clerkMiddleware({
  frontendApiProxy: {
    enabled: (url) => url.hostname === 'app.example.com',
  },
});

// Custom proxy path
export default clerkMiddleware({
  frontendApiProxy: {
    enabled: true,
    path: '/custom-clerk-proxy',
  },
});

Express

import express from 'express';
import { clerkMiddleware } from '@clerk/express';

const app = express();

// Enable proxy with defaults (path: '/__clerk')
app.use(clerkMiddleware({ frontendApiProxy: { enabled: true } }));

// Custom proxy path
app.use(clerkMiddleware({ frontendApiProxy: { enabled: true, path: '/my-proxy' } }));

// Disable proxy
app.use(clerkMiddleware({ frontendApiProxy: { enabled: false } }));

Key Features

  • Embedded in clerkMiddleware: No separate middleware needed - proxy handling is built into clerkMiddleware
  • Auto-derived proxyUrl: The proxyUrl for handshake redirects is automatically derived from the frontendApiProxy config
  • Multi-domain support (Next.js): Use a function for enabled to conditionally enable proxy based on request URL
  • Streaming body support: Request and response bodies are streamed for efficient handling
  • Header rewriting: Redirect responses are automatically rewritten to use the proxy URL

Type of change

  • 🌟 New feature

Testing

  • Unit tests added for proxy functionality in both Next.js and Express
  • Tests cover: proxy path matching, proxyUrl derivation, multi-domain support, header handling

Summary by CodeRabbit

  • New Features

    • Frontend API proxy added across backend, Next.js, and Express with configurable proxy path, automatic proxy URL derivation, and App Router handler helpers.
  • Behavior

    • Proxy streams requests/responses, preserves queries/headers, manages X-Forwarded headers, strips hop-by-hop headers, and rewrites internal redirects.
  • Tests

    • Extensive tests for routing, header propagation, error handling, redirects, and multi-domain scenarios.
  • Documentation

    • Changeset documenting the Frontend API proxy feature.

…s, and @clerk/express

Implement clerkProxy helper that abstracts away the complexity of proxying Clerk's Frontend API (FAPI) requests. This enables scenarios where direct communication with Clerk's API is blocked or needs to go through the application server.

- Core proxy implementation in @clerk/backend/src/proxy.ts with environment-aware URL derivation
- Next.js integration via clerkMiddleware frontendApiProxy option and route handlers
- Express middleware for handling proxy requests with body streaming support
- FAPI URL constants added to @clerk/shared for environment detection

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@changeset-bot
Copy link

changeset-bot bot commented Jan 15, 2026

🦋 Changeset detected

Latest commit: f6f4ab3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 10 packages
Name Type
@clerk/backend Minor
@clerk/nextjs Minor
@clerk/express Minor
@clerk/agent-toolkit Patch
@clerk/astro Patch
@clerk/fastify Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Jan 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
clerk-js-sandbox Skipped Skipped Feb 10, 2026 4:03am

Request Review

- Add comprehensive tests for @clerk/backend/proxy including FAPI URL derivation, path matching, and request forwarding
- Add tests for @clerk/nextjs/proxy route handlers and exports
- Add tests for @clerk/express/proxy middleware and request conversion

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Next.js proxy tests mocked the underlying @clerk/backend/proxy,
making them essentially test that wrapper A calls function B - no real
behavior was verified. The backend proxy tests provide actual coverage.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@brkalow brkalow changed the title feat: Add Frontend API proxy helpers feat(backend): Add Frontend API proxy helpers Jan 15, 2026
Allow the `enabled` option in `frontendApiProxy` to accept a function
`(url: URL) => boolean` for conditional proxy based on the request URL.

This enables scenarios where an application has multiple domains and
only some require proxying (e.g., `foo.replit.app` proxied while
`foo.com` uses direct FAPI access).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add X-Forwarded-Host and X-Forwarded-Proto headers for proxy awareness
- Preserve existing X-Forwarded-* headers from upstream proxies
- Rewrite Location headers for FAPI redirects to go through the proxy
- Add tests for new header handling and redirect rewriting

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…t.js

- Remove separate @clerk/express/proxy entry point and middleware
- Embed proxy handling directly in Express clerkMiddleware
- Auto-derive proxyUrl from frontendApiProxy config for handshake redirects
- Add FrontendApiProxyOptions type with enabled and path options
- Align API structure between Express and Next.js SDKs
- Remove low-value constant tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change from defaulting enabled to true, to requiring explicit enabled: true
- Update tests to use enabled: true
- Update JSDoc to remove default annotation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes issue where paths like /__clerk-admin would incorrectly match
the /__clerk proxy path. Now requires either an exact match or a
trailing slash boundary.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ensures that proxy paths like /__clerk/ work correctly by stripping
trailing slashes before matching.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaces /\/+$/ regex with a simple while loop to avoid ReDoS
concerns flagged by GitHub Advanced Security code scanning.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@brkalow brkalow marked this pull request as ready for review February 9, 2026 17:21
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a Frontend API proxy feature across the monorepo: new backend proxy module (packages/backend/src/proxy.ts) with public exports and build/package manifests; new shared constants and types (DEFAULT_PROXY_PATH, LOCAL/STAGING/PROD_FAPI_URL, ShouldProxyFn); tsup and package.json updated to publish proxy artifacts; integration into Express and Next.js middleware with a request-to-Request conversion helper and auto-derivation of proxyUrl; Next.js App Router proxy handlers and re-exports; comprehensive unit tests and a changeset.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(backend): Add Frontend API proxy helpers' directly and accurately describes the main change - introducing a new proxy module for the backend that provides proxy helper functionality.
Docstring Coverage ✅ Passed Docstring coverage is 86.67% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/nextjs/src/proxy.ts`:
- Around line 66-72: The interface FrontendApiProxyHandlers is missing an
OPTIONS handler which will break CORS preflight requests; add an OPTIONS:
RouteHandler entry to the FrontendApiProxyHandlers interface and update
createFrontendApiProxyHandlers to include and return an OPTIONS handler that
forwards preflight requests (responds appropriately or proxies the OPTIONS
request to the upstream FAPI) so Next.js can handle CORS preflights—modify both
the FrontendApiProxyHandlers type and the createFrontendApiProxyHandlers
function to include the OPTIONS symbol consistently.

Comment on lines +66 to +72
export interface FrontendApiProxyHandlers {
GET: RouteHandler;
POST: RouteHandler;
PUT: RouteHandler;
DELETE: RouteHandler;
PATCH: RouteHandler;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing OPTIONS handler may break CORS preflight requests.

The FrontendApiProxyHandlers interface lacks an OPTIONS handler. If Clerk's FAPI responds to CORS preflight requests, clients making cross-origin requests to the proxy will fail because Next.js won't have a handler for the OPTIONS method.

Proposed fix
 export interface FrontendApiProxyHandlers {
   GET: RouteHandler;
   POST: RouteHandler;
   PUT: RouteHandler;
   DELETE: RouteHandler;
   PATCH: RouteHandler;
+  OPTIONS: RouteHandler;
 }

And update createFrontendApiProxyHandlers:

   return {
     GET: handler,
     POST: handler,
     PUT: handler,
     DELETE: handler,
     PATCH: handler,
+    OPTIONS: handler,
   };
🤖 Prompt for AI Agents
In `@packages/nextjs/src/proxy.ts` around lines 66 - 72, The interface
FrontendApiProxyHandlers is missing an OPTIONS handler which will break CORS
preflight requests; add an OPTIONS: RouteHandler entry to the
FrontendApiProxyHandlers interface and update createFrontendApiProxyHandlers to
include and return an OPTIONS handler that forwards preflight requests (responds
appropriately or proxies the OPTIONS request to the upstream FAPI) so Next.js
can handle CORS preflights—modify both the FrontendApiProxyHandlers type and the
createFrontendApiProxyHandlers function to include the OPTIONS symbol
consistently.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 9, 2026

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7602

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7602

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7602

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7602

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7602

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7602

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7602

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7602

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7602

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7602

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7602

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7602

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7602

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7602

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7602

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7602

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7602

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7602

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7602

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7602

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7602

commit: f6f4ab3

…g changeset

- Update exports snapshot to include new proxy exports (DEFAULT_PROXY_PATH, clerkFrontendApiProxy, createFrontendApiProxyHandlers)
- Fix proxyUrl test assertion to check for falsy value instead of key absence (handleMultiDomainAndProxy always returns proxyUrl: "")
- Add changeset for frontend API proxy feature

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/nextjs/src/server/index.ts`:
- Around line 78-87: Remove the new barrel re-exports from index.ts: delete the
export block that re-exports clerkFrontendApiProxy,
createFrontendApiProxyHandlers and the types FrontendApiProxyHandlers,
FrontendApiProxyOptions, NextFrontendApiProxyOptions; instead ensure
consumers/importers use the dedicated module path './proxy' directly (or add a
new explicit entrypoint file if needed) and update any internal imports to
reference './proxy' rather than the package root to avoid expanding the barrel
and preventing possible circular dependencies.

- Fix simple-import-sort lint errors in authenticateRequest.ts and utils.ts
- Clear authenticateRequestMock between tests to prevent stale call counts
  from causing `.not.toBeCalled()` assertions to fail in proxy tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@packages/express/src/authenticateRequest.ts`:
- Around line 132-136: The proxy path check in authenticateRequest.ts fails when
request.originalUrl contains a query string; update the proxy matching logic to
extract only the pathname (strip the query string) from request.originalUrl ||
request.url before comparing to proxyPath. In practice, compute a
requestPathName (or reuse request.path) that excludes the query string, then use
that value in the existing if checks that reference proxyEnabled, requestPath
(or requestPathName) and proxyPath (including the startsWith(proxyPath + '/')
check).
- Around line 176-188: The code that auto-derives proxyUrl when proxyEnabled and
!options.proxyUrl uses request.headers['x-forwarded-proto'] and
request.headers['x-forwarded-host'] directly, which fails for comma-separated
header chains; update the extraction in the resolvedOptions block (around
proxyEnabled, options.proxyUrl, resolvedOptions, derivedProxyUrl, proxyPath) to
split the header value on ',' and take the first item, trimming whitespace (e.g.
const protoHeader = Array.isArray(forwardedProto) ? forwardedProto[0] :
forwardedProto; const protoValue = (protoHeader || '').split(',')[0].trim(); and
same for host) before computing protocol, host and derivedProxyUrl so the first
forwarded value is used.

…aders

Split header values on ',' and take the first item to handle
multi-proxy chains (e.g. "https, http" or "app.example.com, proxy.example.com").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
request.originalUrl includes query parameters, causing proxy path matching
to fail for requests like /__clerk?_clerk_js_version=5.0.0. Parse the URL
to extract pathname before comparing, consistent with the backend's
matchProxyPath implementation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Removes trailing slashes from a string without using regex
* to avoid potential ReDoS concerns flagged by security scanners.
*/
function stripTrailingSlashes(str: string): string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] I think this might be duped

* Enable Frontend API proxy handling. When true, requests to the proxy path
* will be proxied to Clerk's Frontend API and the proxyUrl will be auto-derived.
*/
enabled?: boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] I think it would make sense to make this a required configuration value so it's easy to grok if the feature is on or off

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacekradko required if frontendApiProxy is present right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep

'@clerk/backend': minor
'@clerk/nextjs': minor
'@clerk/express': minor
---
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
---
'@clerk/shared': minor
---

Copy link
Member

@jacekradko jacekradko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just minor comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants