PHP接入Firebase FCM主题订阅持续出现401认证错误求助
FCM主题订阅401错误排查与解决
问题描述
我尝试用PHP实现FCM主题订阅,更新后的代码如下:
// Path to your service account key file (JSON) $serviceAccountFile = PAD_PLUGIN_DIR . 'positive-notch-181410-2bc8875c71a4.json'; // Your FCM Topic name $topicName = get_the_category($post_id)[0]->slug; // Device token to subscribe $deviceToken = 'fuEMCQmCT_m0H3fdoXqD9m:APA91bGITP85Q6y3Zg3_Ls9bjbPKMBylwHads9hQbkzDJCeeOtlHfJZqxX4hIAJMeOoKYCfm59ki95tOpNViORr6cy4ATuCaDAubCkj1pdXzQsrI1lMeesZYRt-B_vCJO6R55NLfZRoM'; // Initialize Google Client $client = new Google_Client(); $client->setAuthConfig($serviceAccountFile); $client->addScope('https://www.googleapis.com/auth/firebase.messaging'); // Get an OAuth2 access token $accessToken = $client->fetchAccessTokenWithAssertion(); $accessTokenString = $accessToken['access_token']; $subscriptionUrl = 'https://iid.googleapis.com/iid/v1:batchAdd'; $data = [ 'to' => '/topics/blabla', 'registration_tokens' => [$deviceToken] ]; $ch = curl_init($subscriptionUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $accessTokenString, 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode == 200) { echo "Successfully subscribed to topic."; } else { echo "Failed to subscribe: " . $response; } exit;
执行后始终返回401错误,提示:Authentication using server key is deprecated. Please use an OAuth2 token instead.
已确认$accessTokenString有效未过期,且拥有已启用FCM的Google Cloud项目及对应服务账户JSON密钥文件,请问问题出在哪里?
问题根源与解决步骤
1. 核心问题:使用了不支持OAuth2的旧API端点
你调用的https://iid.googleapis.com/iid/v1:batchAdd是旧版IID API端点,该端点仅支持已废弃的服务器密钥认证,不兼容OAuth2令牌,这是导致401错误的直接原因。必须替换为FCM v1 API的官方订阅端点。
2. 具体修正操作
更换API端点:使用FCM v1规范的订阅端点,格式为:
https://fcm.googleapis.com/v1/projects/{你的项目ID}/topics/{主题名称}:batchAdd
项目ID可从服务账户JSON文件的project_id字段读取,或在Google Cloud控制台查看。修正请求体格式:FCM v1 API无需
to字段,直接传入registration_tokens数组即可。修复主题名称硬编码:代码中定义了
$topicName但未实际使用,需将请求体中的硬编码值替换为动态获取的主题名称。
3. 修正后的完整代码
// Path to your service account key file (JSON) $serviceAccountFile = PAD_PLUGIN_DIR . 'positive-notch-181410-2bc8875c71a4.json'; // 从服务账户JSON读取项目ID(也可手动填写) $serviceAccountData = json_decode(file_get_contents($serviceAccountFile), true); $projectId = $serviceAccountData['project_id']; // Your FCM Topic name $topicName = get_the_category($post_id)[0]->slug; // Device token to subscribe $deviceToken = 'fuEMCQmCT_m0H3fdoXqD9m:APA91bGITP85Q6y3Zg3_Ls9bjbPKMBylwHads9hQbkzDJCeeOtlHfJZqxX4hIAJMeOoKYCfm59ki95tOpNViORr6cy4ATuCaDAubCkj1pdXzQsrI1lMeesZYRt-B_vCJO6R55NLfZRoM'; // Initialize Google Client $client = new Google_Client(); $client->setAuthConfig($serviceAccountFile); $client->addScope('https://www.googleapis.com/auth/firebase.messaging'); // Get an OAuth2 access token $accessToken = $client->fetchAccessTokenWithAssertion(); $accessTokenString = $accessToken['access_token']; // FCM v1 API主题订阅端点 $subscriptionUrl = "https://fcm.googleapis.com/v1/projects/{$projectId}/topics/{$topicName}:batchAdd"; // 符合v1规范的请求体 $data = [ 'registration_tokens' => [$deviceToken] ]; $ch = curl_init($subscriptionUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $accessTokenString, 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode == 200) { echo "Successfully subscribed to topic."; } else { echo "Failed to subscribe: " . $response; } exit;
4. 额外验证项
- 确认服务账户已分配
Firebase Messaging Admin角色,或至少拥有firebase.messaging.topics.update权限 - 检查
$topicName是否正确获取到分类slug,避免空值或无效字符
内容的提问来源于stack exchange,提问作者asiermusa
相关产品推荐
相关产品推荐

