如何在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
相关产品推荐
相关产品推荐

