Skip to content

App Check and purchase verification release gate

The production client uses Play Integrity on Android and App Attest with DeviceCheck fallback on Apple platforms. Debug providers are selected only in non-release builds. Release and TestFlight builds cannot consume a debug token, even if one is supplied as a Dart define. App Check tokens use the Firebase default TTL; reassess TTL only after production latency and failure metrics are available.

Apple targets declare the App Attest capability with the production environment because Firebase does not accept App Attest sandbox attestations. The fallback preserves support for Apple versions/devices where App Attest is unavailable; confirm DeviceCheck remains registered before enforcing services.

record_purchase_call requires Authentication, enforced one-time App Check tokens, and store verification. It stores only verified transaction metadata; raw receipts and purchase tokens are never retained or logged.

Stable App Check token for local iOS debugging

iOS simulators cannot use App Attest or DeviceCheck. By default, Firebase generates a debug token inside each simulator app installation. That token can change when the app is uninstalled, simulator content is erased, or the simulator is reset. Registering generated tokens individually is therefore fragile.

Use one private, stable debug token for local iPhone and iPad simulator sessions:

  1. Open Firebase Console and select the production project.
  2. Go to App Check > Apps.
  3. Find the production iOS app. Open its overflow menu and select Manage debug tokens.
  4. Create a token with a descriptive name such as Michelle local iOS development.
  5. Copy the production local template:

shell cp config/app_check.prod.local.example.json config/app_check.prod.local.json

  1. Open config/app_check.prod.local.json and replace the example value with the newly created token:

json { "APP_CHECK_DEBUG_TOKEN": "the-private-token-from-firebase" }

  1. In VS Code, select iPhone Prod (Stable App Check) and start a new debug session. Fully stop and relaunch an existing session; hot reload and hot restart do not reactivate the App Check provider.
  2. Exercise a protected callable function and confirm its request appears as verified in Firebase App Check metrics.

config/app_check.prod.local.json is intentionally ignored by Git. Never force-add it, paste its value into .vscode/launch.json, include it in screenshots, or send it in logs. The tracked example contains no usable credential.

The token is registered to the production iOS Firebase app, not to a particular simulator. The same local token can therefore be used for iPhone and iPad simulators running that Firebase app. A macOS Firebase app, a different Firebase project, and CI should each use their own separately registered token.

To rotate a local token:

  1. Create and register its replacement in Firebase Console.
  2. Replace the value in config/app_check.prod.local.json.
  3. Fully stop and relaunch the app, then verify a protected request.
  4. Return to Manage debug tokens and revoke the previous token.

Revoke a token immediately if it is committed, displayed publicly, or shared with anyone who should not have development access.

Before the public build:

  • Register every shipped Firebase app in App Check. The current Firebase configuration ships iOS and macOS; do not ship another platform until its production provider is registered.
  • Deploy the client with token sending enabled while Firebase product enforcement remains in monitoring mode.
  • Confirm valid request metrics for production and TestFlight builds and investigate all unverified traffic.
  • Confirm the existing APPSTORE_SHARED_SECRET Secret Manager entry has an enabled version. APPLE_BUNDLE_ID and GOOGLE_PACKAGE_NAME are public deployment parameters and default to com.seachellemz.myrecipes; override them only if the shipped identifiers change. Grant the Functions service account Play Developer API access before shipping Android purchases.
  • Deploy Functions from this repository and verify the runtime is Node 22, region is us-east1, memory is 256 MiB, timeout is 30 seconds, and maximum instances is 10.
  • Run sandbox purchase, duplicate restoration, invalid receipt, and cross-user replay checks. Confirm rejected validations are visible in Cloud Logging.
  • Enable App Check enforcement for callable Functions first, then Firestore, Storage, and Authentication after their valid-token metrics are healthy.
  • Keep raw receipt retention disabled. Transaction metadata in purchase_transactions follows the account-retention policy and is removed through the account deletion workflow.