SvelteKit中Cookie传递失败致Google OAuth验证异常求助
我在使用Google OAuth身份验证时遇到state和verifier不匹配的问题,核心原因是:跳转至Google授权前,我在/signup/+page.server.js的动作里把state和verifier存入Cookie,但在/api/oauth/google/+server.js中读取时这两个值全是undefined。试过用event.locals存储也没用,+server.js里的event.locals同样是undefined。现在需要先解决从+page.server.js到+server.js的值传递问题,安全存储后续再考虑。
相关代码
+page.server.js 动作代码
oauth2google: async (event) => { const authMethods = await event.locals.pb?.collection('users_valiantlynx').listAuthMethods(); // 生成state和verifier if (!authMethods) { return { authProviders: '' }; } const redirectUrl = `${event.url.origin}/api/oauth/google`; const googleAuthProvider = authMethods.authProviders.find((provider) => provider.name === 'google'); const authProviderRedirect = `${googleAuthProvider?.authUrl}${redirectUrl}`; // 保存state和verifier到Cookie const state = googleAuthProvider.state; const verifier = googleAuthProvider.codeVerifier; console.log('state', state); console.log('verifier', verifier); event.cookies.set('googleAuthState', state); event.cookies.set('googleAuthVerifier', verifier); throw redirect(302, authProviderRedirect); }
+server.js 代码
export const GET = async ({ locals, url, cookies }) => { console.log('GET', cookies.getAll()); const redirectUrl = `${url.origin}/api/oauth/google`; const expectedState = cookies.get('googleAuthState'); const expectedVerifier = cookies.get('googleAuthVerifier'); // 每次调用listAuthMethods都会生成新的verifier,所以不能在这重新调用PocketBase的方法获取 console.log('expectedState', expectedState); console.log('expectedVerifier', expectedVerifier); const state = url.searchParams.get('state'); const code = url.searchParams.get('code'); console.log('state', state); console.log('code', code); // ...后续逻辑 }
错误日志
expectedState undefined expectedVerifier undefined state e2LyMU4i1lTSGbBEDyWuBKnp8F3zJG code 4/0AfJohXke3dhNwRBhew7jMA1_Aj5KuxuiitAeVh4Vn6g7oZy6V5DR9f8PqxM-llh8_fVs8g state mismatch undefined e2LyMU4i1lTSGbBEDyWuBKnp8F3zJG
解决办法
1. 修正Cookie的路径与跨站配置
SvelteKit的cookies.set默认路径是当前页面的路径(比如/signup),而回调接口在/api/oauth/google,属于不同路径,导致Cookie无法被读取。必须显式设置Cookie的path为/,同时配置SameSite为lax适配OAuth跳转场景:
修改+page.server.js里的Cookie设置:
event.cookies.set('googleAuthState', state, { path: '/', sameSite: 'lax', httpOnly: true, // 可选,增强安全性,防止前端JS读取 maxAge: 60 * 5 // 设置5分钟过期,避免长期留存 }); event.cookies.set('googleAuthVerifier', verifier, { path: '/', sameSite: 'lax', httpOnly: true, maxAge: 60 * 5 });
2. 正确构造Google授权跳转URL
你之前直接拼接redirectUrl的方式可能有误,Google的授权URL需要通过参数传递redirect_uri和state,用URLSearchParams构造更稳妥:
const authUrl = new URL(googleAuthProvider.authUrl); authUrl.searchParams.set('redirect_uri', redirectUrl); authUrl.searchParams.set('state', state); // 确保state传递给Google,回调时会原样返回 const authProviderRedirect = authUrl.toString();
3. 关于event.locals无法传递的原因
SvelteKit的event.locals仅在同一次请求生命周期内有效,302跳转属于新请求,所以locals里的值不会保留。Cookie是跨请求传递状态的正确方式,前提是配置正确的路径和SameSite。
4. 验证Cookie是否生效
可以打开浏览器开发者工具(Application -> Cookies),检查是否存在googleAuthState和googleAuthVerifier,确认它们的路径为/、域名与当前站点一致。
内容的提问来源于stack exchange,提问作者Young Finn

