使用jwt-decode解码react-native-apple-authentication的identityToken失败
苹果登录JWT解析报错:InvalidTokenError 排查与解决
问题背景
我按照react-native-apple-authentication文档实现苹果登录,需要通过jwt-decode解析返回的identityToken获取邮箱等用户信息。参考jwt-decode的polyfill说明,因为node_modules里没有core-js,所以改用import "atob",代码如下:
import { jwtDecode } from "jwt-decode"; import "atob" const signInAppleAuth = async () => { const appleAuthRequestResponse = await appleAuth.performRequest({ requestedOperation: appleAuth.Operation.LOGIN, requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL], }); const { identityToken } = appleAuthRequestResponse const decoded = jwtDecode(identityToken) console.log(" decoded: ", decoded); }
运行后抛出错误:
InvalidTokenError: Invalid token specified: invalid json for part #2
(JSON Parse error: Unable to parse JSON string)
获取到的identityToken如下(在jwt.io上可正常解析):
eyJraWQiOiJZdXlYb1kiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoib3JnLnJlYWN0anMubmF0aXZlLmV4YW1wbGUuSGFwcHlTdW5ueUhvdXJGcm9udCIsImV4cCI6MTcwMjEyODEwNSwiaWF0IjoxNzAyMDQxNzA1LCJzdWIiOiIwMDAxOTUuZWQ1M2RjMTk1MDA1NDU2NTk5Yjk2YzMzMGY5ZmUwNTIuMTU1MyIsIm5vbmNlIjoiYWU1ZmIwY2Y4MWI1YzlhNjNiOWY2NmEzOWZkNjgxZmQzZmU2NWI4MDFmNjRiZTE0MTQ4OGY5NTRlMmM4MDc0OSIsImNfaGFzaCI6Iko0S3NGTV85c0NzbzBhS0p5aXhzRmciLCJhdXRoX3RpbWUiOjE3MDIwNDE3MDUsIm5vbmNlX3N1cHBvcnRlZCI6dHJ1ZX0.uCNoY1FfPwB4rry7-0yVsQapPWnmTEpqhcLpg81xoC5b3u6nGRfjWhMjJZK2_gfIeGqb1DR9-eVlzl5JVMOownVTEQljP1kSrfRQzyUhBRlI_cMa9xqfSf9SOoySg8YshgTZcdlV-M9HIJVHjQYHjwS2relaXd7whHy1ps5pOF2QjYsTaQfpFJgajGjSZXFzNEKTyCtoaDWrAq5zlqAInY7WoCbswSNcOctTwaiTnhi36faWaNC2RPV2jwiNqDT1mSZHqzxjDH2-C_c8o9EWdwq0ShWcc0ILBlFs0jzVAtNgcRc9626OdYzXblzORktXVi9-TY43XzGeGTY_fqfE6g
另外我的项目中没有base-64模块,无法使用import { decode } from "base-64"; global.atob = decode;这个方案,请问问题出在哪?怎么解决?
问题原因
- atob未正确挂载到全局:你导入的
atob包没有自动把方法挂载到global对象上,而jwt-decode依赖全局的atob来解码JWT的base64部分,导致解码失败。 - JWT的Base64格式兼容问题:苹果返回的JWT使用的是URL-safe Base64(将
+替换为-,/替换为_,并省略了填充符=),部分atob实现不兼容这种格式,直接解码会得到无效的JSON字符串。
解决方法
方法1:手动将atob挂载到全局
修改导入方式,手动把atob赋值给全局对象,确保jwt-decode能调用到:
import { jwtDecode } from "jwt-decode"; import atob from 'atob'; // 手动挂载到全局环境 global.atob = atob; const signInAppleAuth = async () => { const appleAuthRequestResponse = await appleAuth.performRequest({ requestedOperation: appleAuth.Operation.LOGIN, requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL], }); const { identityToken } = appleAuthRequestResponse; const decoded = jwtDecode(identityToken); console.log("解码结果: ", decoded); };
方法2:手动处理JWT的Base64格式
如果不想依赖全局的atob,可以手动拆分JWT并处理URL-safe Base64格式后解码:
import { jwtDecode } from "jwt-decode"; // 自定义处理URL-safe Base64的方法 const fixBase64 = (base64String) => { // 替换URL-safe字符,补全填充符 return base64String.replace(/-/g, '+').replace(/_/g, '/').padEnd(base64String.length + (4 - base64String.length % 4) % 4, '='); }; const signInAppleAuth = async () => { const appleAuthRequestResponse = await appleAuth.performRequest({ requestedOperation: appleAuth.Operation.LOGIN, requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL], }); let { identityToken } = appleAuthRequestResponse; // 手动修复token的base64格式后再解码 const [header, payload, signature] = identityToken.split('.'); const fixedPayload = fixBase64(payload); // 重新拼接token identityToken = `${header}.${fixedPayload}.${signature}`; const decoded = jwtDecode(identityToken); console.log("解码结果: ", decoded); };
方法3:手动解析JWT(不依赖jwt-decode)
如果上述方法都不行,可以完全手动解析JWT,避免依赖第三方库的polyfill:
const signInAppleAuth = async () => { const appleAuthRequestResponse = await appleAuth.performRequest({ requestedOperation: appleAuth.Operation.LOGIN, requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL], }); const { identityToken } = appleAuthRequestResponse; // 手动拆分并解析JWT const [, payloadBase64] = identityToken.split('.'); const fixedPayload = payloadBase64.replace(/-/g, '+').replace(/_/g, '/').padEnd(payloadBase64.length + (4 - payloadBase64.length % 4) % 4, '='); const decodedPayload = JSON.parse(atob(fixedPayload)); console.log("解码结果: ", decodedPayload); };
内容的提问来源于stack exchange,提问作者BenoHiT
相关产品推荐
相关产品推荐

