如何使用Chrome扩展获取的Google OAuth Access Token在Auth.js中完成登录?
解决方案
一、利用Google Access Token完成网站登录的实现思路
Auth.js没有直接接收第三方Token的公开登录API,但你可以在SvelteKit中自定义一个后端API端点,完成Token验证、用户匹配与会话创建的流程,具体步骤如下:
1. 后端验证Google Access Token合法性
在SvelteKit的服务器端API中,调用Google的tokeninfo接口验证Token的有效性、权限范围(需包含openid、email等必要scope),确保Token未过期且属于目标用户:
// 示例:验证Token const tokenInfoRes = await fetch(`https://oauth2.googleapis.com/tokeninfo?access_token=${accessToken}`); if (!tokenInfoRes.ok) { return new Response(JSON.stringify({ error: "无效的Access Token" }), { status: 401 }); } const tokenInfo = await tokenInfoRes.json(); if (!tokenInfo.scope.includes("openid") || !tokenInfo.scope.includes("email")) { return new Response(JSON.stringify({ error: "权限范围不足" }), { status: 403 }); }
2. 匹配/创建Auth.js用户与账户
通过Token返回的sub(Google用户唯一ID)和email,查询Auth.js的accounts表:
- 若找到匹配的
account(provider=google且providerAccountId=tokenInfo.sub),直接关联对应的user; - 若未找到,调用Auth.js适配器的
createUser和linkAccount方法,自动创建用户并绑定Google账户。
3. 创建Auth.js会话并返回Cookie
调用Auth.js的createSession方法生成会话,将会话Token通过authjs.session-token Cookie返回给扩展,后续扩展请求携带该Cookie即可被网站识别为已登录状态。
二、Auth.js数据库表与API说明
Auth.js没有官方公开的直接操作users/accounts/sessions/verification_tokens表的API,原因是这些表的结构会随适配器(如Prisma、Drizzle)不同而变化。但你可以通过以下方式间接操作:
- 使用Auth.js提供的服务器端方法:如
@auth/sveltekit/server中的getUser、getSession、createSession等方法,安全操作用户与会话数据; - 直接操作数据库:若需自定义逻辑,可直接读写数据库表,但需严格遵循Auth.js的数据结构(例如
accounts表需包含provider、providerAccountId、userId字段),避免破坏Auth.js内部状态。
三、示例代码实现
SvelteKit自定义登录API端点
// src/routes/api/auth/google-extension-login/+server.js import { auth } from '$lib/server/auth'; export async function POST({ request, cookies }) { const { accessToken } = await request.json(); // 验证Google Token const tokenInfoRes = await fetch(`https://oauth2.googleapis.com/tokeninfo?access_token=${accessToken}`); if (!tokenInfoRes.ok) return new Response(JSON.stringify({ error: "无效Token" }), { status: 401 }); const tokenInfo = await tokenInfoRes.json(); // 检查权限范围 if (!tokenInfo.scope.includes("openid") || !tokenInfo.scope.includes("email")) { return new Response(JSON.stringify({ error: "权限不足" }), { status: 403 }); } // 查找已绑定的账户 const existingAccount = await auth.adapter.getUserByAccount({ provider: "google", providerAccountId: tokenInfo.sub }); let userId; if (existingAccount) { userId = existingAccount.userId; } else { // 创建新用户并绑定账户 const newUser = await auth.adapter.createUser({ email: tokenInfo.email, emailVerified: tokenInfo.email_verified ? new Date() : null, name: tokenInfo.name, image: tokenInfo.picture }); await auth.adapter.linkAccount({ userId: newUser.id, provider: "google", providerAccountId: tokenInfo.sub, type: "oauth", access_token: accessToken, expires_at: tokenInfo.exp }); userId = newUser.id; } // 创建会话并设置Cookie const session = await auth.createSession({ userId, expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // 7天有效期 }); cookies.set("authjs.session-token", session.sessionToken, { path: "/", httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: "lax", maxAge: 7 * 24 * 60 * 60 }); return new Response(JSON.stringify({ success: true }), { status: 200 }); }
Chrome扩展调用登录API
// 扩展内代码 async function loginToWebsite() { const accessToken = await getGoogleAccessToken(); // 你已获取的Token const response = await fetch("https://your-website-domain.com/api/auth/google-extension-login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ accessToken }), credentials: "include" // 携带Cookie }); const data = await response.json(); if (data.success) { console.log("登录成功,可向网站发送数据"); } }
四、注意事项
- 跨域处理:若扩展与网站域名不同,需在SvelteKit中配置CORS,允许扩展域名的请求;
- Token有效期:Google Access Token有效期约1小时,若需长期登录,需在扩展中获取Refresh Token并在后端自动刷新;
- 安全性:所有Token验证逻辑必须在后端完成,避免前端伪造Token;可通过验证请求来源或扩展ID进一步限制API访问权限。
内容的提问来源于stack exchange,提问作者Joey
相关产品推荐
相关产品推荐

