NextAuth集成Spotify API时自动刷新Access Token失败问题求助
解决NextAuth + Spotify Token自动刷新失效问题
问题根源
你的代码核心问题有两个:
- Session回调未同步完整Token状态:当前
session回调只把access_token同步到session对象,但没有传递expires_at、refresh_token和error字段,导致页面无法感知Token是否过期或刷新失败。 - 页面未处理Token过期场景:第一次刷新时,JWT回调正在刷新Token,但页面拿到的还是旧的session缓存,使用过期Token请求Spotify API报错;第二次刷新时JWT已完成更新,所以恢复正常。
修复步骤
1. 完善Session回调
更新session回调,把JWT中的所有关键字段同步到session:
session({ session, token }) { if (session.user) { session.user.id = token.id as string; session.access_token = token.access_token as string; // 新增同步过期时间、刷新Token和错误状态 session.expires_at = token.expires_at as number; session.refresh_token = token.refresh_token as string; session.error = token.error; } return session; }
2. 页面中处理Token过期逻辑
在页面请求Spotify API前,先检查Token是否过期或刷新失败,主动触发Session刷新:
export default async function Page() { const session = await auth(); if (!session?.user) return null; // 检查Token是否过期或刷新失败 if (session.error === "RefreshAccessTokenError" || (session.expires_at && Date.now() > session.expires_at * 1000)) { // 触发Session刷新,自动重新执行JWT回调获取新Token await signIn("spotify", { callbackUrl: "/dashboard", redirect: false }); // 刷新页面获取最新session window.location.reload(); return <div>正在刷新Token...</div>; } const accessToken = session.access_token ?? ""; // 后续Spotify API请求逻辑 }
3. 优化JWT回调的时间计算(确认逻辑)
确保expires_at计算准确(Spotify返回的expires_in是秒数,转换成时间戳时要和当前时间正确相加):
expires_at: Math.floor(Date.now() / 1000) + (tokens.expires_in || 3600),
你的代码这里逻辑正确,可确认下account.expires_in是否正常获取(Spotify默认返回3600秒)。
4. API请求添加重试机制
在调用Spotify API时,捕获Token过期错误,自动重试一次:
async function fetchSpotifyData(endpoint: string, accessToken: string) { try { const res = await fetch(`https://api.spotify.com/v1/${endpoint}`, { headers: { Authorization: `Bearer ${accessToken}` } }); // 捕获Token过期错误 if (res.status === 401) { // 触发Session刷新 await signIn("spotify", { callbackUrl: "/dashboard", redirect: false }); // 获取最新session const newSession = await auth(); if (!newSession?.access_token) throw new Error("Failed to refresh token"); // 重试请求 return fetch(`https://api.spotify.com/v1/${endpoint}`, { headers: { Authorization: `Bearer ${newSession.access_token}` } }).then(res => res.json()); } return res.json(); } catch (err) { console.error("Spotify API请求失败", err); throw err; } }
额外注意事项
- 确保
AUTH_SPOTIFY_ID和AUTH_SPOTIFY_SECRET环境变量配置正确,无拼写错误。 - 检查Spotify开发者后台的重定向URI是否和NextAuth配置一致。
- 若使用Next.js App Router,确保
auth()调用在Server Component中(你的代码逻辑符合要求)。
内容的提问来源于stack exchange,提问作者Eduard
相关产品推荐
相关产品推荐

