Role & Access Check API
ButtrBase exposes three endpoints that your app's frontend and backend can call to validate who a user is, what they're allowed to do, and whether they hold an admin role within a specific app context.
Token Introspection — GET /api/auth/me
Returns the full decoded payload of the caller's access token. Use this in your frontend to drive permission-aware UI without parsing JWTs yourself.
~~~http
GET /api/auth/me
Authorization: Bearer
~~~jsonc // 200 OK { "user_uuid": "usr_01abc...", "email": "alice@acme.com", "org_uuid": "org_01def...", "org_name": "Acme Corp", "roles": ["member", "admin"], "entitlements": ["advanced_analytics", "sso"], "app_admin": ["app_01ghi..."], // apps this user can admin "platform_admin": false, "sandbox": false } ~~~
app_admin is an array so one user can admin multiple apps. If the user is
the org owner they implicitly have app admin rights for every app the org
publishes — this is reflected in the response without an explicit grant row.
---
Feature & Role Check — POST /api/entitlements/check
Checks whether the caller has a specific entitlement or role. Designed for app backends to use on the hot path — the check runs against the already-decoded token and does not re-verify the full JWT chain.
~~~http
POST /api/entitlements/check
Authorization: Bearer
{ "feature": "admin_panel", "org_uuid": "org_01def..." } ~~~
~~~jsonc // 200 OK { "granted": true, "reason": "role:app_admin" // or "entitlement:admin_panel" or "denied" } ~~~
reason values
| Value | Meaning |
|-------|---------|
| role:app_admin | User has an app_admin grant for this app |
| role:platform_admin | User holds a platform_admin credential |
| entitlement: | Feature entitlement is active for the org |
| denied | Neither role nor entitlement matched |
Use this in Axum/Express/Django middleware to gate routes without adding a database roundtrip per request.
---
App Access Check — GET /api/marketplace/apps/:app_id/access
Returns the caller's relationship to a specific marketplace app. Call this from your app's frontend to decide which UI to render, or from your backend to enforce admin-only routes.
~~~http
GET /api/marketplace/apps/app_01ghi.../access
Authorization: Bearer
~~~jsonc // 200 OK { "is_app_admin": true, "is_org_owner": false, "install_status": "active", // or "suspended" | "deprovisioned" | null "install_id": "inst_01jkl..." } ~~~
install_status is null if the caller's org has never installed this app.
---
JWT Claim Structure
All three endpoints derive their response from claims already embedded in the
access token. You can inspect these locally using the SDK's verify_token method
without making any API call:
~~~jsonc // Decoded JWT payload { "sub": "usr_01abc...", "org": "org_01def...", "roles": ["admin"], "entitlements": ["sso"], "app_admin": ["app_01ghi..."], "platform_admin": false, "sandbox": false, "exp": 1748000000, "iat": 1747999100 } ~~~
platform_admin and app_admin are populated at token issuance and remain
valid until the token expires. If you grant or revoke app admin access you should
instruct the affected user to refresh their token to pick up the change.
---
SDK Methods
Rust
~~~rust use buttrbase_sdk::ButtrBaseClient;
let bb = ButtrBaseClient::new("bb_live_cid_...", "bb_live_sk_...");
// Local JWT verification — no network call let claims = bb.verify_token(&bearer).await?; let is_app_admin = claims.app_admin.contains(&app_id);
// Remote entitlement check let result = bb.check_entitlement(&bearer, "admin_panel").await?; if result.granted { / allow access / }
// App access check (new) let access = bb.check_app_access(&bearer, &app_id).await?; if access.is_app_admin { / show admin UI / } ~~~
Node
~~~typescript import { ButtrBaseClient } from '@buttrbase/sdk';
const bb = new ButtrBaseClient({ clientId: '...', clientSecret: '...' });
const claims = await bb.verifyToken(bearer); const check = await bb.checkEntitlement(bearer, 'admin_panel'); const access = await bb.checkAppAccess(bearer, appId); ~~~
Python
~~~python from buttrbase import ButtrBaseClient
bb = ButtrBaseClient(client_id='...', client_secret='...')
claims = await bb.verify_token(bearer) check = await bb.check_entitlement(bearer, 'admin_panel') access = await bb.check_app_access(bearer, app_id) ~~~