SvelteKitAuth集成Cognito时如何获取access_token与id_token?
问题背景
我正在开发一个SvelteKit应用,使用Cognito作为身份认证提供商。调用AWS的IsAuthorizedWithToken API时,需要提供已登录用户的access_token或id_token,希望在+page.server.ts文件中获取这些令牌。
当前+page.server.ts中的代码:
// somefolder/+page.server.ts export async function load({ locals }) { const session = await locals.getSession(); const { id_token, access_token } = session // 使用id_token、access_token }
受NextAuth获取提供商令牌的方法启发,我使用jwt回调在用户登录时获取令牌,控制台日志确认session中存在令牌。但刷新页面后,令牌变为undefined,尽管用户仍处于登录状态,且能访问session中的user.email等属性,推断令牌仅在登录时可用,后续请求无法获取。
当前hooks.server.ts中的代码:
// hooks.server.ts import { SvelteKitAuth } from '@auth/sveltekit'; import Cognito from '@auth/core/providers/cognito'; import { AUTH_SECRET, COGNITO_USER_POOL_ID, COGNITO_CLIENT_SECRET } from '$env/static/private'; import { PUBLIC_COGNITO_CLIENT_ID } from '$env/static/public'; import type { Handle } from '@sveltejs/kit'; export const handle = SvelteKitAuth({ secret: AUTH_SECRET, providers: [ Cognito({ clientId: PUBLIC_COGNITO_CLIENT_ID, clientSecret: COGNITO_CLIENT_SECRET, issuer: `https://cognito-idp.us-east-1.amazonaws.com/${COGNITO_USER_POOL_ID}` }) ], callbacks: { async session({ session, token }) { session.user && (session.user.sub = token.sub); session.access_token = token.accessToken as string; session.id_token = token.id_token as string; console.log(session); return session; }, async jwt({ token, account }) { if (account) { token.access_token = account.access_token; token.id_token = account.id_token; } return token; } } }) satisfies Handle;
问题
- Q1:为何令牌仅在用户登录时可用,后续请求无法获取?SvelteKitAuth对令牌做了什么处理?
- Q2:在
+page.server.ts中获取令牌的正确方式是什么?
解答
Q1:原因分析
- JWT回调逻辑漏洞:Auth.js的
jwt回调仅在用户首次登录时会传入account参数(包含Cognito返回的令牌),此时你将令牌存入了token对象。但刷新页面时,jwt回调会被再次调用,但account参数为undefined,你的代码没有保留token中已有的令牌字段,导致刷新后token里的令牌丢失。 - 字段名称不匹配:
jwt回调中存储的是token.access_token和token.id_token,但session回调中错误地读取token.accessToken(大小写不一致),直接导致session中无法正确获取令牌。 - SvelteKitAuth存储机制:SvelteKitAuth默认将JWT加密后存在客户端Cookie中,每次请求会解析这个JWT得到
token对象。如果token里没有持久化令牌,刷新后自然无法从session中拿到。
Q2:正确解决方法
步骤1:修正jwt回调,持久化令牌
修改jwt回调,确保即使没有account参数,也返回包含已有令牌的token对象:
async jwt({ token, account }) { // 首次登录时,从account中获取令牌并存入token if (account) { token.access_token = account.access_token; token.id_token = account.id_token; } // 直接返回token,保留已有的令牌字段 return token; }
步骤2:修正session回调的字段名称
将session回调中的token.accessToken改为token.access_token,与jwt回调中的存储字段一致:
async session({ session, token }) { session.user && (session.user.sub = token.sub); // 修正字段名称,匹配jwt中存储的key session.access_token = token.access_token as string; session.id_token = token.id_token as string; return session; }
步骤3:验证+page.server.ts中的获取逻辑
保持+page.server.ts中的代码不变,刷新页面后,session中的access_token和id_token就能正常获取:
// somefolder/+page.server.ts export async function load({ locals }) { const session = await locals.getSession(); const { id_token, access_token } = session // 正常使用id_token、access_token }
额外注意事项
确保AUTH_SECRET环境变量配置正确,它是Auth.js加密JWT的密钥,如果配置错误会导致JWT解析失败,进而无法获取令牌。
内容的提问来源于stack exchange,提问作者bluprince13
相关产品推荐
相关产品推荐

