I have checked my Vercel production environment variables multiple times—they are all perfectly configured.
My Google Cloud OAuth credentials are also correctly set up and match what I used in the code.
However, when I click the “Sign in with Google” button in production, I am redirected back to the login page instead of going to the dashboard. The URL shows the following query parameter:
js
url.searchParams.set("error", "unauthenticated");
The same configuration works perfectly in my local environment—I’m able to sign in with Google and access the dashboard.
There is no other error or access block shown from google.
Here’s my lib/auth.js
and middleware.js
code for reference. Please help me fix the issue.
lib/auth.js
import NextAuth from "next-auth";
import Google from "next-auth/providers/google";
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
pages: {
signIn: "/login",
},
session: {
strategy: "jwt",
},
callbacks: {
async jwt({ token, user }) {
if (user?.email) {
token.email = user.email;
}
return token;
},
async session({ session, token }) {
if (token?.email) {
session.user.email = token.email;
}
return session;
},
},
});
middleware.js
import { getToken } from "next-auth/jwt";
import { NextResponse } from "next/server";
const ALLOWED_EMAILS = ["admin@example.com"];
export async function middleware(request) {
const token = await getToken({ req: request, secret: process.env.NEXTAUTH_SECRET });
const email = token?.email;
if (!token) {
const url = new URL("/login", request.url);
url.searchParams.set("error", "unauthenticated");
return NextResponse.redirect(url);
}
if (!email || !ALLOWED_EMAILS.includes(email)) {
const url = new URL("/login", request.url);
url.searchParams.set("error", "unauthorized");
return NextResponse.redirect(url);
}
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard/:path*"],
};