diff --git a/.changeset/clever-wombats-look.md b/.changeset/clever-wombats-look.md new file mode 100644 index 00000000000..034612d6fdd --- /dev/null +++ b/.changeset/clever-wombats-look.md @@ -0,0 +1,5 @@ +--- +'@clerk/backend': minor +--- + +Allow reading proto and host for proxied requests from a custom header besides X-Forwarded-Proto and X-Forwarded-Host diff --git a/packages/backend/src/tokens/__tests__/clerkRequest.test.ts b/packages/backend/src/tokens/__tests__/clerkRequest.test.ts index 9582d70a1fb..3990bcc8ce7 100644 --- a/packages/backend/src/tokens/__tests__/clerkRequest.test.ts +++ b/packages/backend/src/tokens/__tests__/clerkRequest.test.ts @@ -99,6 +99,37 @@ describe('createClerkRequest', () => { expect(createClerkRequest(req).clerkUrl.toString()).toBe('https://example.com/path'); }); + it('with forwarded proto / host headers overridden via env vars', () => { + const originalForwardedProto = process.env.CLERK_PROXY_FORWARDED_PROTO_HEADER; + const originalForwardedHost = process.env.CLERK_PROXY_FORWARDED_HOST_HEADER; + + process.env.CLERK_PROXY_FORWARDED_PROTO_HEADER = 'x-my-forwarded-proto'; + process.env.CLERK_PROXY_FORWARDED_HOST_HEADER = 'x-my-forwarded-host'; + + const req = new Request('http://localhost:3000/path', { + headers: { + 'x-my-forwarded-host': 'example.com', + 'x-my-forwarded-proto': 'https', + }, + }); + + try { + expect(createClerkRequest(req).clerkUrl.toString()).toBe('https://example.com/path'); + } finally { + if (originalForwardedProto === undefined) { + delete process.env.CLERK_PROXY_FORWARDED_PROTO_HEADER; + } else { + process.env.CLERK_PROXY_FORWARDED_PROTO_HEADER = originalForwardedProto; + } + + if (originalForwardedHost === undefined) { + delete process.env.CLERK_PROXY_FORWARDED_HOST_HEADER; + } else { + process.env.CLERK_PROXY_FORWARDED_HOST_HEADER = originalForwardedHost; + } + } + }); + it('with path in request', () => { const req = new Request('http://localhost:3000/path'); expect(createClerkRequest(req).clerkUrl.toString()).toBe('http://localhost:3000/path'); diff --git a/packages/backend/src/tokens/clerkRequest.ts b/packages/backend/src/tokens/clerkRequest.ts index 9eef0a6c117..215b1b54dae 100644 --- a/packages/backend/src/tokens/clerkRequest.ts +++ b/packages/backend/src/tokens/clerkRequest.ts @@ -47,8 +47,18 @@ class ClerkRequest extends Request { */ private deriveUrlFromHeaders(req: Request) { const initialUrl = new URL(req.url); - const forwardedProto = req.headers.get(constants.Headers.ForwardedProto); - const forwardedHost = req.headers.get(constants.Headers.ForwardedHost); + + // When Clerk is served behind a proxy, it determines the protocol and host of the request + // by looking at the request headers. + // The default values are "X-Forwarded-Proto" and "X-Forwarded-Host" respectively, but the + // header names can be overwritten via env vars. + const forwardedProto = req.headers.get( + process.env.CLERK_PROXY_FORWARDED_PROTO_HEADER || constants.Headers.ForwardedProto, + ); + const forwardedHost = req.headers.get( + process.env.CLERK_PROXY_FORWARDED_HOST_HEADER || constants.Headers.ForwardedHost, + ); + const host = req.headers.get(constants.Headers.Host); const protocol = initialUrl.protocol;