CORS

Fix CORS Errors With Auth.js โ€” API Routes and Session Endpoints

Updated April 2026

Reading this? Verify your fix live. Test your CORS config โ†’ CORSFixer

Auth.js CORS errors are usually not CORS problems. They are NEXTAUTH_URL mismatches or architecture issues appearing as CORS. Adding CORS headers to auth routes makes things worse. Here is the right approach.

The rule: do not add CORS to /api/auth routes

# Auth.js handles its own session management and CORS
# Adding custom CORS headers to these routes breaks things

# Wrong โ€” breaks auth cookies
// middleware.ts
export function middleware(request: NextRequest) { if (request.nextUrl.pathname.startsWith("/api/auth")) { // Do NOT add CORS headers here const response = NextResponse.next(); response.headers.set("Access-Control-Allow-Origin", "*"); // โŒ breaks auth return response; }
}

Where to add CORS โ€” your data API routes only

# These routes need CORS if called from a different domain:
/api/users โœ… add CORS
/api/products โœ… add CORS
/api/data โœ… add CORS

# These routes should NOT have custom CORS:
/api/auth/session โŒ Auth.js handles this
/api/auth/signin โŒ Auth.js handles this
/api/auth/callback/*  โŒ Auth.js handles this

Add CORS to Next.js data API routes

// middleware.ts โ€” only for /api routes, not /api/auth
import { NextResponse } from "next/server";

export function middleware(request: NextRequest) { // Skip auth routes if (request.nextUrl.pathname.startsWith("/api/auth")) { return NextResponse.next(); } // Handle CORS for data API routes if (request.nextUrl.pathname.startsWith("/api/")) { if (request.method === "OPTIONS") { return new NextResponse(null, { status: 204, headers: { "Access-Control-Allow-Origin": "https://yourapp.com", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE", "Access-Control-Allow-Headers": "Content-Type, Authorization", }, }); } const response = NextResponse.next(); response.headers.set("Access-Control-Allow-Origin", "https://yourapp.com"); return response; } return NextResponse.next();
}

export const config = { matcher: "/api/:path*",
};

The most common mistake โ€” wrong architecture

# Wrong: frontend on different domain calling Auth.js session endpoint
# Frontend: https://frontend.yourapp.com
# Backend:  https://api.yourapp.com
# Auth.js session endpoint: https://api.yourapp.com/api/auth/session
# โ†’ Browser sends cross-origin request with cookie โ†’ CORS blocks it

# Right: frontend and Auth.js on same domain
# Frontend: https://yourapp.com
# Auth.js:  https://yourapp.com/api/auth
# โ†’ Same-origin, no CORS needed for auth

# If you must have separate domains: use JWT sessions in Auth.js
export const { handlers, auth } = NextAuth({ session: { strategy: "jwt" },  // token-based, not cookie-based // This allows cross-domain auth with Authorization header
});

Debug Auth.js CORS errors

# Check 1: Is NEXTAUTH_URL set correctly?
echo $NEXTAUTH_URL  # should be https://yourapp.com

# Check 2: Are the domains matching?
# Browser is at: https://yourapp.com
# Auth.js URL: https://yourapp.com  โ† must match

# Check 3: What does the actual error say?
# Open DevTools โ†’ Network โ†’ find the /api/auth request
# Check: is it a CORS error or a 401/500 with CORS symptoms?
Test your CORS config โ†’ CORSFixer