Expo React Native项目PHP端无法验证Firebase ID Token求助
Expo Firebase登录ID Token后端PHP验证失败问题
我有一个基于Expo的项目,使用Firebase的createUserWithEmailAndPassword和signInWithEmailAndPassword实现客户端登录,功能正常。但在PHP后端用JWT PHP库和Kreait Firebase Admin SDK验证ID Token时,分别出现「Signature verification failed」和「invalid token」错误。
环境配置
- 使用
npm expo install firebase安装Firebase依赖 - 通过
npm expo run:ios --device在iOS设备上运行项目 - 后端采用PHP开发
React Native相关代码片段
import { initializeApp } from 'firebase/app'; import { getAuth, signInWithEmailAndPassword, createUserWithEmailAndPassword, updateProfile } from 'firebase/auth'; const firebaseConfig = { apiKey: "AIzaxxxxxxxxxxxxxxxxxxJxk", authDomain: "oxxxxxxxxx.firebaseapp.com", projectId: "oxxx-xxxx", storageBucket: "oxxx-xxxx.firebasestorage.app", messagingSenderId: "1111111111", appId: "1:111111111:web:1111111111", measurementId: "G-5555555555" }; export default function Index() { const app = initializeApp(firebaseConfig); const auth = getAuth(app); // Email/Password Authentication const handleEmailAuth = async () => { if (!email || !password) { Alert.alert('Error', 'Please fill in all fields'); return; } if (!isLogin && password !== confirmPassword) { Alert.alert('Error', 'Passwords do not match'); return; } if (!isLogin && !name.trim()) { Alert.alert('Error', 'Please enter your name'); return; } setLoading(true); try { let userCredential; if (isLogin) { userCredential = await signInWithEmailAndPassword(auth, email, password); } else { userCredential = await createUserWithEmailAndPassword(auth, email, password); } // Update user profile with name await updateProfile(userCredential.user, { displayName: name.trim() }).then(() => { userCredential.user.reload().then(() => { console.log('Profile reloaded - displayname: ' + JSON.stringify(userCredential.user)); }); }).catch((error) => { console.log(error); }); await registerUserInBackend(auth.currentUser, "emailpwd"); } catch (error: any) { Alert.alert('Error', error.message); } finally { setLoading(false); } }; const registerUserInBackend = async (responsedata: any, provider: string) => { try { const user = (provider == "google" ? responsedata.user : responsedata); const firebaseIdToken = provider!="google" ? JSON.stringify(await user.getIdToken(true)): null; const response = await fetch('https://qqqqqqqq.com/register_user.php', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ idToken: provider == "google" ? responsedata.idToken : firebaseIdToken, email: user.email, name: provider=="google" ? user.name : user.displayName, photo_url: provider == "google" ? user.photo: "", provider: provider }) }); const data = await response.json(); if (data.success) { storeUserSession(user, data.uid, responsedata.idToken); await signIn({ uid: data.uid, accessToken: responsedata.accessToken, email: user.email, displayName: user.name, photoURL: user.photo }); router.replace('/(tabs)/mainScreen'); setLoading(false); } else { setLoading(false); throw new Error(data.error); } } catch (error) { console.error('Backend registration error:', error); } };
PHP相关代码片段
require_once '../../vendor/autoload.php'; use Google\Client as GoogleClient; use Kreait\Firebase\Factory; use Kreait\Firebase\Auth; use Firebase\JWT\JWT; use Firebase\JWT\Key; use GuzzleHttp\Client; public function verifyFirebaseIdToken($idToken) { try { error_log('inside verifyFirebaseIdToken'.$idToken); // Verify the ID token $verifiedIdToken = $this->auth->verifyIdToken($idToken); // Get user info return [ 'success' => true, 'uid' => $verifiedIdToken->claims()->get('sub'), 'email' => $verifiedIdToken->claims()->get('email'), 'email_verified' => $verifiedIdToken->claims()->get('email_verified'), 'name' => $verifiedIdToken->claims()->get('name') ]; } catch (\Kreait\Firebase\Exception\Auth\FailedToVerifyToken $e) { error_log('inside catch1'.$e); return ['success' => false, 'error' => 'Invalid token']; } catch (\Exception $e) { error_log('inside catch2'.$e); return ['success' => false, 'error' => $e->getMessage()]; } } public function verifyIdToken($idToken) { try { $tokenParts = explode('.', $idToken); if (count($tokenParts) != 3) { throw new Exception('Invalid token format'); } // Get token header to determine which key to use $header = json_decode(base64_decode($tokenParts[0]), true); if (!isset($header['kid']) || !isset($this->publicKeys[$header['kid']])) { throw new Exception('Invalid token header'); } $publicKey = $this->publicKeys[$header['kid']]; error_log('verifyIdToken - idtoken:'.$idToken); error_log('verifyIdToken - kid:'.$header['kid']); error_log('verifyIdToken - publicKey:'.$publicKey); $decodedToken = JWT::decode($idToken, new Key($publicKey, 'RS256')); error_log('verifyIdToken - decodedToken:'.$decodedToken); // Verify issuer and audience if ($decodedToken->iss !== 'https://securetoken.google.com/oxxx-00000') { throw new Exception('Invalid token issuer'); } return [ 'success' => true, 'uid' => $decodedToken->sub, 'email' => $decodedToken->email ?? null, 'email_verified' => $decodedToken->email_verified ?? false, 'name' => $decodedToken->name ?? null ]; } catch (Exception $e) { return ['success' => false, 'error' => $e->getMessage()]; } } // in register_user.php error_log('token: '.$data['idToken']); error_log('email: '.$data['email']); if($data['provider']=='google') $verifyTokenResponse = $Oxxx->validateGoogleToken($data['idToken']); else $verifyTokenResponse = $Oxxx->verifyFirebaseIdToken($data['idToken']); error_log('verifyTokenResponse: '.implode($verifyTokenResponse));
已完成的配置
- Firebase控制台已配置iOS、Android和Web平台
- 已添加GoogleServices.plist到项目根目录
- 曾尝试使用react-native-firebase/auth及/app模块,仍出现相同错误;最终改用
npm install firebase - 已尝试删除node_modules并重新安装(
npm install + pod install),问题依旧
已验证的内容
- 客户端与服务端打印的idToken完全一致
- idToken中的kid可在Google公开密钥列表中找到
- Firebase控制台「用户」标签显示用户已成功注册
- 在jwt.io中可正常解码idToken,能看到正确的头部和负载信息,但始终显示「invalid signature」
- 在
handleEmailAuth()中尝试传递userCredential.user替代auth.currentUser,错误仍存在
请问我遗漏了什么配置或步骤?希望有经验的开发者能提供帮助。
内容的提问来源于stack exchange,提问作者jbrn_81
相关产品推荐
相关产品推荐

