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

如何使用expo-apple-authentication对接React Native Firebase Auth?

解决Expo Apple Authentication + Firebase Auth的invalid-credential错误

问题背景

用expo-apple-authentication对接Firebase Auth时,已在Firebase控制台配置好Apple登录提供商,但调用signInAsync后仅拿到identityToken和授权码。手动生成nonce配合identityToken传给Firebase时,触发[auth/invalid-credential] The supplied auth credential is malformed or has expired错误。

核心问题

你当前代码的问题是拿到Apple返回的token后才生成nonce,但Firebase要求的nonce必须满足三个关键条件:

  1. 必须在请求Apple登录前生成
  2. 要将哈希后的nonce传给Apple,让Apple用它签名identityToken
  3. 传给Firebase的是原始未哈希的nonce,用于验证Apple签名的有效性

前后nonce不匹配的话,Firebase会直接判定凭证无效。

解决步骤

  1. 提前生成原始nonce:在调用signInAsync前生成随机字符串作为nonce
  2. 对nonce做SHA-256哈希:Apple要求传入的nonce是哈希后的值
  3. 将哈希后的nonce传入Apple登录请求:让Apple用这个哈希值签名identityToken
  4. 用原始nonce和Apple返回的identityToken生成Firebase凭证

修正后的完整代码

import * as AppleAuthentication from 'expo-apple-authentication';
import { auth } from '../path/to/your/firebase/config'; // 替换成你的Firebase配置路径
import * as Crypto from 'expo-crypto'; // 需先安装:npx expo install expo-crypto

// 生成随机nonce,移除Apple不允许的特殊字符
const generateRandomNonce = () => {
  const randomBytes = Crypto.getRandomBytes(32);
  return Crypto.bytesToBase64(randomBytes).replace(/[+/=]/g, '');
};

// 对nonce做SHA-256哈希
const hashNonce = async (nonce) => {
  const utf8 = new TextEncoder().encode(nonce);
  const hashBuffer = await Crypto.digestStringAsync(
    Crypto.CryptoDigestAlgorithm.SHA256,
    utf8
  );
  return Array.from(new Uint8Array(hashBuffer))
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('');
};

const signInWithApple = async () => {
  try {
    // 1. 生成原始nonce
    const rawNonce = generateRandomNonce();
    // 2. 生成哈希后的nonce
    const hashedNonce = await hashNonce(rawNonce);

    // 3. 调用Apple登录,传入哈希后的nonce
    const credential = await AppleAuthentication.signInAsync({
      requestedScopes: [
        AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
        AppleAuthentication.AppleAuthenticationScope.EMAIL,
      ],
      nonce: hashedNonce,
    });

    if (!credential.identityToken) {
      throw new Error("Apple登录失败:未返回identity token");
    }

    // 4. 用原始nonce和identityToken生成Firebase凭证
    const appleCredential = auth.AppleAuthProvider.credential(
      credential.identityToken,
      rawNonce
    );

    // 完成Firebase登录
    await auth().signInWithCredential(appleCredential);
    console.log("Apple登录成功");
  } catch (error) {
    console.error("Apple登录出错:", error);
  }
};

额外注意事项

  • 必须用真实iOS设备测试,Apple Sign-In在模拟器上可能无法正常返回identityToken
  • 确保Firebase控制台的Apple提供商配置正确:
    • 填写正确的团队ID、服务ID、密钥ID和私钥
    • 回调URL要和你的App配置一致(比如Expo Go的回调URL是exp://localhost:19000,生产环境用App的bundle ID对应的URL)
  • 若使用Expo,务必安装expo-crypto,原生React Native环境可使用crypto模块,但需额外配置

内容的提问来源于stack exchange,提问作者Victor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 15:32:32