The short answer
- App Attest is Apple’s check; App Check is Firebase’s service around it. With App Check, Firebase checks Apple’s proof and gives your app a Firebase token. Without it, your own server checks the proof.
- The main difference is what reaches your server. App Attest can sign every request. A standard App Check token works for an hour by default, so a copied one keeps working until it expires. Limited-use tokens work once, at the cost of a round trip to Firebase per request.
- Choose App Check if you already use Firebase, need Android or the web as well, or call only Gemini through Firebase AI Logic.
- Choose App Attest on your server if your app is iOS-only and every request costs money, or if you don’t want your backend to depend on Firebase.
- Either way, add limits. Neither one says who the user is or stops a genuine app from running up your bill.
How App Attest itself works, and every check your server must run, is covered in How to use App Attest to protect your AI backend.
App Check can run App Attest for you
App Attest is Apple’s service. Once per install, the app creates a key on the device and Apple certifies that it belongs to your unmodified app on a genuine device. After that, the app can sign any request with that key, and your server checks the signature.
Firebase App Check is Google’s service. On iPhone it gets its proof from App Attest or from DeviceCheck, Apple’s older service, which shows the device is a real Apple device but not that your app is unmodified. Android uses Play Integrity and the web uses reCAPTCHA. On every platform, Firebase checks the proof and returns the same kind of token: a signed App Check token that your app sends with its requests.
So on iPhone, the real choice is who checks Apple’s proof and what your server sees afterwards: an App Attest signature on each request, or a Firebase token.
App Attest and App Check side by side
| App Attest on your server | App Check with App Attest | |
|---|---|---|
| Who checks Apple’s proof | Your server | Firebase |
| What each AI request carries | A fresh signature over that request | A Firebase token, reused for an hour by default (30 minutes to 7 days) |
| A copied request | Refused: the counter was already used | Works until the token expires, unless you use limited-use tokens |
| Server code | About a dozen checks; open-source libraries exist | Check one signed token: one call in Firebase’s server SDK |
| Platforms | Apple only | iOS, Android and the web, with one token format |
| Devices without App Attest | Your own fallback | An error, unless you fall back to DeviceCheck yourself |
| Apple’s fraud metric | Available to your server | Not used |
| Price | Free | Free, within Apple’s and Firebase’s quotas |
| Your backend depends on | Apple, once per install | Apple and Firebase |
Performance of each approach
Both talk to Apple once per install, which often takes 4 to 8 seconds. After that, the cost of each AI request depends on the token:
| Approach | Work for each AI request |
|---|---|
| App Attest on your server | A signature on the phone, with no network, and a signature check plus a counter update on your server |
| App Check, standard token | None: the app sends the cached token, and the SDK renews it in the background at about half its lifetime |
| App Check, limited-use token | A round trip to Firebase for a fresh token before each request, and one more from your server if it marks the token as used |
Next to an AI call that takes seconds, none of these is large. The difference is what each one buys: only the signature and the limited-use token stop a copied request.
What a copied token can do
A standard App Check token is a bearer token: whoever holds it can use it. Firebase says so plainly: tokens “can be re-used until their TTL expires.” Anyone who copies one from your app’s traffic, for example on their own phone, can call your AI endpoint from a script until it expires: an hour by default, and up to 7 days if you raise it to save attestations.
Firebase offers two ways to narrow that window:
- A shorter lifetime, down to 30 minutes. Each renewal is another exchange with Firebase, which adds network calls and uses quota faster.
- Limited-use tokens. The app fetches a new token for each request, valid for 5 minutes. To make it single-use, your server must also mark it as used when it checks it. That step is in Firebase’s Node.js server SDK only, and still in beta.
An App Attest signature has neither problem. It covers the method, path and body of one request and carries a counter, so it can’t be sent twice or moved to a changed prompt. It’s made on the phone, with no extra round trip.
For a backend that serves cheap requests, an hour-long token is often fine. For an endpoint where one request can cost cents and a script can send thousands, per-request proofs are worth it.
App Check on your own server
App Check isn’t only for Firebase services. Your app can send the token to your own server in a header, and your server checks it:
// Partial example: error handling and retries are left out.
import FirebaseCore
import FirebaseAppCheck
import DeviceCheck
// App Check uses DeviceCheck unless you choose App Attest. This factory uses
// App Attest where the device supports it, and DeviceCheck where it doesn't.
final class AttestFactory: NSObject, AppCheckProviderFactory {
func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
if DCAppAttestService.shared.isSupported { return AppAttestProvider(app: app) }
return DeviceCheckProvider(app: app)
}
}
// At launch, before FirebaseApp.configure():
AppCheck.setAppCheckProviderFactory(AttestFactory())
FirebaseApp.configure()
// On each AI request to your own server:
let token = try await AppCheck.appCheck().limitedUseToken() // or token(forcingRefresh: false)
request.setValue(token.token, forHTTPHeaderField: "X-Firebase-AppCheck")On the server, Firebase’s Admin SDK checks the token in one call, in Node.js, Python and Go. In other languages, any JWT library works: fetch Firebase’s public keys, then check the signature, the issuer, your project as the audience, and the expiry time.
// Partial example for Node.js: limits, logging and the AI call are left out.
import { initializeApp } from "firebase-admin/app";
import { getAppCheck } from "firebase-admin/app-check";
initializeApp();
// app is an Express app.
app.post("/ai", async (req, res) => {
const token = req.header("X-Firebase-AppCheck");
if (!token) return res.status(401).end();
try {
// consume: true accepts each limited-use token once (beta, Node.js only).
const { alreadyConsumed } = await getAppCheck().verifyToken(token, { consume: true });
if (alreadyConsumed) return res.status(401).end();
} catch {
return res.status(401).end();
}
// Only now: check your limits and call the AI provider.
});The switch called enforcement in the Firebase console doesn’t protect this server. It covers Firebase’s own services and callable Cloud Functions only. One developer enforced App Check and still reached a plain HTTP function with curl, because only their code could check the token. The rule from the App Attest article holds: a proof the server doesn’t require stops nothing.
Without the Node.js SDK, you can still make limited-use tokens single-use: store each token you accept until it expires, and refuse it the second time.
Firebase AI Logic for Gemini only
If your app calls only Gemini, Firebase AI Logic lets it do so with no server of your own. Its proxy checks App Check before forwarding each request to Google’s Gemini API. It doesn’t reach OpenAI, Anthropic or any other provider.
- App Check is becoming mandatory. From 2 November 2026, Firebase enforces App Check for AI Logic and it can’t be turned off. Users on app versions without App Check will be blocked.
- Limited-use tokens are recommended, and AI Logic is the one Firebase service that checks them as single-use for you.
- Its limit per user is the same for everyone: 100 requests a minute by default, with no way to set it for one user or a group. There’s no daily or spending limit per user.
That last point matters more than the proof. In April 2026, a developer reported a €54,000 Gemini bill in 13 hours after an unrestricted Firebase key was used for Gemini requests, with budget alerts arriving hours late. App Check makes scripted abuse harder; only limits and spending caps bound the cost.
Five App Check setup traps
- App Attest isn’t the default. With no provider chosen, App Check uses DeviceCheck on devices and the debug provider in the Simulator. Choose App Attest explicitly, as in the example above.
- The entitlement must say production. App Check rejects tokens from App Attest’s development environment, so set the App Attest environment to
production, even for builds you run from Xcode. - There’s no automatic fallback. On a device where App Attest isn’t supported, the App Attest provider returns an error rather than switching to DeviceCheck. Check
isSupportedin your own factory, as in the example. - Some real users fail. In 2024, one app reported about 10% of its iOS users never getting a token. The cause was a key left over from an earlier install, and a later SDK release resets it. Watch App Check’s metrics in monitoring mode before you enforce.
- Enforcing blocks old app versions. Versions released without the App Check SDK fail once you enforce, and enforcement takes up to 15 minutes to apply. Turn it on before launch if you can. Never ship a debug token: it works from any device.
Which one to use
| Your situation | A good fit |
|---|---|
| You call only Gemini and want no server of your own | Firebase AI Logic with App Check and limited-use tokens |
| You have your own server and also ship Android or a web app | App Check, with limited-use tokens on the expensive endpoints |
| You already use Firebase and requests are cheap | App Check with standard tokens |
| Your app is iOS-only and every request costs money | App Attest checked on your server, with a signature on every request |
| You don’t want your backend to depend on Google | App Attest checked on your server |
Whichever you pick, the server decides. It refuses any request without a valid proof before it calls the AI provider.
What neither one stops
App Check’s guarantee is the guarantee of the proof underneath it, so both leave the same gaps. Firebase itself says App Check prevents “some, but not all, abuse vectors”:
- A jailbroken device. Someone can hook your genuine app and make it produce valid proofs for their own requests.
- Who the user is. Both prove the app, not the person. Firebase calls App Check and sign-in complementary: one protects you, the other your users.
- Heavy use. A real person in your real app can still send expensive requests all day.
- Who has paid. Your paywall lives in the app; only a server-side check decides who gets the larger allowance.
How to add limits, sign-in and a payment check is covered in Check 2: Is this request within limits? and the sections after it.
App AI Gateway checks App Attest itself
App AI Gateway, the product we build, sits between your iOS app and the AI provider and takes the App Attest side of this comparison:
- It checks App Attest on its own server, with a signature on every request by default, so a copied request is refused.
- It holds your provider keys and works with OpenAI, Gemini, Anthropic and other providers, not only Gemini.
- It limits each install and each user by requests and by spending. If your app uses Firebase Authentication, it accepts Firebase sign-in tokens to tie those limits to people.
The hosted service has a free plan with 1,000 requests a month, or you can self-host it. Before choosing it, know its limits:
- It doesn’t accept App Check tokens. On iOS it replaces App Check rather than working with it.
- It supports Apple apps only. If you need Android or the web too, App Check covers them and the gateway doesn’t yet.
- There’s no fallback for devices that can’t use App Attest, and its Swift package needs iOS 16 or later.
The comparison of AI gateways for mobile apps shows how other services check requests, and the Firebase App Check entry in the glossary sums up what it stops and what it leaves open.
References
- Firebase App Check — Firebase docs
- Get started using App Check with App Attest on Apple platforms — Firebase docs
- Protect custom backend resources with App Check on Apple platforms — Firebase docs
- Verify App Check tokens from a custom backend — Firebase docs
- Enable App Check enforcement — Firebase docs
- Monitor App Check request metrics — Firebase docs
- Use App Check with the debug provider on Apple platforms — Firebase docs
- Prevent Gemini API abuse with Firebase App Check — Firebase AI Logic docs
- Rate limits and quotas — Firebase AI Logic docs
- Preparing to use the App Attest service — Apple Developer
- AppCheck + AppAttest getAppCheckToken failing for 10% of users in production — firebase-ios-sdk on GitHub
- Enforced App Check on my app and on my cloud functions does not prevent calls from outside — Stack Overflow
- Ensuring Secure Backend Access for Mobile App Using Firebase App Check — Stack Overflow
- €54k spike in 13h from unrestricted Firebase browser key accessing Gemini APIs — Hacker News
