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