升级Apollo Server 4后遇JsonWebTokenError: jwt malformed问题求助
Auth0 + Apollo Server 4 验证Bearer Token时出现
JsonWebTokenError: jwt malformed错误 升级到Apollo Server 4后,使用Auth0验证Bearer Token时持续触发错误:JsonWebTokenError: jwt malformed。根据文档说明,该错误是因为Token缺少.分隔的三个组件之一,检查提供的Token确实存在连续的..,结构不符合标准JWT要求。
提供的Bearer Token:
eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaXNzIjoiaHR0cHM6Ly9kZXYteWpkczdzMHcudXMuYXV0aDAuY29tLyJ9..ra0kpvVLjOY5SXNL.QcHMSTrOB1gewFkjwJdg3MHCr0UfdS0tKA2XdskUKp8_10puH_oq6meSs9x6f_LDZHeYfJso8QaofxDhNvlpWU2zQFbmPD_tJtTui4jCqNFpYM6Aapw6d7ADeckl0vjsBVs9AdJHUF_6tlBtI6s8Qk6r4UtufKSGfpm5ucb2FeCz-9DREH19QGCBzundoi5goSKK4Br8VhZTrP89KZDwQYSYWR-SXXrAUSz3mhDPbYQjrPeyVZtt4WCHwgCweF-iLHkMI6g82zKYbNUHImfcSZcmNgYS3sTL6MkKLKr9oOkgLyR0KDA2r22vKracFdoZB0g.Lk0ClIc1usAEXFaGzO-hDg
服务器代码
import { ApolloServer } from '@apollo/server'; import { startStandaloneServer } from '@apollo/server/standalone'; import resolvers from './graphql/Resolvers.js'; import { typeDefs } from './graphql/gqlSchema.js'; import verifyToken from './verifyToken.js'; import config from './config.cjs'; import startMongo from './Mongo/StartMongo.js'; const server = new ApolloServer({ cors: { origin: 'https://www.timerwise.com' }, typeDefs, resolvers, }); const { url } = await startStandaloneServer(server, { context: async ({ req }) => { let isAuthenticated = false; let token; try { const authHeader = req.headers.authorization || ''; if (authHeader) { const token = authHeader.split(' ')[1]; const payload = await verifyToken(token); isAuthenticated = payload && payload.sub ? true : false; } } catch (error) { console.error(error); } return { req, auth: { token, isAuthenticated } }; }, listen: { port: config.PORT }, }); startMongo(); console.log(`🚀 Server ready at ${url}`);
Token验证代码
import jwt from 'jsonwebtoken'; import jwksClient from 'jwks-rsa'; import config from './config.cjs'; const verifyToken = async (bearerToken) => { const client = jwksClient({ jwksUri: `https://${config.AUTH0_DOMAIN}/.well-known/jwks.json` }); function getJwksClientKey(header, callback) { client.getSigningKey(header.kid, function (error, key) { const signingKey = key.publicKey || key.rsaPublicKey; callback(null, signingKey); }); } return new Promise((resolve, reject) => { jwt.verify( bearerToken, getJwksClientKey, { audience: config.AUDIENCE, issuer: `https://${config.AUTH0_DOMAIN}/`, algorithms: ['RS256'], }, function (err, decoded) { console.log(bearerToken); if (err) reject(err); resolve(decoded); } ); }); }; export default verifyToken;
问题原因与解决方案
核心原因
你提供的Token是加密JWT(JWE),而非标准的签名JWT(JWS)。jsonwebtoken库仅支持JWS格式,无法解析JWE,因此会判定Token格式错误。另外,服务器代码中存在变量作用域问题:context里的const token会覆盖外层的let token,导致返回的auth.token始终为undefined,不过这不是触发格式错误的直接原因。
解决方案
- 确认Token类型:检查Auth0应用配置,确保前端获取的是JWS格式的Token(比如ID Token或Access Token),而非加密的JWE。如果是前端请求时参数错误导致获取到JWE,调整请求参数即可。
- 替换为支持JWE的库:如果确实需要处理JWE,弃用不再维护的
jsonwebtoken,改用jose库(支持JWS和JWE)。示例验证代码如下:
import { createRemoteJWKSet, jwtVerify } from 'jose'; import config from './config.cjs'; const verifyToken = async (bearerToken) => { const jwks = createRemoteJWKSet(new URL(`https://${config.AUTH0_DOMAIN}/.well-known/jwks.json`)); const { payload } = await jwtVerify(bearerToken, jwks, { audience: config.AUDIENCE, issuer: `https://${config.AUTH0_DOMAIN}/`, }); return payload; }; export default verifyToken;
- 修复变量作用域问题:将服务器代码中
const token = authHeader.split(' ')[1];改为token = authHeader.split(' ')[1];,避免变量覆盖导致的逻辑异常。
内容的提问来源于stack exchange,提问作者Dom355
相关产品推荐
相关产品推荐

