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

NextAuth session回调生产环境不触发,会话为空问题

NextAuth v4.17.0在AWS Amplify生产环境中session回调不触发问题

我使用AWS Amplify部署了基于Next.js(v13)的应用,采用NextAuth(v4.17.0)的CredentialsProvider对接自定义服务端。开发环境下一切正常,但生产环境中session回调不触发,会话为空,尽管数据库已生成token。

已排查情况

  • 确认session默认策略为jwt,无需额外配置
  • .env.production中已正确设置NEXT_AUTH_SECRET、NEXT_PUBLIC_API_URL和NEXTAUTH_URL
  • API请求和NextAuth请求均返回200状态码
  • Amplify日志无报错

补充说明

若通过/api/auth/signin/credentials使用默认UI登录,会话可成功创建。

相关代码(路径:/page/api/auth/[...nextauth].tsx)

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import jwt_decode from "jwt-decode";
import { TokenInfo } from "../../../components/types/auth_types";


async function refreshAccessToken(token) {
    try {
        console.log("BUT WHY?");

        const res = await fetch(
            `${process.env.NEXT_PUBLIC_API_URL}/api/token/refresh/`,
            {
                method: "POST",
                body: JSON.stringify({refresh: token.refreshToken}),
                headers: {"Content-Type": "application/json"},
            }
        );

        if (!res.ok) throw "refreshError";
        const responseJson = await res.json();
        return {
            ...token,
            accessToken: responseJson.access,
        }

    } catch(error) {
        return {
            ...token,
            error: "RefreshAccessTokenError",
        }
    }
}

export const authOptions = {
    providers: [
        CredentialsProvider({
            id: "credentials",
            name: "Credentials",
            credentials: {
                email: { label: "Username", type: "text", placeholder: "" },
                password: { label: "Password", type: "password" }
            },
            async authorize(credentials, req) {
                const userCredentials = {
                    email: credentials.email, password: credentials.password
                };
                try {
                    const res = await fetch(
                        `${process.env.NEXT_PUBLIC_API_URL}/api/token/`,
                        {
                            method: "POST",
                            body: JSON.stringify(userCredentials),
                            headers: {"Content-Type": "application/json"},
                            credentials: "include",
                        }
                    );
                    console.log("res", res);
                    if (res.ok) {
                        const responseJson = await res.json();
                        console.log("resJson", responseJson);
                        const tokenInfo: TokenInfo = jwt_decode(responseJson.access);
                        console.log("tokenInfo", tokenInfo);
                        return {
                            id: tokenInfo.user_id.toString(),
                            email: tokenInfo.email,
                            firstName: tokenInfo.first_name,
                            lastName: tokenInfo.last_name,
                            isStaff: tokenInfo.is_staff,
                            accessToken: responseJson.access,
                            refreshToken: responseJson.refresh,
                        };
                    }
                    return null;
                } catch(e) {
                    return null;
                }
            }
        })
    ],
    callbacks: {
        async jwt({ token, account, user }) {
            if (account && user) {
                console.log("got into token", user);
                
                token.firstName = user.firstName;
                token.lastName = user.lastName;
                token.refreshToken = user.refreshToken;
                token.accessToken = user.accessToken;
            }
            if (token.accessToken) {
                console.log("got in this if instead");
                const decodedToken: TokenInfo = jwt_decode(token.accessToken);
                if (Date.now() < decodedToken.exp * 1000) {
                    console.log("got here, returned properly");
                    return token;
                }
            }
            console.log("got here, not properly, why?");
            return await refreshAccessToken(token);
        },
        async session({ session, token }) {
            console.log("getting session");
            session.user.firstName = token.firstName;
            session.user.lastName = token.lastName;
            session.accessToken = token.accessToken;
            console.log("sess", session);
            return session;
        }
    },
    secret: process.env.NEXT_AUTH_SECRET,
    session: {
        maxAge: 2 * 24 * 60 * 60,  // two days
    }
};

export default NextAuth(authOptions);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 07:35:26