Skip to content

feat(backend): Add Frontend API proxy helpers#7602

Draft
brkalow wants to merge 15 commits intomainfrom
brkalow/clerk-proxy-helper
Draft

feat(backend): Add Frontend API proxy helpers#7602
brkalow wants to merge 15 commits intomainfrom
brkalow/clerk-proxy-helper

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

…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

⚠️ No Changeset found

Latest commit: 7752813

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a 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.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Feb 3, 2026 4:40am

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>
export function matchProxyPath(request: Request, options?: Pick<FrontendApiProxyOptions, 'proxyPath'>): boolean {
const proxyPath = options?.proxyPath || DEFAULT_PROXY_PATH;
const url = new URL(request.url);
return url.pathname.startsWith(proxyPath);
Copy link
Member

Choose a reason for hiding this comment

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

Should we check for an exact match or a / boundary here? startsWith alone means something like /__clerk-admin would incorrectly match the default /__clerk prefix.

return url.pathname === proxyPath || url.pathname.startsWith(proxyPath + '/');

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>
Express types these headers as string | string[] | undefined.
Take the first element when they're arrays to avoid malformed URLs.

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

- Remove @clerk/nextjs/proxy subpath export
- Re-export proxy functions from @clerk/nextjs/server
- Update JSDoc examples to use new import path

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

2 participants