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

NextAuth API路由调用返回undefined session问题求助

客户端/服务器组件能正常获取Session,但API路由调用返回null

我目前碰到一个问题:客户端组件和服务器组件页面里都能成功拿到session,但通过API路由调用getServerSession()时,返回结果是undefined(服务器日志显示为null)。

正常工作的服务器组件(/app/profile)

import FeedCard from '@/components/application/feed/FeedCard';
import { authOptions } from '@/pages/api/auth/[...nextauth]';
import { getServerSession } from 'next-auth';

export default async function Feed() {
  const session = await getServerSession(authOptions);

  return (
    <div className="container mx-auto">
      <div className="flex flex-col">
        <div className="my-5">
          <h1 className="text-5xl font-black mb-5">Feed</h1>
          <p>
            <strong>Welcome, </strong>
            {session?.user?.name}!
          </p>
          <pre>{JSON.stringify(session)}</pre>
        </div>
        <FeedCard />
      </div>
    </div>
  );
}

正常工作的客户端组件(/app/navigation)

'use client'

import React, { useState } from 'react';
import Link from 'next/link';
import { useSession, signOut } from 'next-auth/react';

const AppMainNavigation = () => {
  const { data: session, status } = useSession();
  console.log(session)
  return (
    <div>Test</div>
  )
}

获取Session失败的API路由

import prisma from '@/libs/client';
import { getServerSession } from 'next-auth/next';
import { authOptions } from './auth/[...nextauth]';

export default async function handler(req, res) {
  if (req.method === 'GET') {
    const session = await getServerSession(req, res, authOptions);
    console.log(`===== session ======`);
    console.log(`session: ${session}`);

  }
}

服务器控制台日志

===== session ======
session: null

[...nextauth].ts 配置

import NextAuth from 'next-auth';
import type { NextAuthOptions } from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import prisma from '@/libs/client';
const bcrypt = require('bcrypt');

const confirmPasswordHash = (plainPassword, hashedPassword) => {
  return new Promise((resolve) => {
    bcrypt.compare(plainPassword, hashedPassword, function (err, res) {
      resolve(res);
    });
  });
};

export const authOptions: NextAuthOptions = {
  // 配置认证提供者
  providers: [
    CredentialsProvider({
      name: 'Credentials',
      credentials: {
        email: { label: 'email', type: 'text' },
        password: { label: 'Password', type: 'password' },
      },
      // 授权逻辑
      async authorize(credentials) {
        const { email, password } = credentials;
        const formPassword = credentials.formPassword;
        const authFormType = credentials.newUser ? formPassword : password;

        try {
          if (!email || !password) {
            console.log('未提供邮箱或密码');
            return null;
          }

          const user = await prisma.appUsers.findUnique({
            where: {
              email: email,
            },
          });

          if (!user) {
            console.log('用户不存在');
            return null;
          }

          const isPasswordValid = await confirmPasswordHash(
            authFormType,
            user.password
          );

          if (!isPasswordValid) {
            console.log('密码不正确');
            return null;
          }

          return {
            email: user.email,
            name: `${user.firstName} ${user.lastName}`,
            firstName: user.firstName,
            lastName: user.lastName,
            id: user.id,
          };
        } catch (error) {
          console.log(`错误: ${error}`);
        }
      },
    }),
  ],
  callbacks: {
    // 在session之前调用
    jwt: ({ token, user }) => {
      if (user) {
        return {
          ...token,
          id: user.id,
          firstName: user.firstName,
          lastName: user.lastName,
        };
      }
      return token;
    },
    // 在jwt之后调用
    session: ({ session, token }) => {
      return {
        ...session,
        user: {
          ...session.user,
          id: token.id,
          firstName: token.firstName,
          lastName: token.lastName,
        },
      };
    },
  },
  pages: {
    signIn: '/login',
  },
  session: {
    strategy: 'jwt',
  },
};

export default NextAuth(authOptions);

问题排查与解决方案

1. 检查客户端API调用是否携带Credentials

如果是通过客户端fetch调用API路由,必须显式设置credentials: 'include',否则浏览器不会传递认证Cookie:

// 客户端调用示例
fetch('/api/your-route', {
  method: 'GET',
  credentials: 'include'
})

2. 验证NEXTAUTH_URL环境变量配置

确保.env文件中正确设置了NEXTAUTH_URL:

  • 本地开发:NEXTAUTH_URL=http://localhost:3000
  • 生产环境:NEXTAUTH_URL=https://your-production-domain.com
    这个变量会影响Cookie的域名和路径设置,错误配置会导致API路由无法读取Session Cookie。

3. 确认API路由中getServerSession的调用方式

虽然Next.js 13+的Server Component可以省略req/res参数,但API路由必须完整传递这两个参数,确保调用方式正确:

const session = await getServerSession(req, res, authOptions);

4. 检查Cookie是否被拦截

  • 查看是否有自定义中间件(Middleware)修改或丢弃了请求头中的Cookie
  • 打开浏览器DevTools的Application面板,确认next-auth.session-token Cookie存在且域名、路径配置正确

5. 调整Cookie的SameSite属性

如果应用涉及跨域或子域名访问,需要在authOptions中调整Cookie的SameSite配置:

export const authOptions: NextAuthOptions = {
  // ...其他配置
  cookies: {
    sessionToken: {
      name: '__Secure-next-auth.session-token',
      options: {
        httpOnly: true,
        sameSite: 'Lax', // 根据场景调整为None或Lax
        path: '/',
        secure: process.env.NODE_ENV === 'production'
      }
    }
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 22:37:03