Firebase Ships Replay Protection, iOS Apps Can't Use It Yet
Firebase's Admin SDKs finished shipping App Check replay protection, but a FlutterFire bug stops iOS and macOS from getting the short-lived tokens it needs.

Firebase finished rolling App Check’s replay protection out across its Admin SDKs this month, giving backends a way to reject a stolen or reused security token outright. But a bug reported Sept. 24, 2026 means iOS and macOS apps built with FlutterFire can’t yet issue the short-lived tokens that protection depends on, so turning it on can break their own legitimate requests (firebase/flutterfire issue #18718, Sept. 24, 2026).
What shipped
Replay protection works by pairing a client call with a server check. On the client, an app requests a token via getLimitedUseToken() instead of the usual getToken(); that token is meant to live for 300 seconds and be used once. On the backend, the Admin SDK’s verifyToken() takes a consume: true option, which marks the token spent after the first successful check and rejects any second attempt to use it. Firebase’s Admin Python SDK added that consume parameter Sept. 16, 2026, merging support for the one-time-token flow into app_check.verify_token(), per pull request #976 on the firebase-admin-python repo; Firebase’s release notes list it shipping in Python SDK v7.6.0 on Sept. 17, with a further fix rolled into v7.7.0, alongside the Go and Node.js Admin SDKs, on Sept. 23.
The feature is aimed squarely at endpoints developers can’t otherwise rate-limit by identity, and Firebase’s own docs call out Firebase AI Logic (the Gemini proxy) as a primary use case: without replay protection, a captured App Check token could be replayed against a Gemini endpoint indefinitely within its normal one-hour lifetime.
Where it breaks
That one-hour lifetime is exactly the problem on Apple platforms. The FlutterFire issue traces the bug to AppCheckProviderWrapper, which implements the required getToken() method but not the optional getLimitedUseToken() one. iOS silently falls back to the standard call, so getLimitedUseToken() returns a normal hour-long token instead of a 300-second single-use one. That’s verifiable by decoding the returned JWT and checking exp - iat: the reporter found it came back as 3,600 seconds on iOS and macOS, versus a correct 300 on Android. Any backend enforcing consume: true for an AI Logic call sees the same cached token show up on a second legitimate request and rejects it with “Unverified: Reused token.”
A fix is written and open as pull request #18719, forwarding getLimitedUseToken(completion:) through the wrapper; its author says testing on a physical iOS device confirmed the token TTL drops to the expected 300 seconds. As of this writing the PR hasn’t merged, so the gap is still live in the current FlutterFire release.
Key Takeaways
- Firebase’s Admin Python, Go and Node.js SDKs finished shipping App Check’s
consume: truereplay protection Sept. 16-23, 2026, aimed at endpoints like Firebase AI Logic. - Replay protection depends on clients calling
getLimitedUseToken()for a 300-second single-use token instead of the standard hour-long one. - On iOS and macOS, FlutterFire’s
AppCheckProviderWrapperdoesn’t implementgetLimitedUseToken(), so it silently returns the standard token instead, confirmed by a Sept. 24, 2026 GitHub issue. Android is unaffected. - A fix (PR #18719) is open but hasn’t merged yet.
What to do
Don’t flip consume: true on for a Flutter iOS or macOS client hitting Firebase AI Logic or any other replay-protected endpoint until #18719 merges and ships. The mismatch will reject repeat calls from real users, not just replay attempts. Track the PR, and verify the fix on a physical device rather than the simulator once it lands, since App Check attestation behaves differently in each.


