Subscription check
Require that a signed-in user has paid before they can call AI providers through the app.
Subscription check is the third level of the Auth policy page. It requires the user's sign-in token to carry a claim that says they have paid. It is available only with Signed-in users only, because it needs a token to inspect. The state line says Paid users only, Any signed-in user, Paid check not finished, or Needs signed-in users.
How it works
The gateway never talks to the App Store. It checks a claim inside the verified ID token, and something else has to put that claim there after the purchase:
- RevenueCat with its Firebase extension writes the user's active
entitlements into their Firebase token as
revenueCatEntitlements. - Your own backend can set any custom claim on your identity provider after it confirms a purchase.
On every token exchange the gateway verifies the token as usual and then
checks the required claims. A token without them is refused with
403 issuer_claims_missing.
Choices
- Any signed-in user: signing in is enough. Nothing about payment is checked.
- Paid users only: the sign-in token must carry a claim that says the
user has paid. Then choose which claim:
- RevenueCat entitlement: enter the Entitlement identifier from RevenueCat's Product catalog, the identifier rather than the display name. Several, comma separated, admit a user carrying any one of them.
- Custom claim: one or more rows of Path, Match and Value. Paths are dot paths into the token. contains matches arrays and space-delimited scopes; equals compares exactly.
The propagation gap
The claim is written after the purchase, by a webhook or a backend job, and the app may refresh its token before that has happened. During that window a paying user holds a perfectly valid token that lacks the claim.
This is why the refusal has its own code. issuer_claims_missing means "the
user is real, the entitlement has not arrived yet, wait and try again". Treating
it as a sign-in failure would send the user round a loop they cannot escape.
The Swift package exposes a hook that runs only on this code, so you can
trigger a purchase sync there. See iOS with the Swift package.
The gateway measures the gap. The app's Auth & Errors page shows how long activation usually takes and how many users are waiting on a claim right now.
In the configuration
The check is the required_claims list on the issuer block. A RevenueCat
entitlement named pro:
"required_claims": [
{ "path": "revenueCatEntitlements", "contains": "pro" }
],
"entitlement": "revenuecat"A custom claim requiring a scope:
"required_claims": [
{ "path": "scope", "contains": "ai.invoke" }
]Each requirement has a path and either contains (a string or a list of
alternatives) or equals (a string, number or boolean). All requirements
must pass. entitlement is bookkeeping for the console and may be omitted.