使用自定义OAuth提供商Trackmania时NextAuth Session返回null
尝试将Trackmania作为自定义OAuth提供商实现身份验证,已成功获取令牌响应,但访问profile页面调用getServerSession时返回的session始终为null,怀疑是next-auth.session-token未正确替换next-auth.state cookie导致。
已完成的操作:
- 按Trackmania OAuth文档配置流程,登录页使用SignInButton组件触发授权
- Trackmania OAuth应用已配置好首页与重定向URI
- 自定义的
src/app/api/user/auth-return/route.ts能正常获取令牌,但无法生成有效会话
NextAuth配置
import type { AuthOptions } from "next-auth"; export const options: AuthOptions = { pages: { signIn: "/sign-in", signOut: "/sign-out" }, providers: [ { id: "trackmania", name: "Trackmania", type: "oauth", wellKnown: "https://api.trackmania.com/.well-known/openid-configuration", authorization: { params: { response_type: "code", client_id: process.env.TM_OAUTH_CLIENT_ID, scope: "write_favorite", redirect_uri: "http://localhost:3000/api/user/auth-return" }, url: "https://api.trackmania.com/oauth/authorize" }, profile(profile, tokens) { console.log("profile: ", profile); console.log("tokens: ", tokens); return { ...profile, ...tokens }; }, clientId: process.env.TM_OAUTH_CLIENT_ID, clientSecret: process.env.TM_OAUTH_SECRET_ID, issuer: "https://api.trackmania.com/", token: { url: "https://api.trackmania.com/api/access_token" }, userinfo: { url: "https://api.trackmania.com/api/user" } } ], session: { strategy: "jwt" } };
自定义重定向处理路由
import { NextRequest, NextResponse } from "next/server"; export const GET = async (request: NextRequest) => { const code = request.nextUrl.searchParams.get("code") || ""; const url = "https://api.trackmania.com/api/access_token"; const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ grant_type: "authorization_code", client_id: process.env.TM_OAUTH_CLIENT_ID, client_secret: process.env.TM_OAUTH_SECRET_ID, code: code, redirect_uri: "http://localhost:3000/api/user/auth-return" }) }); if (!res.ok) { const text = await res.text(); throw new Error(`Failed to fetch data\nStatus: ${res.status}\nResponse: ${text}`); } const data = await res.json(); console.log("data: ", data); return NextResponse.redirect(new URL("/profile", request.url)); };
Profile页面代码
import { getServerSession } from "next-auth"; import { options } from "../api/auth/[...nextauth]/options"; const ProfilePage = async () => { const session = await getServerSession(options); console.log("session: ", session); return ( <div className="pl-4"> <h1 className="text-2xl">ProfilePage</h1> </div> ); };
.env.local配置
NEXTAUTH_SECRET="ID_GENERATED_FROM_OPENSSL_RAND" NEXTAUTH_URL="http://localhost:3000/" TM_OAUTH_CLIENT_ID="..." TM_OAUTH_SECRET_ID="..."
问题核心是你绕过了NextAuth的内置OAuth流程,自定义路由仅获取了令牌,但未让NextAuth处理会话生成和Cookie设置。按以下步骤修复:
删除自定义的
auth-return路由
完全移除src/app/api/user/auth-return/route.ts,让NextAuth默认回调路由/api/auth/callback/trackmania处理授权响应。修正NextAuth配置中的重定向URI
更新authorization.params.redirect_uri为NextAuth的回调地址:authorization: { params: { response_type: "code", client_id: process.env.TM_OAUTH_CLIENT_ID, scope: "write_favorite", // 修改为NextAuth标准回调地址 redirect_uri: "http://localhost:3000/api/auth/callback/trackmania" }, url: "https://api.trackmania.com/oauth/authorize" },更新Trackmania OAuth应用的重定向URI
在Trackmania开发者后台,将重定向URI修改为http://localhost:3000/api/auth/callback/trackmania,确保与NextAuth配置完全一致。添加会话同步回调(可选)
若需要将令牌信息同步到会话,可补充JWT和session回调:export const options: AuthOptions = { // ...其他配置 callbacks: { async jwt({ token, user, account }) { // 首次登录时存入用户和令牌信息 if (user && account) { token.id = user.id; token.accessToken = account.access_token; } return token; }, async session({ session, token }) { // 将JWT信息同步到session对象 session.user.id = token.id; session.accessToken = token.accessToken; return session; } } };重启应用测试
重新启动项目后触发登录流程,NextAuth会自动处理令牌交换、会话生成和Cookie设置,此时getServerSession即可返回有效会话。
内容的提问来源于stack exchange,提问作者Andrew Shearer

