You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js next-auth在Vercel生产环境遇CLIENT_FETCH_ERROR,Google登录异常

Next.js 集成 NextAuth 部署到 Vercel 生产环境后出现 CLIENT_FETCH_ERROR

问题描述

本地环境功能正常,但部署到Vercel生产环境后出现以下异常:

  • 点击调用signIn('google')的按钮时,未弹出Google登录窗口,直接跳转至/api/auth/error页面
  • 控制台报CLIENT_FETCH_ERROR,提示JSON.parse解析异常,向/api/auth/session发送POST请求返回405错误

相关代码

pages/api/auth/[...nextauth].ts

import NextAuth, { NextAuthOptions } from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import Google from 'next-auth/providers/google';
import { gql } from '@apollo/client';
import client from '@/lib/apollo-client';

const secret = process.env.NEXTAUTH_SECRET;

const LOGIN_MUTATION = gql`
  mutation Login($username: String!, $password: String!) {
    login(username: $username, password: $password) {
      token
      user {
        id
        username
        email
      }
    }
  }
`;
declare module "next-auth" {
  interface Session {
    id: string;
    username: string;
    email: string;
    accessToken: string;
  }
}
export const authOptions: NextAuthOptions = {
  providers: [
    CredentialsProvider({
      name: 'Credentials',
      credentials: {
        username: {
          label: 'Username:',
          type: 'text',
          placeholder: 'your username',
        },
        password: {
          label: 'Password:',
          type: 'password',
        },
      },
      async authorize(credentials) {
        const { username, password } = credentials || { username: null, password: null };
        try {
          const { data } = await client.mutate({
            mutation: LOGIN_MUTATION,
            variables: { username, password },
          });
          const { token, user } = data.login;

          if (user) {
            return {
              id: user.id,
              username: user.username,
              email: user.email,
              token,
            };
          } else {
            return null;
          }
        } catch (error) {
          console.error('Login error:', error);
          return null;
        }
      },
    }),
    Google({
      clientId: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
      profile(profile) {
        const username = profile.email.split('@')[0];
        return {
          id: profile.sub,
          email: profile.email,
          username,
        };
      },
    })
  ],
  pages: {
    signIn: '/login',
    error: '/login'
  },
  callbacks: {
    async signIn({ user, account, profile }) {
      return true;
    },
    async jwt({ token, user }: { token: any; user: any }) {
      if (user) {
        token.id = user.id;
        token.username = user.username;
        token.email = user.email;
        token.accessToken = user.token;
      }
      return token;
    },
    async session({ session, token }: { session: any; token: any }) {
      if (token) {
        session.id = token.id;
        session.username = token.username;
        session.email = token.email;
        session.accessToken = token.accessToken;
      }
      return session;
    },
    async redirect({ url, baseUrl }) {
      return baseUrl;
    },
  },
  session: {
    strategy: 'jwt',
  },
  secret,
  jwt: {
    secret,
    maxAge: 60 * 60 * 24 * 7,
  }
  
}

export default async function auth(req: any, res: any) {
  return NextAuth(req, res, authOptions);
}

触发错误的按钮代码

<button
  onClick={() => signIn('google')}
  className="bg-blue-500 text-white px-8 py-4 rounded-lg shadow-lg flex flex-row mb-5"
>
  <FcGoogle className='text-2xl'/><h2>Google</h2>
</button>

控制台错误信息

[next-auth][error][CLIENT_FETCH_ERROR] 
JSON.parse: unexpected character at line 1 column 1 of the JSON data 
Object { error: {…}, url: "/api/auth/session", message: "JSON.parse: unexpected character at line 1 column 1 of the JSON data", client: true }
_app-b6853d7412a1048d.js:1:30260
    NextJS 8
        error
        e
        e
        h
        value
        S
        t
        u
[next-auth][error][CLIENT_FETCH_ERROR] 
JSON.parse: unexpected character at line 1 column 1 of the JSON data 
Object { error: {…}, url: "/api/auth/session", message: "JSON.parse: unexpected character at line 1 column 1 of the JSON data" }
cinemation-3.vercel.app:13851:25
    overrideMethod https://cinemation-3.vercel.app/:13851
    NextJS 34
        error
        e
        e
        h
        value
        S
        t
        u
    (Async: promise callback)
        t
        s
    (Async: promise callback)
        t
        s
        exports
        exports
        fetchData
        e
        h
        value
        S
        t
        s
        exports
        exports
        D
        e
        h
        value
        S
        t
        s
        exports
        exports
        e
        r

已做排查

  • 配置了Vercel环境变量,包括NEXTAUTH_SECRET、GOOGLE_CLIENT_ID、GOOGLE_CLIENT_SECRET
  • OAuth2客户端授权重定向URI设置为https://xxx.vercel.app/api/auth/callback/google
  • MongoDB已设置允许所有IP访问

解决方案

1. 修复代码语法错误

原代码中LOGIN_MUTATION的gql模板字符串缺少闭合反引号,生产环境编译后会返回非JSON内容,直接引发JSON.parse异常,已在上述代码中修正。

2. 修正/api/auth/session请求方法

/api/auth/session仅支持GET请求,控制台出现POST请求405错误,需检查客户端代码中useSession或自定义获取session的逻辑,确保使用GET方法发起请求。

3. 验证Vercel环境变量有效性

  • 确认NEXTAUTH_SECRET、GOOGLE_CLIENT_ID、GOOGLE_CLIENT_SECRET等变量在Vercel中已正确配置,且部署时触发了重新构建(环境变量修改后需重新部署才会生效)
  • 生产环境必须设置NEXTAUTH_SECRET,否则JWT签名验证会失败,导致session获取异常

4. 调整Google OAuth配置

  • 确认Google Cloud控制台中,OAuth客户端的授权重定向URI与Vercel生产域名完全一致,包含https前缀
  • 检查OAuth客户端是否已发布到生产环境(未发布的客户端仅允许测试用户登录)

5. 修改redirect回调逻辑

当前redirect回调强制返回baseUrl,会破坏Google登录后的重定向流程,修改为:

async redirect({ url, baseUrl }) {
  if (url.startsWith(baseUrl)) return url;
  return baseUrl;
}

6. 检查Apollo Client生产配置

若Credentials登录也存在异常,需确认Apollo Client在生产环境的API地址配置正确,避免因跨域或地址错误导致请求失败,影响NextAuth的authorize流程。


内容的提问来源于stack exchange,提问作者malle2002

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:17:05