Authentication

Authentication answers “who is making this request, and what may they do?” There are two separate relationships: Alice signs in to your app; your backend authenticates itself to the commerce provider.

Alice → your backend

Your existing login identifies Alice. Your backend selects her user ID and checks whether she may claim this purchase.

Your backend → provider

A server credential allows account reads and changes. Keep it on your backend; Alice’s app must never receive it.

A receipt proves neither relationship. Bob holding Alice’s receipt must not be enough to move the purchase to Bob.

Two credentials, with the same boundary

Run the flow locally

openiap-commerce-protocol-example

Two fixed demo credentials separate verification from account operations. The request handler checks the role before parsing input. The dashboard preselects Alice; it is not an app login implementation.

Read code: fetch: authorization before input
See the service implementation

IAPKit

Publishable and secret keys identify the calling project. Convex checks the stored key’s permissions before server operations. Your own backend still authenticates Alice and chooses her user ID.

Read code: commerceAuth / authoritativeServerAuth
How to check this behavior

Example. The request checks reject missing credentials and the verification credential on account operations. Run npm test. Inspect reference

IAPKit. Tests exercise missing, invalid, and under-scoped keys before input parsing on both bindings. Inspect reference

Choose the credential for the job#

A verification credential can check purchase evidence. A server credential can also read access, bind purchases, and request erasure. These must be different credentials.

Credential roles and allowed operations
RoleHolderMay call
verificationMay ship inside an applicationproviderCapabilities, verifyPurchase
serverThe caller's authenticated backendproviderCapabilities, subscriptionStatus, entitlements, verifyPurchase, bindPurchase, eraseUser

One operation needs no credential at all: providerCapabilities is a public read with no customer purchase data (auth role none). Every other operation requires one of the two roles above.

Providers issue their own credentials; the protocol does not impose a key format. Credentials travel in the Authorization header and never in a URL. A protected request without a credential returns UNAUTHORIZED; a credential with the wrong role returns FORBIDDEN. Separate credentials keep a shipped app from looking up or changing other users’ accounts. Full rules: SPEC.md §5.

Authenticate server-role operations before validating their input. In GraphQL this includes authorization before variable coercion, not only inside a resolver. The app backend selects the user from its session and ownership policy; neither a client-supplied user ID nor possession of a receipt authorizes binding by itself.