如何使用Next-auth同时存储多个会话
如何用Next-auth实现多应用令牌存储
你开发类似Zapier的集成工具时,需要连接多个第三方应用并保存它们的访问令牌,但Next-auth默认会覆盖单一会话中的令牌信息。下面是实现多应用令牌存储的具体方案:
核心思路
Next-auth的JWT令牌支持扩展自定义数据,我们可以在JWT中维护一个对象,按第三方应用的Provider ID分别存储每个应用的访问令牌、刷新令牌等信息,避免覆盖问题。
修改Auth配置
调整authOptions中的jwt和session回调,实现多账号令牌的存储与传递:
export const authOptions = { secret: process.env.NEXTAUTH_SECRET, providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, authorization: { params: { scope: 'openid https://www.googleapis.com/auth/gmail.compose https://www.googleapis.com/auth/gmail.modify' } } }), { clientId: process.env.QUICK_BOOKS_CLIENT_ID, clientSecret: process.env.QUICK_BOOKS_CLIENT_SECRET, id: 'quickbooks', name: 'QuickBooks', type: 'oauth', wellKnown: 'https://developer.api.intuit.com/.well-known/openid_sandbox_configuration', authorization: { params: { scope: 'com.intuit.quickbooks.accounting openid profile email phone address' } }, idToken: true, checks: ['pkce', 'state'], profile(profile) { return { id: profile.sub, name: profile.name, email: profile.email, image: profile.picture } } } // 可添加更多Provider ], callbacks: { async session({ session, token }) { // 将多账号令牌信息挂载到session,供前端访问 session.accounts = token.accounts || {}; // 保留用户基础信息 session.user.id = token.id; return session; }, async jwt({ token, account, profile }) { // 初始化accounts对象(首次连接应用时创建) token.accounts = token.accounts || {}; // 当有新的授权账号时,按Provider ID存储令牌信息 if (account) { token.accounts[account.provider] = { accessToken: account.access_token, refreshToken: account.refresh_token, expiresAt: account.expires_at ? account.expires_at * 1000 : null, // 转换为毫秒时间戳 providerUserId: profile.sub, provider: account.provider }; } return token; } } }
关键细节说明
- 令牌存储逻辑:每次用户授权新应用时,
jwt回调会把该应用的令牌信息存入token.accounts对象,键为Provider的ID(如google、quickbooks),不会覆盖已有应用的令牌。 - 前端访问:通过
session.accounts可以获取所有已连接应用的令牌,比如session.accounts.google.accessToken就能拿到Google的访问令牌。 - 令牌过期与刷新:如果需要处理令牌过期,可以在
jwt回调中检查expiresAt,自动调用Provider的刷新令牌接口更新,并同步到token.accounts中。 - 断开应用功能:可以编写API路由,接收Provider ID,解码JWT后删除
token.accounts中对应条目,再重新编码JWT并更新会话。
可选优化:数据库存储
如果需要连接大量应用,或者需要持久化令牌信息(避免JWT过期后丢失),建议将令牌存储到数据库中:
- 创建
ConnectedAccount表,关联用户ID、Provider ID、访问令牌、刷新令牌等字段。 - 在
jwt回调中,从数据库拉取用户所有已连接的账号信息,挂载到token.accounts中;新授权时,同时写入数据库。
内容的提问来源于stack exchange,提问作者fasil
相关产品推荐
相关产品推荐

