Adventure Labs Logo
Scout Docs

Client Abilities Token Authorization

Short-lived JWTs for UI permission gating per herd

Client Abilities Tokens

Short-lived JWTs carry per-herd ability keys. Abilities keys can be used to gate specific actions. For example, before allowing "user x" to upload a photo, you can first check if "user x" has the corresponding upload photo ability.

Claims

ClaimRole
subUser UUID
platform_superadminWhen true, UI may allow all abilities
herds[{ herd_id, slug, abilities: string[] }, …] per active membership
audscout-client
iat / expIssued / expiry (CLIENT_ABILITIES_TOKEN_TTL_SEC; edge default 900s if unset, production often 3600)

Verifiers use public JWKs by kid. Edge secrets are: CLIENT_ABILITIES_JWT_PRIVATE_JWK and optional CLIENT_ABILITIES_TOKEN_TTL_SEC (within range of 60–86400 seconds).

Flow

  1. Client calls mint-client-abilities-token.
  2. Edge runs get_client_abilities_token_claims() as the caller and signs herds / platform_superadmin.
  3. Client gates actions, visuals, and realtime channel joins based on abilities.
  4. All supabase requests still enforce permissions via RLS (including realtime.messages for private channels). The abilities JWT cannot replace Realtime RLS — it uses a different signing key and audience than the Supabase session JWT.

Who Gets What Claims

CallerClaimsMint
Platform superadminplatform_superadmin: true, herds: []Yes
User with active herd role(s)One herd entry per membership, abilities from role matrixYes
User, no active herds—No (null → 403)
Device API key / anon—No
Unauthenticated—No

Database

ObjectRole
client_abilities_jwt_public_keysActive public JWKs by kid
get_client_abilities_jwt_public_keys()Keys for verifiers
upsert_client_abilities_jwt_public_keyRegister / rotate (service role or superadmin)
revoke_client_abilities_jwt_public_keySoft-revoke
get_client_abilities_token_claims()Mint only — not for clients

Rotation: upsert public key → update edge private JWK → wait TTL → revoke old kid. Refresh tokens when membership or role matrices change.

Generate a key pair

deno eval "
import { generateKeyPair, exportJWK } from 'npm:jose@5';

const kid = 'client-abilities-' + crypto.randomUUID().slice(0, 8);
const { publicKey, privateKey } = await generateKeyPair('ES256', { extractable: true });
const pub = await exportJWK(publicKey);
const priv = await exportJWK(privateKey);
pub.kid = kid;
priv.kid = kid;

console.log('# Private (EDGE ONLY):\n');
console.log(JSON.stringify(priv));
console.log('\n# Public:\n');
console.log(JSON.stringify(pub));
"

On this page