From d7c98af561f669fe670666e8c71afd7c677f21cd Mon Sep 17 00:00:00 2001 From: guillaume Date: Fri, 17 Oct 2025 16:06:45 +0100 Subject: [PATCH 1/3] fix(tanstack-react-start): do not consume the body of the request in middleware --- .changeset/full-horses-repair.md | 5 +++++ .../tanstack-react-start/src/server/clerkMiddleware.ts | 9 +++++---- .../tanstack-react-start/src/server/loadOptions.ts | 10 ++++------ 3 files changed, 14 insertions(+), 10 deletions(-) create mode 100644 .changeset/full-horses-repair.md diff --git a/.changeset/full-horses-repair.md b/.changeset/full-horses-repair.md new file mode 100644 index 00000000000..f174cded80d --- /dev/null +++ b/.changeset/full-horses-repair.md @@ -0,0 +1,5 @@ +--- +'@clerk/tanstack-react-start': patch +--- + +fix bug where the clerkMiddleware would consume the body of the request diff --git a/packages/tanstack-react-start/src/server/clerkMiddleware.ts b/packages/tanstack-react-start/src/server/clerkMiddleware.ts index ecd6d140200..dd4c77d97e3 100644 --- a/packages/tanstack-react-start/src/server/clerkMiddleware.ts +++ b/packages/tanstack-react-start/src/server/clerkMiddleware.ts @@ -1,5 +1,5 @@ import type { RequestState } from '@clerk/backend/internal'; -import { AuthStatus, constants } from '@clerk/backend/internal'; +import { AuthStatus, constants, createClerkRequest } from '@clerk/backend/internal'; import { handleNetlifyCacheInDevInstance } from '@clerk/shared/netlifyCacheHandler'; import type { PendingSessionOptions } from '@clerk/types'; import type { AnyRequestMiddleware } from '@tanstack/react-start'; @@ -8,12 +8,13 @@ import { createMiddleware, json } from '@tanstack/react-start'; import { clerkClient } from './clerkClient'; import { loadOptions } from './loadOptions'; import type { ClerkMiddlewareOptions } from './types'; -import { getResponseClerkState } from './utils'; +import { getResponseClerkState, patchRequest } from './utils'; export const clerkMiddleware = (options?: ClerkMiddlewareOptions): AnyRequestMiddleware => { return createMiddleware().server(async args => { - const loadedOptions = loadOptions(args.request, options); - const requestState = await clerkClient().authenticateRequest(args.request, { + const clerkRequest = createClerkRequest(patchRequest(args.request)); + const loadedOptions = loadOptions(clerkRequest, options); + const requestState = await clerkClient().authenticateRequest(clerkRequest, { ...loadedOptions, acceptsToken: 'any', }); diff --git a/packages/tanstack-react-start/src/server/loadOptions.ts b/packages/tanstack-react-start/src/server/loadOptions.ts index cbf1e4e984b..be9abaf358d 100644 --- a/packages/tanstack-react-start/src/server/loadOptions.ts +++ b/packages/tanstack-react-start/src/server/loadOptions.ts @@ -1,4 +1,4 @@ -import { createClerkRequest } from '@clerk/backend/internal'; +import { ClerkRequest } from '@clerk/backend/internal'; import { apiUrlFromPublishableKey } from '@clerk/shared/apiUrlFromPublishableKey'; import { getEnvVariable } from '@clerk/shared/getEnvVariable'; import { isDevelopmentFromSecretKey } from '@clerk/shared/keys'; @@ -9,18 +9,16 @@ import { errorThrower } from '../utils'; import { getPublicEnvVariables } from '../utils/env'; import { commonEnvs } from './constants'; import type { LoaderOptions } from './types'; -import { patchRequest } from './utils'; -export const loadOptions = (request: Request, overrides: LoaderOptions = {}) => { - const clerkRequest = createClerkRequest(patchRequest(request)); +export const loadOptions = (clerkRequest: ClerkRequest, overrides: LoaderOptions = {}) => { const commonEnv = commonEnvs(); const secretKey = overrides.secretKey || commonEnv.SECRET_KEY; const machineSecretKey = overrides.machineSecretKey || commonEnv.MACHINE_SECRET_KEY; const publishableKey = overrides.publishableKey || commonEnv.PUBLISHABLE_KEY; const jwtKey = overrides.jwtKey || commonEnv.CLERK_JWT_KEY; const apiUrl = getEnvVariable('CLERK_API_URL') || apiUrlFromPublishableKey(publishableKey); - const domain = handleValueOrFn(overrides.domain, new URL(request.url)) || commonEnv.DOMAIN; - const isSatellite = handleValueOrFn(overrides.isSatellite, new URL(request.url)) || commonEnv.IS_SATELLITE; + const domain = handleValueOrFn(overrides.domain, new URL(clerkRequest.url)) || commonEnv.DOMAIN; + const isSatellite = handleValueOrFn(overrides.isSatellite, new URL(clerkRequest.url)) || commonEnv.IS_SATELLITE; const relativeOrAbsoluteProxyUrl = handleValueOrFn(overrides?.proxyUrl, clerkRequest.clerkUrl, commonEnv.PROXY_URL); const signInUrl = overrides.signInUrl || commonEnv.SIGN_IN_URL; const signUpUrl = overrides.signUpUrl || commonEnv.SIGN_UP_URL; From 8d757fc0b2279709bf23c3a4f43205931c05a8ba Mon Sep 17 00:00:00 2001 From: Robert Soriano Date: Fri, 17 Oct 2025 13:49:35 -0700 Subject: [PATCH 2/3] chore: update changeset --- .changeset/full-horses-repair.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/full-horses-repair.md b/.changeset/full-horses-repair.md index f174cded80d..ec0bcc7937c 100644 --- a/.changeset/full-horses-repair.md +++ b/.changeset/full-horses-repair.md @@ -2,4 +2,4 @@ '@clerk/tanstack-react-start': patch --- -fix bug where the clerkMiddleware would consume the body of the request +Fixed a bug where the `clerkMiddleware()` helper would consume the body of the request From 17377b3fe0bf5d611404dc07a809fd05ebe06276 Mon Sep 17 00:00:00 2001 From: Robert Soriano Date: Fri, 17 Oct 2025 13:51:02 -0700 Subject: [PATCH 3/3] chore: format --- .../tanstack-react-start/src/server/loadOptions.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/tanstack-react-start/src/server/loadOptions.ts b/packages/tanstack-react-start/src/server/loadOptions.ts index be9abaf358d..55a72e028ab 100644 --- a/packages/tanstack-react-start/src/server/loadOptions.ts +++ b/packages/tanstack-react-start/src/server/loadOptions.ts @@ -1,4 +1,4 @@ -import { ClerkRequest } from '@clerk/backend/internal'; +import type { ClerkRequest } from '@clerk/backend/internal'; import { apiUrlFromPublishableKey } from '@clerk/shared/apiUrlFromPublishableKey'; import { getEnvVariable } from '@clerk/shared/getEnvVariable'; import { isDevelopmentFromSecretKey } from '@clerk/shared/keys'; @@ -10,16 +10,16 @@ import { getPublicEnvVariables } from '../utils/env'; import { commonEnvs } from './constants'; import type { LoaderOptions } from './types'; -export const loadOptions = (clerkRequest: ClerkRequest, overrides: LoaderOptions = {}) => { +export const loadOptions = (request: ClerkRequest, overrides: LoaderOptions = {}) => { const commonEnv = commonEnvs(); const secretKey = overrides.secretKey || commonEnv.SECRET_KEY; const machineSecretKey = overrides.machineSecretKey || commonEnv.MACHINE_SECRET_KEY; const publishableKey = overrides.publishableKey || commonEnv.PUBLISHABLE_KEY; const jwtKey = overrides.jwtKey || commonEnv.CLERK_JWT_KEY; const apiUrl = getEnvVariable('CLERK_API_URL') || apiUrlFromPublishableKey(publishableKey); - const domain = handleValueOrFn(overrides.domain, new URL(clerkRequest.url)) || commonEnv.DOMAIN; - const isSatellite = handleValueOrFn(overrides.isSatellite, new URL(clerkRequest.url)) || commonEnv.IS_SATELLITE; - const relativeOrAbsoluteProxyUrl = handleValueOrFn(overrides?.proxyUrl, clerkRequest.clerkUrl, commonEnv.PROXY_URL); + const domain = handleValueOrFn(overrides.domain, new URL(request.url)) || commonEnv.DOMAIN; + const isSatellite = handleValueOrFn(overrides.isSatellite, new URL(request.url)) || commonEnv.IS_SATELLITE; + const relativeOrAbsoluteProxyUrl = handleValueOrFn(overrides?.proxyUrl, request.clerkUrl, commonEnv.PROXY_URL); const signInUrl = overrides.signInUrl || commonEnv.SIGN_IN_URL; const signUpUrl = overrides.signUpUrl || commonEnv.SIGN_UP_URL; const afterSignInUrl = overrides.afterSignInUrl || getPublicEnvVariables().afterSignInUrl; @@ -27,7 +27,7 @@ export const loadOptions = (clerkRequest: ClerkRequest, overrides: LoaderOptions let proxyUrl; if (!!relativeOrAbsoluteProxyUrl && isProxyUrlRelative(relativeOrAbsoluteProxyUrl)) { - proxyUrl = new URL(relativeOrAbsoluteProxyUrl, clerkRequest.clerkUrl).toString(); + proxyUrl = new URL(relativeOrAbsoluteProxyUrl, request.clerkUrl).toString(); } else { proxyUrl = relativeOrAbsoluteProxyUrl; }