You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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;这个方案,请问问题出在哪?怎么解决?

问题原因

  1. atob未正确挂载到全局:你导入的atob包没有自动把方法挂载到global对象上,而jwt-decode依赖全局的atob来解码JWT的base64部分,导致解码失败。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 16:00:57