GEMINI LABEN
NANOLITE — Nano Banana 2 Liteが登場しました。Googleで最も速く、最もコスト効率の高いGemini Imageモデルで、軽量な画像生成を安く回したい用途に向いていますOMNIFLASH — Gemini Omni Flashがpublic previewになりました。ネイティブにマルチモーダルなモデルで、企業や開発者が独自の動的な動画ワークフローを構築できますAGENTS — Managed Agentsが拡張されました。background: trueでサーバー側の非同期実行とポーリング、リモートMCPサーバー連携、対話をまたぐ認証情報のリフレッシュに対応しますMEMORY — Memory BankのIngestEvents APIが一般提供になりました。イベントの取り込みとメモリ生成を分離し、コンテンツを継続的にストリームできますTHROUGHPUT — Provisioned Throughputで、同一モデル・同一リージョンに対して最大7件の保留オーダーを提出できるようになりましたDEPRECATE — 画像生成モデルは8月17日に、Gemini Enterprise Agent PlatformのGrok 4.1系は8月20日に停止される予定ですNANOLITE — Nano Banana 2 Liteが登場しました。Googleで最も速く、最もコスト効率の高いGemini Imageモデルで、軽量な画像生成を安く回したい用途に向いていますOMNIFLASH — Gemini Omni Flashがpublic previewになりました。ネイティブにマルチモーダルなモデルで、企業や開発者が独自の動的な動画ワークフローを構築できますAGENTS — Managed Agentsが拡張されました。background: trueでサーバー側の非同期実行とポーリング、リモートMCPサーバー連携、対話をまたぐ認証情報のリフレッシュに対応しますMEMORY — Memory BankのIngestEvents APIが一般提供になりました。イベントの取り込みとメモリ生成を分離し、コンテンツを継続的にストリームできますTHROUGHPUT — Provisioned Throughputで、同一モデル・同一リージョンに対して最大7件の保留オーダーを提出できるようになりましたDEPRECATE — 画像生成モデルは8月17日に、Gemini Enterprise Agent PlatformのGrok 4.1系は8月20日に停止される予定です
記事一覧/API / SDK
API / SDK/2026-06-02中級

Firebase AI Logic で iOS から Gemini を呼ぶと 403 になる原因と対処

Firebase AI Logic(旧 Vertex AI in Firebase)で iOS アプリから Gemini を呼び出すと 403 PERMISSION_DENIED が返る問題。App Check の強制適用・API 未有効化・Blaze 未設定の3つの原因を切り分けて解決する手順を、実機検証の経験から整理します。

gemini-api279firebase6ios12troubleshooting57app-check

2014年からアプリ事業を続けている個人開発者として、Firebase AI Logic を自分の iOS アプリに組み込んだとき、シミュレータでは動くのに TestFlight に上げた瞬間すべての Gemini 呼び出しが 403 で落ちる、という現象に丸一日悩まされました。

エラーメッセージ自体は短く、The request is missing a valid API keyPERMISSION_DENIED としか出ないため、原因がコードなのか設定なのか判別しづらいのが厄介です。以下では、累計5,000万ダウンロードの自社アプリに Gemini を組み込む過程で私が実際にぶつかった3つの原因と、その切り分け手順を、実機検証の経験からまとめます。

まず出ている 403 の中身を確認する

Firebase AI Logic(Swift では FirebaseAI モジュール)で Gemini を呼ぶと、失敗時には次のような形でエラーが返ります。

import FirebaseAI
 
let model = FirebaseAI.firebaseAI(backend: .googleAI())
    .generativeModel(modelName: "gemini-2.5-flash")
 
do {
    let response = try await model.generateContent("こんにちは")
    print(response.text ?? "")
} catch {
    // ここで握りつぶさず、必ず error をそのまま出力する
    print("Gemini call failed:", error)
}

catch 節で error をそのまま print すると、ログに httpStatusCode = 403 と一緒に status: PERMISSION_DENIEDApp Check token is invalid といった詳細が出ます。まずこの全文を読むことが切り分けの起点です。response.text が nil だから、と曖昧に判断して進めると遠回りになります。

403 の裏には、大きく分けて次の3つの原因があります。上から順に確認していくのが早道です。

原因1: App Check が強制適用されているのにトークンが出ていない(最頻出)

私のケースで犯人だったのがこれです。Firebase コンソールで App Check を「強制(Enforce)」に切り替えると、有効な App Check トークンを持たないリクエストはすべて 403 で拒否されます。シミュレータで動いて実機やTestFlightで落ちるのは、シミュレータでは debug provider のトークンが通っていたのに、実機では App Attest プロバイダを初期化していなかったためでした。

対処は、FirebaseApp.configure() に App Check プロバイダを設定することです。順序を間違えると、Firebase が初期化された後にプロバイダが差し替わり、最初の数リクエストがトークンなしで飛びます。

import FirebaseCore
import FirebaseAppCheck
 
class AppCheckSetup: NSObject, AppCheckProviderFactory {
    func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
        // iOS 14 以降の実機は App Attest、それ以前は DeviceCheck
        if #available(iOS 14.0, *) {
            return AppAttestProvider(app: app)
        }
        return DeviceCheckProvider(app: app)
    }
}
 
// AppDelegate / App 起動時、configure より前に呼ぶ
AppCheck.setAppCheckProviderFactory(AppCheckSetup())
FirebaseApp.configure()

