I'm attempting to make a middleware for making API calls to a separate server but failing to make a redirect/rewrite. Paths which starts with /api/proxy
should be written without that prefix and route to the API server.
I'm using NextJS v.15.1.4, NextAuth 5.0.0-beta.25 and @rescale/nemo 1.4 for combining (future) middlewares.
My middleware.ts looks like this at the moment:
import { NextResponse } from "next/server";
import { cookies } from 'next/headers';
import { createMiddleware, type MiddlewareFunctionProps } from '@rescale/nemo'
import { auth } from 'auth';
const globalMiddlewares = {
before: async ({ request }: MiddlewareFunctionProps) => {
if (!request.url.includes("api/auth")) {
return;
}
auth()
},
};
const middlewares = {
"/api/proxy/*segments": [
async ({ request, response, context, event, forward, params }: MiddlewareFunctionProps) => {
const sessionCookieName = process.env.NODE_ENV === "development"
? "authjs.session-token"
: "__Secure-next-auth.session-token";
const cookieStore = await cookies();
const bearerToken = cookieStore.get(sessionCookieName);
request.headers.set("Authorization", "Bearer " + bearerToken?.value);
const newHeaders = new Headers(request.headers);
newHeaders.set("Authorization", "Bearer " + bearerToken?.value);
const newResponse = NextResponse.next({
request: {
headers: newHeaders
}
});
forward(newResponse);
},
async ({ request, response, context, event, forward, params }: MiddlewareFunctionProps) => {
const path = params()?.segments?.join("/");
return NextResponse.rewrite(new URL(path, process.env.NEXT_PUBLIC_API_BASE));
}
]
}
// create middleware
export const middleware = createMiddleware(middlewares, globalMiddlewares);
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
}
```
Your forward(newResponse)
is misplaced, you’re forwarding in the middle of a chain where you likely expect to modify the request path first. Instead, chain your logic only after addressing header manipulations and rewriting the path. Make sure the /api/proxy
prefix is removed and the rest of the URL is correctly added to the API server. You are currently trying to set headers for a proxy API request using request.headers
. This may be error-prone depending on how your middleware processes requests in Next.js. You can construct a fetch
request to the API server directly and handle the response. Below code adjusted
import { NextResponse } from "next/server";
import { cookies } from "next/headers";
import { createMiddleware, type MiddlewareFunctionProps } from "@rescale/nemo";
import { auth } from "auth";
const globalMiddlewares = {
before: async ({ request }: MiddlewareFunctionProps) => {
if (!request.url.includes("api/auth")) {
return;
}
auth();
},
};
const middlewares = {
"/api/proxy/*segments": [
// Middleware function for adding Authorization header
async ({
request,
response,
context,
event,
forward,
params,
}: MiddlewareFunctionProps) => {
const sessionCookieName =
process.env.NODE_ENV === "development"
? "authjs.session-token"
: "__Secure-next-auth.session-token";
const cookieStore = cookies();
const bearerToken = cookieStore.get(sessionCookieName);
if (bearerToken?.value) {
request.headers.set("Authorization", `Bearer ${bearerToken.value}`);
}
// Allow the next middleware in the chain to handle the rewrite
return forward();
},
// Middleware function for rewriting the path to the external API server
async ({
request,
response,
context,
event,
forward,
params,
}: MiddlewareFunctionProps) => {
const path = params()?.segments?.join("/"); // Extract segments after `/api/proxy`
return NextResponse.rewrite(
new URL(path ?? "", process.env.NEXT_PUBLIC_API_BASE)
);
},
],
};
export const middleware = createMiddleware(middlewares, globalMiddlewares);
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};
EDIT
Instead of expecting RTK Query to resolve or handle requests after rewrite()
, you can make the middleware act as a proxy server. Modify the middleware to directly handle the request and forward it with fetch
. Intercept the request in the middleware, rewrite, and fetch the response from the API server.
export const middleware = async (req: Request) => {
const url = new URL(req.url);
if (!url.pathname.startsWith("/api/proxy")) return NextResponse.next();
const targetPath = url.pathname.replace("/api/proxy/", "");
const targetURL = `${process.env.NEXT_PUBLIC_API_BASE}/${targetPath}`;
const sessionCookieName =
process.env.NODE_ENV === "development"
? "authjs.session-token"
: "__Secure-next-auth.session-token";
const cookieStore = cookies();
const bearerToken = cookieStore.get(sessionCookieName);
const headers = new Headers(req.headers);
if (bearerToken?.value) {
headers.set("Authorization", `Bearer ${bearerToken.value}`);
}
// Forward the request to the API server
const response = await fetch(targetURL, {
method: req.method,
headers,
body: req.body,
});
// Return the proxied response back to the client
const proxiedResponse = new NextResponse(response.body, {
status: response.status,
headers: response.headers,
});
return proxiedResponse;
};
export const config = {
matcher: "/api/proxy/:path*",
};