Skip to content

Commit f69d94d

Browse files
Update middleware combination example to prevent unintended backend execution (#2076)
1 parent ae064cb commit f69d94d

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

EXAMPLES.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,13 @@ By default, the middleware does not protect any pages. It is used to mount the a
786786

787787
You can combine multiple middleware, like so:
788788

789+
> [!WARNING]
790+
> **Handling `x-middleware-next` Header**
791+
> The `auth0.middleware` response (`authResponse`) might contain an `x-middleware-next` header. This header signals to Next.js that the request should be forwarded to the backend application, regardless of the status code of the response you construct.
792+
>
793+
> When combining middleware, **do not** copy the `x-middleware-next` header from `authResponse` to your final response if your custom middleware intends to block the request (e.g., by returning a `NextResponse.json` with a 401 status, or a `NextResponse.redirect`). Copying this header in such cases will cause Next.js to still execute the backend route handler despite your middleware attempting to block access. Only copy headers that are necessary, like `set-cookie`.
794+
795+
789796
```ts
790797
export async function middleware(request: NextRequest) {
791798
const authResponse = await auth0.middleware(request)
@@ -797,9 +804,14 @@ export async function middleware(request: NextRequest) {
797804

798805
// call any other middleware here
799806
const someOtherResponse = await someOtherMiddleware(request)
807+
const shouldProceed = someOtherResponse.headers.get('x-middleware-next');
800808

801809
// add any headers from the auth middleware to the response
802810
for (const [key, value] of authResponse.headers) {
811+
// Only copy 'x-middleware-next' if the custom middleware response intends to proceed.
812+
if (key.toLowerCase() === 'x-middleware-next' && !shouldProceed) {
813+
continue; // Skip copying this header if we are blocking/redirecting
814+
}
803815
someOtherResponse.headers.set(key, value)
804816
}
805817

examples/with-next-intl/middleware.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,25 @@ export async function middleware(request: NextRequest) {
1717
// call any other middleware here
1818
const intlRes = intlMiddleware(request)
1919

20-
// add any headers from auth to the response
20+
// Combine headers from authResponse (from auth0.middleware) and intlRes (from intlMiddleware).
21+
// If authResponse contains 'x-middleware-next' (signaling Next.js to proceed to the page),
22+
// but intlRes is a response that should terminate the request chain (like a redirect or an error),
23+
// we must NOT copy 'x-middleware-next' from authResponse. Doing so would override
24+
// intlRes's decision to stop the request.
2125
for (const [key, value] of authResponse.headers) {
22-
intlRes.headers.set(key, value)
26+
if (key.toLowerCase() === 'x-middleware-next') {
27+
// Check if intlRes is a redirect (3xx status code) or an error (4xx, 5xx status code).
28+
const isIntlResponseTerminating = intlRes.status >= 300;
29+
if (isIntlResponseTerminating) {
30+
// If intlRes is already redirecting or returning an error,
31+
// do not copy 'x-middleware-next' from authResponse.
32+
// This allows intlRes's redirect/error to take effect.
33+
continue;
34+
}
35+
}
36+
// For all other headers, or if 'x-middleware-next' can be safely copied,
37+
// set them on intlRes. This ensures session cookies from authResponse are preserved.
38+
intlRes.headers.set(key, value);
2339
}
2440

2541
return intlRes

0 commit comments

Comments
 (0)