在SvelteKit服务器端使用Auth0认证并获取用户详情时遭遇invalid_token错误的技术问询
你遇到的invalid_token错误附带的Cannot read properties of undefined (reading 'XMLHttpRequest')提示,其实已经点明了核心问题:auth0-js是专门为浏览器环境设计的客户端库,它依赖浏览器特有的API(比如XMLHttpRequest、window对象),而SvelteKit的服务器端运行在Node.js环境中,没有这些浏览器API,所以直接调用会报错。
webAuth.parseHash和webAuth.client.userInfo这两个方法都是为浏览器场景设计的:parseHash用来解析浏览器URL中的哈希参数,userInfo内部用XMLHttpRequest发送请求,这些在服务器端都无法正常工作。
我们需要替换掉客户端的auth0-js,改用Auth0提供的Node.js SDK,或者直接调用Auth0的REST API,这些都是为服务器端环境设计的。下面分步骤给出具体实现:
1. 优化客户端代码:提前解析哈希提取令牌
与其把整个哈希字符串发给服务器,不如在客户端先解析出需要的令牌(比如access_token或id_token),这样更高效,也减少服务器端的处理负担:
<script lang="ts"> import { onMount } from 'svelte'; onMount(async () => { // 解析URL哈希中的参数 const hashParams = new URLSearchParams(window.location.hash.slice(1)); const accessToken = hashParams.get('access_token'); const idToken = hashParams.get('id_token'); if (accessToken) { const response = await fetch("/api/sign-in", { method: "POST", headers: { "Content-Type": "application/json" }, // 只发送需要的令牌,而不是整个哈希 body: JSON.stringify({ accessToken, idToken }) }); const result = await response.json(); console.log('Server response:', result); } }); </script> <div class="content"> <p>Redirecting, please wait...</p> </div>
2. 改造服务器端端点:使用服务器端方式获取用户信息
方式一:直接调用Auth0的/userinfo REST API
这种方式不需要额外安装SDK,用Node.js原生的fetch即可(SvelteKit服务器端支持fetch):
import { env } from '$env/dynamic/private'; /** @type {import('@sveltejs/kit').RequestHandler} */ export async function post({ request }) { const { accessToken } = await request.json(); try { // 调用Auth0的userinfo端点获取用户信息 const userInfoResponse = await fetch(`https://${env.AUTH0_DOMAIN}/userinfo`, { headers: { 'Authorization': `Bearer ${accessToken}` } }); if (!userInfoResponse.ok) { throw new Error('Invalid or expired access token'); } const user = await userInfoResponse.json(); console.log('Fetched user info:', user); return { status: 200, body: { user, message: 'Success' } }; } catch (err) { console.error('Error during authentication:', err); return { status: 401, body: { error: 'invalid_token', errorDescription: err.message } }; } };
方式二:使用Auth0 Node.js SDK(更便捷)
如果需要更丰富的服务器端操作(比如管理用户、角色等),可以安装官方的Node.js SDK:
首先安装依赖:
npm install auth0
然后修改端点代码:
import { ManagementClient } from 'auth0'; import { env } from '$env/dynamic/private'; /** @type {import('@sveltejs/kit').RequestHandler} */ export async function post({ request }) { const { accessToken } = await request.json(); try { // 初始化Auth0管理客户端 const managementClient = new ManagementClient({ domain: env.AUTH0_DOMAIN, clientId: env.AUTH0_CLIENT_ID, clientSecret: env.AUTH0_CLIENT_SECRET, // 从环境变量读取,不要硬编码 token: accessToken // 使用用户的access_token访问userinfo }); // 获取当前令牌对应的用户信息 const user = await managementClient.getUser({ id: 'me' }); console.log('Fetched user info:', user); return { status: 200, body: { user, message: 'Success' } }; } catch (err) { console.error('Error during authentication:', err); return { status: 401, body: { error: 'invalid_token', errorDescription: err.message } }; } };
3. 关键安全提示:验证令牌有效性
无论用哪种方式,服务器端都应该验证令牌的合法性,确保它是Auth0签发、未过期、受众正确的。对于id_token,可以用jsonwebtoken库结合Auth0的公钥来验证签名:
安装依赖:
npm install jsonwebtoken jwks-rsa
添加验证逻辑:
import jwt from 'jsonwebtoken'; import jwksClient from 'jwks-rsa'; import { env } from '$env/dynamic/private'; // 初始化JWKS客户端,用于获取Auth0的公钥 const jwksClientInstance = jwksClient({ jwksUri: `https://${env.AUTH0_DOMAIN}/.well-known/jwks.json` }); // 获取签名公钥的辅助函数 function getSigningKey(header, callback) { jwksClientInstance.getSigningKey(header.kid, (err, key) => { if (err) return callback(err); const signingKey = key.getPublicKey(); callback(null, signingKey); }); } // 在post处理函数中验证id_token const { idToken } = await request.json(); jwt.verify(idToken, getSigningKey, { audience: env.AUTH0_CLIENT_ID, issuer: `https://${env.AUTH0_DOMAIN}/`, algorithms: ['RS256'] }, (err, decodedToken) => { if (err) { console.error('Invalid ID token:', err); return { status: 401 }; } // decodedToken中包含用户的核心信息 console.log('Verified user:', decodedToken); });
核心问题就是误用了客户端库在服务器端环境,只要替换为服务器端兼容的Auth0工具,就能解决XMLHttpRequest未定义的错误,同时也能更安全地完成用户认证流程。
内容的提问来源于stack exchange,提问作者mcy

