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

如何在Next.js的next-auth服务端回调中创建并确认会话?

解决Next-auth自定义OAuth Provider服务端回调创建会话问题

核心问题在于你没必要自己实现独立的回调端点,next-auth的内置[...nextauth].ts已经封装了OAuth完整的回调流程,包括令牌交换、会话创建逻辑。以下是具体修正步骤:


1. 修正自定义Provider配置

在你的MyCustomProvider中补充令牌交换和用户信息获取的端点配置,让next-auth自动完成code→token、获取用户信息的流程,无需手动写回调:

//CustomProvider.tsx
export default function MyCustomProvider<P extends MyCustomProviderProfile>(
    options: MyCustomOAuthUserConfig<P>
): OAuthConfig<P> {
    return {
        id: `${options.id}`,
        name: "Your Custom Account",
        type: "oauth",
        authorization: {
            url: `${options.authorization}`,
            params: {
                client_id: `${options.clientId}`,
                app_id: `${options.applicationId}`,                
            },
        },
        // 补充令牌交换端点配置(替换为你的SSO实际令牌接口)
        token: `${options.issuer}/token`,
        // 补充用户信息获取端点配置(替换为你的SSO实际用户信息接口)
        userinfo: `${options.issuer}/userinfo`,
        checks: ["pkce", "state"],
        idToken: true,
        profile(profile) {
            return {
                id: profile.sub,
                name: profile.nickname,
                email: profile.email,
                image: profile.picture,
            }
        },
        style: {
            logo: "/auth0.svg",
            logoDark: "/auth0-dark.svg",
            bg: "#fff",
            text: "#EB5424",
            bgDark: "#EB5424",
            textDark: "#fff",
        },
        options,
    }
}

2. 移除自定义的callback端点

删除pages/api/authentication/callback.tsx,因为next-auth会自动处理回调请求(默认路径是/api/auth/callback/[providerId],对应你的场景就是/api/auth/callback/custom),你只需要在SSO平台把回调地址配置为这个路径即可。

3. 在next-auth回调中注入自定义逻辑(获取用户权限)

如果你需要获取用户的scopes,直接在next-auth的jwt和session回调中扩展即可,无需手动处理:

//[...nextauth].tsx
export const authOptions: NextAuthOptions = {
    providers: [
      MyCustomProvider({
        id: "custom",
        applicationId: applicationIdentifier,
        clientId: clientIdentifier,
        clientSecret: 'your-client-secret',
        issuer: 'https://your-issuer.com',        
        authorization: `${rootApiServer}/_AppAuth`,    
     }),     
    ],
    session: {
      strategy: "jwt",
      maxAge: 3000,
    },   
    callbacks: {
      async jwt({ token, account, profile }) {
        // 首次登录时,用access_token获取用户scopes
        if (account?.access_token) {
          const scopesResponse = await getUserScopes(account.access_token);
          if (scopesResponse) {
            token.scopes = scopesResponse;
          }
        }
        return token;
      },
      async session({ session, token }) {
        // 把scopes注入到session中,供前端和服务端使用
        if (token.scopes) {
          session.user.scopes = token.scopes;
        }
        return session;
      }
    } 
  }
  export default NextAuth(authOptions)

4. 若必须手动在服务端创建会话

如果因为业务需求一定要用自己的回调端点,可通过next-auth的服务端方法手动创建会话:

//pages/api/authentication/callback.tsx
import { signIn } from "next-auth/react";
import { authOptions } from "../auth/[...nextauth]"; // 引入你的auth配置

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    const code = req.query?.code as string;
    if (!code) {
        res.status(401).json({ message: 'Not authorized' });
        return;
    }

    const tokenResponse = await exchangeCodeForToken(code, req);
    if (!tokenResponse) {
        res.status(403).json({ message: 'Error authenticating user. Please try again.' });
        return;
    }

    const scopesResponse = await getUserScopes(tokenResponse.token);
    if (!scopesResponse) {
        res.status(403).json({ message: 'There was an error determining the user\'s scope.' });
        return;
    }

    // 手动调用next-auth的服务端signIn方法创建会话
    const result = await signIn("custom", {
        callbackUrl: "/", // 登录成功后的跳转地址
        user: {
            id: tokenResponse.userId, // 替换为实际用户ID
            name: tokenResponse.nickname,
            email: tokenResponse.email,
            image: tokenResponse.picture,
            scopes: scopesResponse
        }
    }, req, res);

    if (result?.error) {
        res.status(500).json({ message: 'Failed to create session' });
    } else {
        res.redirect("/");
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 02:57:52