Skip to content

Commit 78f01a3

Browse files
brkalowclaude
andcommitted
fix: Strip query string from Express proxy path matching
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>
1 parent 05d1fd5 commit 78f01a3

2 files changed

Lines changed: 28 additions & 1 deletion

File tree

packages/express/src/__tests__/clerkMiddleware.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
import type { Request, RequestHandler, Response } from 'express';
22
import { vi } from 'vitest';
33

4+
const { mockClerkFrontendApiProxy } = vi.hoisted(() => ({
5+
mockClerkFrontendApiProxy: vi.fn(),
6+
}));
7+
vi.mock('@clerk/backend/proxy', async () => {
8+
const actual = await vi.importActual('@clerk/backend/proxy');
9+
return {
10+
...actual,
11+
clerkFrontendApiProxy: mockClerkFrontendApiProxy,
12+
};
13+
});
14+
415
import { clerkMiddleware } from '../clerkMiddleware';
516
import { getAuth } from '../getAuth';
617
import { assertNoDebugHeaders, assertSignedOutDebugHeaders, runMiddleware, runMiddlewareOnPath } from './helpers';
@@ -116,6 +127,22 @@ describe('clerkMiddleware', () => {
116127
});
117128

118129
describe('Frontend API proxy handling', () => {
130+
beforeEach(() => {
131+
mockClerkFrontendApiProxy.mockReset();
132+
});
133+
134+
it('intercepts proxy path with query parameters', async () => {
135+
mockClerkFrontendApiProxy.mockResolvedValueOnce(new globalThis.Response('proxied', { status: 200 }));
136+
137+
const response = await runMiddlewareOnPath(
138+
clerkMiddleware({ frontendApiProxy: { enabled: true } }),
139+
'/__clerk?_clerk_js_version=5.0.0',
140+
{},
141+
).expect(200);
142+
143+
expect(mockClerkFrontendApiProxy).toHaveBeenCalled();
144+
});
145+
119146
it('authenticates default path when custom proxy path is set', async () => {
120147
// When using a custom path, the default /__clerk should be authenticated
121148
const response = await runMiddlewareOnPath(

packages/express/src/authenticateRequest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export const authenticateAndDecorateRequest = (options: ClerkMiddlewareOptions =
131131

132132
// Handle Frontend API proxy requests early, before authentication
133133
if (proxyEnabled) {
134-
const requestPath = request.originalUrl || request.url;
134+
const requestPath = new URL(request.originalUrl || request.url, `http://${request.headers.host}`).pathname;
135135
if (requestPath === proxyPath || requestPath.startsWith(proxyPath + '/')) {
136136
// Convert Express request to Fetch API Request
137137
const proxyRequest = requestToProxyRequest(request);

0 commit comments

Comments
 (0)