NextAuth.js 向Session添加额外属性:Discord认证会话异常问题
问题根因
- Cookie大小超限导致登录态丢失:使用JWT会话策略(NextAuth无适配器时的默认策略)时,完整JWT会序列化后存入客户端Cookie。你把包含全量Discord guilds数组的profile直接塞进JWT后,整体体积极易超过浏览器单Cookie 4KB的限制,浏览器会直接丢弃超限Cookie,导致NextAuth每次请求都无法获取有效登录态,表现为会话返回null、反复跳转Discord要求重新授权。
- 类型报错未做扩展定义:NextAuth内置的Session、JWT类型仅包含基础字段,你新增的
profile、accessToken、自定义guilds字段未在TS类型声明中扩展,因此触发类型校验报错,不需要额外用@ts-ignore规避。
修正实现步骤
1. 优化存储逻辑,规避Cookie超限
根据guilds的使用场景选择对应方案:
- 若guilds仅需在部分页面使用:仅在JWT中存储
accessToken,需要guilds时在服务端接口中用accessToken实时请求Discord接口拉取,不要将全量guilds存入客户端。 - 若需要全局直接访问guilds:优先过滤guilds字段,仅保留必要属性(如
id、name),减少存储体积;如果guilds数量过多(体积仍超限),则切换为数据库会话策略,将会话内容存在服务端数据库,客户端Cookie仅存储会话ID,完全不受Cookie大小限制。 - 注意:Discord v8 API已废弃,建议替换为v10版本的接口地址。
2. 修正回调逻辑
修正后的JWT回调
仅在初次登录时写入自定义字段,过滤冗余内容:
async jwt(token, user, account, profile, isNewUser) { // 仅初次登录时写入自定义数据,后续回调profile参数为undefined if (user && account?.access_token) { token.accessToken = account.access_token; // 仅保留需要的Discord profile字段,避免冗余 token.profile = { id: profile.id, username: profile.username, email: profile.email, }; // 拉取guilds并过滤冗余字段 const guildRes = await fetch("https://discord.com/api/v10/users/@me/guilds", { headers: { Authorization: `Bearer ${account.access_token}`, }, }); const rawGuilds = await guildRes.json(); // 过滤后仅存必要属性,压缩体积 token.profile.guilds = rawGuilds.map(g => ({ id: g.id, name: g.name })); } return token; }
修正后的Session回调
直接从token中读取自定义字段赋值到会话即可:
async session(session, token) { session.accessToken = token.accessToken; session.profile = token.profile; return session; }
3. 彻底解决TS类型报错
不需要使用@ts-ignore,通过扩展NextAuth的内置类型实现类型提示:
在项目根目录新建types/next-auth.d.ts类型声明文件,写入以下内容:
import NextAuth, { DefaultSession } from "next-auth"; // 扩展Session类型 declare module "next-auth" { interface Session { accessToken?: string; profile?: { id: string; username: string; email?: string; guilds?: Array<{ id: string; name: string }>; } & DefaultSession["user"]; } } // 扩展JWT类型 declare module "next-auth/jwt" { interface JWT { accessToken?: string; profile?: Session["profile"]; } }
确保该类型文件被tsconfig.json的include字段扫描到,即可消除所有类型报错。
内容的提问来源于stack exchange,提问作者dheerajpv
相关产品推荐
相关产品推荐

