Documentation/Developers
Back
  • Getting started
    • Frontends and app types
    • Environments and endpoints
  • OAuth clients
    • Client ID and secret
    • Redirect URIs and start URL
    • Secret rotation
  • Login with appsolut
    • Authorization code flow
    • Tokens and claims
    • Frontend role
    • Sign-out
    • Revocation and issued tokens
    • Token endpoint errors
  • Frontend keys
    • Issue and store a key
    • Send a key
    • Rotate and revoke
  • Members API
    • Eligibility from a backend
    • The signed-in member
    • Results, rate limits and errors
    • Is an applicant an eligible member?
    • The signed-in frontend user's membership
  • appsolut register API
    • Implement the API
    • Connect and test
    • Verify a member with their challenge code
    • List every member
    • The status of several members
    • The status of one member
    • The person data of several members
    • The person data of one member
    • The claims of several members
    • The claims of one member
    • Health check

Tokens and claims

What the access token carries, how to check it, and what it is not for.

The access token

A JWT for your backend. A decoded example, with made-up values:

{
  "iss": "https://example-project.supabase.co/auth/v1",
  "sub": "3f0c9a52-7d1e-4b8a-9c6f-2e5d8b1a4c70",
  "aud": "authenticated",
  "iat": 1792682619,
  "exp": 1792686219,
  "client_id": "9d4b7c1e-3a2f-4e5d-8b6a-7c0f1e2d3a4b",
  "scope": "openid",
  "tenant_id": "c2a8e6f4-1b3d-4f5a-9e7c-0d2b4f6a8c1e",
  "frontend_role": "member",
  "email": "anna.berger@pannoniqa.example",
  "given_name": "Anna",
  "family_name": "Berger",
  "role": "frontend_user",
  "user_metadata": {},
  "phone": ""
}

Read these claims:

ClaimMeaning
subThe frontend user, stable for the life of the account. Key your users by it. The same person at two organisations has two unrelated subs.
tenant_idThe organisation the user belongs to.
client_idThe frontend the token was issued to.
scopeAlways openid.
frontend_roleauthenticated or member (see Frontend role). Only on these OAuth tokens.
emailThe user's real, verified address, lower-cased. It can change; never key a user by it.
given_name, family_nameThe names the user gave at sign-up.
iss, aud, exp, iatStandard JWT claims. aud is authenticated for every frontend's token.

Never read the others:

  • role is the database role (frontend_user), not the frontend role.
  • user_metadata is always {} and phone always "".
  • app_metadata, session_id, aal, amr and is_anonymous are the Auth server's own. Take the organisation from the top-level tenant_id.

Check every access token before you trust it

  1. Verify the signature against the keys of <auth>/.well-known/jwks.json. Cache them, and fetch again for an unknown kid. Accept only the algorithm of the key in JWKS; never HS256 or none.
  2. Check iss against the issuer in discovery, exp, and aud authenticated.
  3. Check that client_id is your own client ID. aud is the same for every frontend, so only client_id binds a token, and its frontend_role, to your frontend. Skip this and your backend accepts a token another frontend of the organisation obtained, with that frontend's member, which may mean another community.
  4. Check that tenant_id is your organisation.
  5. Only then read frontend_role, sub, email and the names.

What the access token is not for

  • Never send it to the Studio as a bearer token. The Studio refuses any Authorization: Bearer with an access token, and the Members API authenticates your backend by its frontend key. The one exception is GET /api/v1/members/me, which takes the token beside the key, in its own header (see The signed-in member).
  • Never send it to the project's database, storage or GraphQL APIs. It carries the database role frontend_user, which has no access to anything there.
  • Never call GET <auth>/user (or any other <auth>/user endpoint) with it: it answers with the account's internal technical address, not the real email. Apart from /oauth/userinfo, never send it to <auth> at all.
  • Keep it on your server. Never hand the access or refresh token to the browser.

ID token and UserInfo

Both carry only sub about the user, because the scope is openid alone. The ID token also carries the standard iss, aud, exp and iat, and your nonce if you sent one. Everything else is in the access token.