From 8c6633092ad8815af8dfb419783a39b4ff67f05b Mon Sep 17 00:00:00 2001 From: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com> Date: Wed, 22 Oct 2025 21:07:39 -0700 Subject: [PATCH 1/2] feat: Allow reading proto and host for proxied requests from a custom header --- .changeset/clever-wombats-look.md | 5 +++ .../src/tokens/__tests__/clerkRequest.test.ts | 31 +++++++++++++++++++ packages/backend/src/tokens/clerkRequest.ts | 14 +++++++-- 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 .changeset/clever-wombats-look.md 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..d132cfebd59 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; From 69383d8c0b19e47a77b1cde911d9c8fb21aaeb51 Mon Sep 17 00:00:00 2001 From: "Alessandro (Ale) Segala" <43508+ItalyPaleAle@users.noreply.github.com> Date: Wed, 22 Oct 2025 21:16:11 -0700 Subject: [PATCH 2/2] Update packages/backend/src/tokens/clerkRequest.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- packages/backend/src/tokens/clerkRequest.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/tokens/clerkRequest.ts b/packages/backend/src/tokens/clerkRequest.ts index d132cfebd59..215b1b54dae 100644 --- a/packages/backend/src/tokens/clerkRequest.ts +++ b/packages/backend/src/tokens/clerkRequest.ts @@ -53,10 +53,10 @@ class ClerkRequest extends Request { // 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, + 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, + process.env.CLERK_PROXY_FORWARDED_HOST_HEADER || constants.Headers.ForwardedHost, ); const host = req.headers.get(constants.Headers.Host);