Replies: 1 comment
-
|
The clean pattern is to stop treating all NextAuth middleware is a good fit for pages and browser driven app routes, but webhooks, service callbacks, CLI diagnostics, and machine to machine endpoints should usually bypass it and authenticate inside the route or Nest guard using the mechanism appropriate for that caller. For example, make the middleware protect app pages and selected user facing API routes, but explicitly skip machine routes: import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { auth } from "@/auth";
const publicApiRoutes = [
"/api/webhooks/stripe",
"/api/orders/session",
"/api/compliance/offers/checkout",
"/api/gmail/messages",
];
export default auth((req) => {
const { pathname } = req.nextUrl;
if (publicApiRoutes.some((route) => pathname.startsWith(route))) {
return NextResponse.next();
}
if (!req.auth) {
const loginUrl = new URL("/auth/login", req.url);
loginUrl.searchParams.set("callbackUrl", req.nextUrl.pathname);
return NextResponse.redirect(loginUrl);
}
return NextResponse.next();
});
export const config = {
matcher: [
"/((?!_next/static|_next/image|favicon.ico).*)",
],
};Or, if most of export const config = {
matcher: [
"/((?!api|_next/static|_next/image|favicon.ico).*)",
],
};Then protect API routes at the API layer. For Stripe webhooks, do not use NextAuth cookies. Verify the Stripe signature: const signature = request.headers["stripe-signature"];
const event = stripe.webhooks.constructEvent(
rawBody,
signature,
process.env.STRIPE_WEBHOOK_SECRET,
);For Nest, that usually means a dedicated webhook route that uses the raw request body and a Stripe signature guard. For internal machine routes, use a different auth scheme, for example an HMAC header or API key: @Injectable()
export class MachineAuthGuard implements CanActivate {
canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
const apiKey = request.headers["x-api-key"];
return apiKey === process.env.INTERNAL_API_KEY;
}
}For anything that can mutate money, compliance state, or user data, I would prefer HMAC over a plain static API key: Then reject old timestamps and invalid signatures in a Nest guard. For Gmail, split the cases: So the overall structure I would use is: For local Stripe testing, point the Stripe CLI directly at the webhook route that bypasses NextAuth: stripe listen --forward-to localhost:3002/api/webhooks/stripeIf that still redirects, the middleware matcher is still catching the route. The key point is that bypassing NextAuth middleware does not mean the route is public. It means the route is not authenticated with a browser session cookie. It should still be authenticated at the API layer with the correct mechanism for that caller. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi all,
We’re building a Next.js + NestJS hybrid app with BoxyHQ’s SaaS starter kit. It uses:
Next.js (frontend, middleware, NextAuth)
NestJS (backend API, mounted under /api/**)
Stripe (checkout, webhooks, subscriptions)
Google Gmail API integration (via NextAuth Google provider / service account)
Everything works fine when running in-browser with a logged-in user, but we’ve hit a roadblock:
The Problem:
-Any curl / CLI / Stripe CLI / Gmail API calls to routes like:
--GET /api/orders/session?sessionId=...
--POST /api/compliance/offers/checkout
--GET /api/gmail/messages
…get intercepted by NextAuth middleware. Instead of returning JSON, it 307-redirects to /auth/login?callbackUrl=....
That makes it impossible to:
Use Stripe CLI (stripe trigger …) against /api/webhooks/stripe (unless hacked around).
Call diagnostic endpoints like /api/orders/session with curl.
Integrate Gmail API fetchers (server-to-server) because middleware assumes everything must be a logged-in user.
What We Tried
Whitelisting routes in middleware.ts (/api/orders/, /api/webhooks/, /api/compliance/, /api/gmail/).
Passing cookies manually in curl:
curl "http://localhost:3002/api/orders/session?sessionId=cs_test_123"
-H "Cookie: next-auth.session-token=…"
This works, but defeats the purpose for automated systems like Stripe CLI or background workers.
Adding a dev-only bypass header (ugly hack, not suitable for prod).
Moving some checks down into NestJS (HmacGuard), but NextAuth middleware still intercepts before it hits Nest.
What We Need
A clean pattern for letting some /api/** routes bypass NextAuth middleware (Stripe webhooks, Gmail, diagnostics) while keeping the rest protected.
A way to call /api/orders/session or /api/gmail/messages without NextAuth cookies, but still secured (e.g. HMAC header, API key, service account).
Guidance on how to best wire NextAuth + NestJS so auth is enforced where needed, but doesn’t break machine-to-machine integrations.
Ask
If you’ve solved this or have ideas:
How do you structure middleware.ts allowlists for hybrid Next.js/Nest apps?
Do you secure “machine” routes with API keys, HMAC, or something else instead of NextAuth?
Any examples of Gmail API integration in a Next.js + Nest setup would be gold.
How do you test with Stripe CLI locally when NextAuth middleware blocks /api/webhooks/stripe?
We’d love contributions or pointers — whether it’s PRs, snippets, or just sharing your approach.
Thanks in advance 🙏
Beta Was this translation helpful? Give feedback.
All reactions