開発中にシミュレータで検証したいときは、debug provider を使い、コンソールに出力されるデバッグトークンを Firebase コンソールの「App Check → アプリ → デバッグトークンを管理」に登録します。

#if DEBUG
AppCheck.setAppCheckProviderFactory(AppCheckDebugProviderFactory())
#else
AppCheck.setAppCheckProviderFactory(AppCheckSetup())
#endif
FirebaseApp.configure()

ここで一つ注意点があります。App Attest はサーバー側で実機の正当性を検証するため、TestFlight ビルドであっても初回の検証に数秒かかることがあります。アプリ起動直後に即座に Gemini を呼ぶ設計だと、トークンがまだ発行されておらず 403 になることがあるので、最初の呼び出しはユーザー操作を待つか、軽いリトライを挟むと安定します。

原因2: 必要な Google API が有効化されていない

Firebase コンソールの「AI Logic」から初回セットアップをウィザード経由で行うと、必要な API は自動で有効化されます。しかし、別の Firebase プロジェクトを流用したり、GoogleService-Info.plist だけ差し替えて使い回したりすると、API が無効のままで 403 になります。

使用するバックエンドによって必要な API が異なります。

  • Gemini Developer API バックエンド.googleAI()): firebasevertexai.googleapis.com と Generative Language API
  • Vertex AI バックエンド.vertexAI()): aiplatform.googleapis.com

Google Cloud Console の「API とサービス → 有効な API」で、対象プロジェクトに上記が並んでいるか確認します。コマンドで確認・有効化する場合は次の通りです。

# 有効化済みか確認
gcloud services list --enabled --project=YOUR_PROJECT_ID | grep -E "aiplatform|firebasevertexai"
 
# 足りなければ有効化(Vertex AI バックエンドの例)
gcloud services enable aiplatform.googleapis.com --project=YOUR_PROJECT_ID

私の経験上、既存アプリに後から AI 機能を足すときにこの罠を踏みやすいです。新規ウィザードを通っていないプロジェクトは、まずここを疑ってください。

原因3: Blaze プラン(従量課金)が未設定

Vertex AI バックエンドを使う場合、プロジェクトが無料の Spark プランのままだと、課金が必要なため 403 もしくは課金関連のエラーになります。Firebase コンソールの「使用量と請求」から Blaze プランへアップグレードすると解消します。

Gemini Developer API バックエンドは無料枠の範囲なら Spark プランでも動きますが、本番アプリでレート制限を避けたいなら、いずれにせよ Blaze への移行を検討することになります。コストが不安な場合は、Google Cloud の予算アラートを設定しておくと安心です。

切り分けの順序をまとめると

403 に当たったら、次の順で確認すると最短で原因にたどり着けます。

  1. catch でエラー全文を出力し、App Check token is invalid の文字列があるか確認する → あれば原因1
  2. なければ Google Cloud Console で対象 API が有効か確認する → 無効なら原因2
  3. API も有効なら、課金プランが Blaze かを確認する → Spark なら原因3
  4. すべて満たしているのに 403 が続く場合は、GoogleService-Info.plist呼び出し元プロジェクトのものと一致しているかを確認する(別環境の plist を混入させていると、コンソールで見ている設定と実際の宛先がずれます)

特に1と4は、コンソール上の設定だけ見ていても気づけません。実機ログのエラー全文と、ビルドに含まれている plist の PROJECT_ID を突き合わせるのが確実です。

再発を防ぐために

私は今、AI 機能を持つアプリのリリースチェックリストに「App Check を強制適用する前に、実機(TestFlight)で App Attest トークンが発行されることを確認する」という項目を入れています。強制適用は最後に切り替える設定であって、開発初期から有効にすると、原因の切り分けが一気に難しくなるからです。

開発中は App Check を「強制」ではなく「未強制(モニタリングのみ)」にしておき、トークンの発行状況をコンソールで観察してから本番で強制に切り替える。この順番にしてから、403 に振り回されることがなくなりました。

同じところでつまずいている方の参考になれば幸いです。

シェア

お読みいただきありがとうございます

Gemini Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

API / SDK2026-05-05
Gemini APIキーをモバイルアプリに埋め込んではいけない:Firebase App Check で実現する多層防御アーキテクチャ
モバイルアプリでGemini APIを安全に使うためのバックエンド設計パターン。Firebase App Check・Cloud Functions・レートリミット・異常検知を組み合わせた本番グレードの多層防御実装ガイド。
API / SDK2026-07-01
AI Studio で通ったプロンプトが API では静かに崩れるとき — 差分を計測して切り分ける運用メモ
AI Studio では完璧に動いたプロンプトが、自分のコードから Gemini API を呼ぶと空応答や 404 になる。目視ではなく、設定差と finish_reason・使用トークン・解決モデル名を機械的に記録する小さなハーネスで、原因別に切り分ける運用手順をまとめました。
API / SDK2026-06-23
Gemini 3.2 Pro の Function Calling を iOS/Android アプリに統合する実装パターン
Gemini 3.2 Pro の Function Calling を iOS/Android アプリに統合する実装ガイド。SwiftUI・Kotlin 両対応の動くコード例と、個人開発の壁紙アプリで実証した本番設計パターン(コスト・レイテンシ・段階ロールアウト・回帰テスト)を解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →