Week:05|FCM third-party-auth-error の原因はAPNsキーだった — Apple .p8キー管理の落とし穴

はじめに
Firebase Cloud Messaging(FCM)でiOSにプッシュ通知を送ろうとしたら、全送信が失敗した。
エラーは messaging/third-party-auth-error。Cloud Functionsのログでは success=0, failure=1 が並ぶ。
原因はAPNsキーだった。正確には、APNsキーだと思って登録していたファイルが、APNsキーではなかった。
この記事では、FCMのiOS通知で third-party-auth-error が出たときの調査手順と、Apple .p8 キーの管理で陥りやすい罠を共有する。
1. 問題
Cloud Functions v2からFCM v1 APIで通知を送信。全リクエストが失敗する。
messaging/third-party-auth-error
Firebase Consoleの Cloud Messaging 設定にはAPNsキーが登録されている。キーIDもTeam IDも入っている。一見、設定は正しく見える。
2. 調査
最初に疑ったこと(外れ)
-
IAMロールの不足: Cloud Functions v2のCompute Engineデフォルトサービスアカウントに
Firebase Cloud Messaging API Adminロールを付与 → 変わらず - firebase-admin SDKのバージョン: v13のAPIの変更を疑う → 関係なし
どちらも外れだった。third-party-auth-error はFirebaseとApple間の認証エラーであり、IAMやSDKは無関係だ。エラー名が示す通り、問題は「サードパーティ(Apple)との認証」にある。
有効だった調査: FCM v1 APIを直接叩く
Cloud Functions経由ではエラーの詳細が見えない。FCM v1 APIを直接呼び出して、レスポンスの詳細を確認した。
curl -X POST \
"https://fcm.googleapis.com/v1/projects/{PROJECT_ID}/messages:send" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"message": {
"token": "{DEVICE_TOKEN}",
"notification": { "title": "test", "body": "test" }
}
}'
レスポンスにAPNsからの詳細エラーが含まれていた。
InvalidProviderToken (403)
InvalidProviderToken はAPNsが「送られてきた認証トークンを検証できない」ときのエラー。つまり、Firebaseに登録したAPNsキーに問題がある。
3. 根本原因
Firebase Cloud Messagingに登録されていた .p8 キーを確認した。
キーIDは XXXXXXXXXX。
このキーは RevenueCat用に取得したApp Store Connect APIキー だった。APNsキーではない。
なぜ気づかなかったか
.p8 キーのファイル形式は用途に関係なく同じだ。ファイル名も AuthKey_XXXXX.p8 で統一されている。中身を見ても、どちらもECDSA P-256の秘密鍵で、見た目では区別がつかない。
「.p8 は .p8 でしょ。全部同じように使えるはず」——この思い込みが原因だった。
4. Apple .p8 キーの落とし穴
Apple の .p8 キーは複数の場所から発行され、それぞれ用途が異なる。ファイル形式は同じだが、互換性はない。
発行元と用途
| 発行元 | 用途 | 使用先 |
|---|---|---|
| Apple Developer → Certificates, Identifiers & Profiles → Keys | APNs(プッシュ通知) | Firebase Cloud Messaging |
| Apple Developer → Certificates, Identifiers & Profiles → Keys | Sign In with Apple | Firebase Auth |
| App Store Connect → Users and Access → Integrations → Keys | App Store Connect API | RevenueCat, Fastlane等 |
| App Store Connect → Users and Access → Integrations → In-App Purchase | In-App Purchase | サーバー側の課金検証 |
見分け方
ファイル名 AuthKey_XXXXX.p8 の XXXXX がキーIDだが、これだけでは用途はわからない。
確認方法:
- Apple Developer → Keys に表示されるキーは、APNs / Sign In with Apple 用
- App Store Connect → Integrations → Keys に表示されるキーは、API用
- App Store Connect → Integrations → In-App Purchase に表示されるキーは、課金検証用
Firebase Cloud Messagingに登録すべきは、Apple Developer → Keys で APNs を有効にして発行したキーだ。App Store Connect APIキーをここに登録しても InvalidProviderToken になる。
5. 正しい管理方法
用途別のフォルダ管理
_credentials/
├── apns/
│ └── AuthKey_YYYYYYYYYY.p8 # APNs用
├── auth/
│ └── AuthKey_ZZZZZZZZZZ.p8 # Sign In with Apple用
├── revenuecat/
│ └── AuthKey_XXXXXXXXXX.p8 # App Store Connect API用
└── README.md # 各キーの用途・発行元・登録先
ドキュメント化
各キーについて以下を記録する。
| 項目 | 記録内容 |
|---|---|
| Key ID | YYYYYYYYYY |
| 発行元 | Apple Developer → Keys |
| 用途 | APNs(プッシュ通知) |
| 登録先 | Firebase Console → Cloud Messaging(dev/prod) |
| 作成日 | 2026-03-02 |
| 備考 | Sandbox & Production、Team Scoped |
.p8 ファイルはダウンロードが1回限りのため、紛失すると再発行が必要になる。保管場所と用途を明確にしておくことが重要だ。
6. 修正手順
今回実施した修正手順を残しておく。
-
Apple Developer Console → Keys で新規キー作成
- 名前:
Push Notifications(アプリ名を含めない。全アプリ共通で使用) - サービス: Apple Push Notifications service (APNs) を有効化
-
.p8ファイルをダウンロード(1回限り)
- 名前:
-
Firebase Console → Cloud Messaging で設定変更
- 間違ったキーを削除
- 新しいAPNsキー(Key ID + Team ID +
.p8ファイル)を登録 - dev / prod 両方で実施
-
動作確認
- 別アカウントからアクションを実行(いいね等)
- 端末に通知バナーが表示されることを確認
修正自体は1時間で完了した。
7. 教訓
third-party-auth-error が出たら
- Cloud Functions経由ではなく、FCM v1 APIを直接叩いてAPNsの詳細エラーを確認する
-
InvalidProviderTokenなら、登録しているキーの用途を疑う - Firebase Console → Cloud Messagingに登録されたKey IDが、Apple Developer → Keys のどのキーに対応するかを確認する
.p8 キーを扱うとき
- ファイル形式が同じでも、発行元が違えば互換性はない
- キーIDだけでは用途がわからない。フォルダとドキュメントで管理する
- 「このキーで合っているはず」で進めず、発行元と用途を突き合わせて確認する
設定系トラブル全般
third-party-auth-error 系の問題は、コードやログだけを追っていても解決しない。Firebase Console、Apple Developer Consoleの管理画面を直接確認する方が圧倒的に速い。
登録されているKey IDが正しい発行元のキーかどうかは、管理画面と照合して初めてわかる。ツールやAPIで間接的に確認しようとすると遠回りになる。
この障害が起きた背景や、AI開発を通じて見えた「AIの得意・不得意」については、別の記事にまとめています。
開発ログとして週次でまとめているnote記事はこちら。
Discussion