Skip to content

App Check: all Exchange* methods return 403 PERMISSION_DENIED on iOS while GenerateAppAttestChallenge succeeds 100% #18399

Description

@jansabai

Environment

  • firebase_app_check: 0.4.5 (also reproduced on 0.3.2+10 before upgrading)
  • firebase_core: 4.11.0
  • Firebase project: hex2hex-a6377 (Blaze, fully activated billing — confirmed not a Free Trial account)
  • iOS app ID: 1:1073646974663:ios:d4f17b64428b2262be70e2
  • Bundle ID: com.homesweethome.hex2hex / Apple Team ID: DR45PFUQ65
  • Reproduced on two real physical devices (iOS 26.5 and iOS 16.7.16) — never tried in a simulator

Error (identical for every provider tried — see below)

HTTP 403
{ "error": { "code": 403, "message": "App Attestation failed.", "status": "PERMISSION_DENIED" } }

The key signal: per-method error rates

Google Cloud Console → APIs & Services → Firebase App Check API, per-method breakdown over the same period:

Method Requests Error rate
GenerateAppAttestChallenge 50 0%
ExchangeAppAttestAttestation 48 100%
ExchangeDebugToken 12 100%
ExchangeDeviceCheckToken 4 100%

Every token-exchange method fails unconditionally; the preceding challenge-generation step always succeeds.

Decisive test: provider swap

Switched providerApple from AppleAppAttestProvider() to AppleDeviceCheckProvider() — a completely different attestation mechanism with no dependency on the App Attest capability or entitlement. Result: identical PERMISSION_DENIED. This rules out anything App-Attest-specific; the failure appears to be at the project/App-Check-backend level, affecting every attestation method uniformly, while challenge generation always succeeds.

Full list of verified, ruled-out causes

  1. iOS app ID confirmed as the only registered iOS app (firebase apps:list IOS); found and fixed an earlier local mismatch where our firebase_options.dart pointed at a stale, deleted app ID — no change to this error.
  2. Bundle ID matches exactly across Xcode, GoogleService-Info.plist, and Apple Developer Portal.
  3. Apple Team ID matches exactly, triple-checked.
  4. App Attest capability + "App Attest Opt-In" explicitly enabled on the Apple Developer Portal App ID (found and fixed it being unchecked) — no change.
  5. Local entitlement (com.apple.developer.devicecheck.appattest-environment) added and confirmed actually embedded in the signed binary via codesign -d --entitlements :- — no change.
  6. Waited several real hours for possible Apple-side capability propagation — no change.
  7. Removed/re-added the App Attest provider registration in Firebase Console (got "App Registration Successful") — no change.
  8. Fully uninstalled and clean-reinstalled the app to rule out a stale/cached App Attest key from early failed attempts — no change.
  9. Upgraded firebase_app_check 0.3.2+10→0.4.5 with firebase_core/firebase_database/cloud_functions bumped in lockstep — no change. (Only break from the upgrade: 0.4.x replaced the androidProvider/appleProvider enum-style API with provider classes and renamed activate() params to providerAndroid/providerApple — unrelated to this bug, just noting for anyone else upgrading.)
  10. Google Cloud Billing account was on Free Trial status; activated to a full paid account — no change.
  11. Swapped to an entirely different attestation provider (DeviceCheck) — identical failure.

Related context

A separate-but-possibly-connected issue in the same Firebase project on Android: firebase_app_check's Play Integrity provider throws an internal NullPointerException (obfuscated field reference, Attempt to read from field 'z1.p i2.e.j' on a null object reference) specifically on sideloaded (non-Play-installed) builds, matching #11117 and firebase/firebase-android-sdk#7110. Both platforms' App Check integrations are failing in this same project, via different mechanisms.

Ask

Every locally/Console-verifiable configuration point is confirmed correct, and the failure is isolated to the token-minting step specifically, uniformly across all three attestation methods, while challenge generation always succeeds. Is there a project-level or App-Check-backend-side state that wouldn't be visible from the client or Firebase Console that could cause this?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions