6.7 C
Canberra
Saturday, April 11, 2026

Firebase App Verify debug token returns 403 “App attestation failed” on iOS Flutter app — deceptive error hides API key restriction


Drawback

After enabling Firebase App Verify enforcement on Firestore, Storage, and RTDB, my Flutter iOS debug construct fails to acquire an App Verify token. All Firestore listeners fail with “Lacking or inadequate permissions.” The Xcode console reveals:

AppCheck failed: 'The operation could not be accomplished. The server responded with an error:
 - URL: https://firebaseappcheck.googleapis.com/v1/tasks/YOUR_PROJECT/apps/YOUR_APP_ID:exchangeDebugToken
 - HTTP standing code: 403
 - Response physique: {
    "error": {
      "code": 403,
      "message": "App attestation failed.",
      "standing": "PERMISSION_DENIED"
    }
  }

Setup

  • Flutter app utilizing firebase_app_check bundle
  • iOS bodily machine, debug mode by way of Xcode
  • AppleDebugProvider() configured in Dart:
await FirebaseAppCheck.occasion.activate(
  providerApple: kDebugMode
      ? const AppleDebugProvider()
      : const AppleAppAttestWithDeviceCheckFallbackProvider(),
);
  • Firebase initialized programmatically by way of firebase_options.dart (not utilizing GoogleService-Information.plist for initialization)
  • Debug token accurately registered in Firebase console beneath the right iOS app
  • Firebase App Verify API enabled in Google Cloud Console
  • App Attest registered as attestation supplier in Firebase console
  • Token propagation waited 30+ minutes
  • Android emulator works nice with its personal debug token

What I attempted (none of those mounted it)

  1. Verified the debug token UUID matched precisely between Xcode logs and Firebase console
  2. Confirmed the Firebase App Verify API was enabled in GCP
  3. Waited over an hour for token propagation
  4. Added the App Attest entitlement to the Xcode challenge
  5. Configured DeviceCheck as a further supplier in Firebase console
  6. Set AppCheckDebugProviderFactory in native AppDelegate.swift

Root trigger

The iOS API key (present in GoogleService-Information.plist beneath the API_KEY subject, or in firebase_options.dart) has an iOS utility restriction that solely permits requests from a particular bundle ID. Each App Verify token change request should embody an X-Ios-Bundle-Identifier header.

The native Firebase iOS SDK reads the bundle ID from GoogleService-Information.plist within the app bundle. As a result of I used programmatic initialization by way of firebase_options.dart, the plist was by no means added to the Xcode construct goal. It existed on disk at ios/Runner/GoogleService-Information.plist however wasn’t referenced in challenge.pbxproj, so it was by no means copied into the app bundle.

With out the plist within the bundle, the SDK despatched requests with no bundle ID. Firebase blocked them however returned the deceptive “App attestation failed” error as an alternative of the actual purpose.

How I confirmed this

I known as the exchangeDebugToken endpoint straight with curl:

# With out bundle ID — reveals the REAL error
curl -s -X POST 
  "https://firebaseappcheck.googleapis.com/v1/tasks/YOUR_PROJECT/apps/YOUR_APP_ID:exchangeDebugToken?key=YOUR_API_KEY" 
  -H "Content material-Sort: utility/json" 
  -d '{"debugToken": "YOUR_DEBUG_TOKEN"}'

# Response:
# "Requests from this iOS shopper utility  are blocked."
# purpose: API_KEY_IOS_APP_BLOCKED
# WITH bundle ID — succeeds
curl -s -X POST 
  "https://firebaseappcheck.googleapis.com/v1/tasks/YOUR_PROJECT/apps/YOUR_APP_ID:exchangeDebugToken?key=YOUR_API_KEY" 
  -H "Content material-Sort: utility/json" 
  -H "X-Ios-Bundle-Identifier: com.instance.yourapp" 
  -d '{"debugToken": "YOUR_DEBUG_TOKEN"}'

# Response: legitimate App Verify token returned

Substitute YOUR_PROJECT, YOUR_APP_ID, YOUR_API_KEY, and YOUR_DEBUG_TOKEN with values out of your Firebase console and Xcode logs. YOUR_APP_ID is the total app ID (e.g., 1:123456789:ios:abcdef1234567890).

Repair

Two adjustments are wanted:

1. Add GoogleService-Information.plist to the Xcode construct goal

The file probably already exists at ios/Runner/GoogleService-Information.plist — it simply is not within the Xcode challenge. In Xcode:

  1. Drag GoogleService-Information.plist into the Runner group within the challenge navigator
  2. Uncheck “Copy gadgets if wanted” (it is already there)
  3. Verify the Runner goal

You possibly can confirm it is lacking by trying to find it in challenge.pbxproj:

grep -c "GoogleService-Information.plist" ios/Runner.xcodeproj/challenge.pbxproj
# If result's 0, it is not within the construct

2. Set AppCheckDebugProviderFactory in AppDelegate.swift

With the plist now within the bundle, the native Firebase SDK will auto-configure and default to DeviceCheck (or App Attest) as an alternative of the debug supplier. You need to set the debug supplier manufacturing facility earlier than Firebase configures:

import FirebaseCore
import FirebaseAppCheck

@most important
@objc class AppDelegate: FlutterAppDelegate {
  override func utility(
    _ utility: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    let providerFactory = AppCheckDebugProviderFactory()
    AppCheck.setAppCheckProviderFactory(providerFactory)

    // ... remainder of your setup
    GeneratedPluginRegistrant.register(with: self)
    return tremendous.utility(utility, didFinishLaunchingWithOptions: launchOptions)
  }
}

Observe: You would possibly see examples utilizing #if DEBUG across the manufacturing facility setup. Bear in mind that the Runner goal in Flutter tasks could not have DEBUG in its SWIFT_ACTIVE_COMPILATION_CONDITIONS construct setting (solely RunnerTests does). Verify your construct settings earlier than counting on #if DEBUG, or omit the guard — the Dart-side activate() overrides the supplier for launch builds anyway.

After each adjustments, do a clear construct (flutter clear then flutter pub get then cd ios && pod set up) and run from Xcode.

TL;DR

When you use programmatic Firebase init in Flutter (firebase_options.dart) and your iOS API key has utility restrictions, App Verify debug token change silently fails with a deceptive “App attestation failed” error. The repair: add GoogleService-Information.plist to your Xcode construct goal so the native SDK can ship the bundle ID with requests, and set AppCheckDebugProviderFactory in AppDelegate.swift earlier than plugin registration.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

[td_block_social_counter facebook="tagdiv" twitter="tagdivofficial" youtube="tagdiv" style="style8 td-social-boxed td-social-font-icons" tdc_css="eyJhbGwiOnsibWFyZ2luLWJvdHRvbSI6IjM4IiwiZGlzcGxheSI6IiJ9LCJwb3J0cmFpdCI6eyJtYXJnaW4tYm90dG9tIjoiMzAiLCJkaXNwbGF5IjoiIn0sInBvcnRyYWl0X21heF93aWR0aCI6MTAxOCwicG9ydHJhaXRfbWluX3dpZHRoIjo3Njh9" custom_title="Stay Connected" block_template_id="td_block_template_8" f_header_font_family="712" f_header_font_transform="uppercase" f_header_font_weight="500" f_header_font_size="17" border_color="#dd3333"]
- Advertisement -spot_img

Latest Articles