Every client needs two things: your project’s API address and an API key. This page explains what each key can do, how scopes narrow it, how requests are authenticated, and what to check before you go live. To create and manage keys in Studio, see API keys.

The two kinds of key

How a request is authenticated

Every call carries a key in the apikey header. Calls made on behalf of a signed-in person also carry their access token:
  1. The gateway reads the key. A missing key is missing_api_key and a bad one invalid_api_key (both 401).
  2. It checks the key’s limits: expiry, allowed browser origins, allowed addresses, allowed routes, rate limit, and your plan’s quotas.
  3. It checks the key’s scopes (below).
  4. If there is a bearer token, it identifies the person: their id, roles, organization and assurance level.
  5. The access rule for what’s being asked is evaluated with all of that.
The SDKs do all of this for you: give them the key and they add the headers, refresh tokens and retry politely.

Scopes

A scope names something a key may do. A scope has the form family:read, family:write or family:*:
  • read allows looking: GET, HEAD and OPTIONS requests.
  • write allows changing: every other method.
  • * allows both.
  • A lone * is everything.
A key with no scopes may do anything its role allows. A key with scopes may make only the requests its scopes name, whichever route they reach. The check happens at the edge for every request, so no route can forget it.

The scope families

A publishable key can only hold the application families (data, storage, auth, flows, ai, realtime). Management scopes need a secret key because the management API is out of a browser’s reach.

Presets

When you create a key, Start from a preset and adjust: The two AI presets are what AI tools use.

Other limits on a key

Besides scopes: an expiry, allowed IP ranges and allowed routes (GET /rest/v1/*). The environment also has a list of websites allowed to use publishable keys. All refuse the call at the gateway. See API keys.

Rules of thumb

  1. Put the publishable key in client code. It is meant to be seen.
  2. Keep the secret key in an environment variable on a server. The browser build of the client refuses to start with one.
  3. Never trust the browser for permissions. Your access rules run on the server for every request, whatever the client sends.
  4. Do not store anything sensitive in user_metadata, since the user can edit it. Store permissions in roles or app_metadata, set from a server.
  5. Give each app and job its own key with the fewest scopes it needs.

Choosing a key on a server

See Node.js for both patterns.

Rotating and revoking

If a secret key may have leaked, rotate it: create the replacement, deploy it, and let the old one expire after a grace period. If you are sure it leaked, revoke it now. See API keys.

Redirect addresses

Links in emails (confirmation, reset, invite) and social sign-in can only return to addresses you have listed under Users & auth → Domains. List exactly your app’s addresses, including http://localhost:… for development, and no wildcards you do not need. See Redirect URLs.

Go-live security checklist

  • Secret keys only on servers, in your host’s secret store, never in a repository or a mobile app.
  • A different key per environment, and per app or job, each scoped.
  • Websites allowed to call it lists only your real sites (Environment settings).
  • Servers allowed to use secret keys is set if your servers have fixed addresses.
  • Every table has an access rule. No table is left open by accident. Test each rule as a signed-in person, as a different person, and as nobody.
  • Password policy, two-step verification and attack protection are set the way you want.
  • Models are Servers only unless a browser must call them, and agents have a cost limit (Approvals and limits).
  • Webhook receivers verify signatures (Verify signatures), and inbound hooks aren’t set to None.
  • Alarms and a backup schedule are on.
  • You know where the audit log is.

Common mistakes