Checking Roles in Your App
This tutorial shows how to validate user roles from both your app's frontend and backend — covering platform admin, app admin, org roles, and feature entitlements.
The Three Checks
| What you want to know | Use |
|---|---|
| Who is this user and what can they do? | GET /api/auth/me |
| Does this user have feature X? | POST /api/entitlements/check |
| Is this user an admin of my specific app? | GET /api/marketplace/apps/:id/access |
---
Frontend: Driving Permission-Aware UI
Fetch /api/auth/me once after login and store the result. Use it to show or
hide UI elements without making a call per page.
~~~typescript
// React / SolidJS — call once after auth
const me = await fetch('/api/auth/me', {
headers: { Authorization: Bearer ${token} },
}).then(r => r.json());
// me.app_admin → string[] (app UUIDs this user can admin) // me.platform_admin → boolean // me.entitlements → string[] (active feature slugs)
const isAppAdmin = me.app_admin.includes(APP_ID); const canUseAnalytics = me.entitlements.includes('advanced_analytics'); ~~~
SolidJS example with a reactive store:
~~~typescript import { createResource } from 'solid-js';
const [me] = createResource(token, (tok) =>
fetch('/api/auth/me', { headers: { Authorization: Bearer ${tok} } })
.then(r => r.json())
);
// In JSX:
//
---
Backend: Middleware Gate (Rust / Axum)
Use the SDK's verify_token for local validation and check_entitlement for
server-side feature checks.
~~~rust use axum::{extract::State, http::HeaderMap, Json}; use buttrbase_sdk::ButtrBaseClient;
// Gate a route on app admin status
async fn admin_only_handler(
State(bb): State
// Local JWKS verification — no network call let claims = bb.verify_token(&bearer).await?;
if !claims.app_admin.contains(&APP_ID) { return Err(AppError::forbidden("app admin required")); }
// ... handler logic Ok(Json(serde_json::json!({ "ok": true }))) } ~~~
For entitlement checks:
~~~rust let result = bb.check_entitlement(&bearer, "advanced_analytics").await?; if !result.granted { return Err(AppError::forbidden("entitlement required: advanced_analytics")); } ~~~
---
Backend: Middleware Gate (Node / Express)
~~~typescript import { ButtrBaseClient } from '@buttrbase/sdk';
const bb = new ButtrBaseClient({ clientId: process.env.BB_CLIENT_ID!, clientSecret: process.env.BB_CLIENT_SECRET! });
// Middleware export async function requireAppAdmin(req, res, next) { const bearer = req.headers.authorization?.slice(7); if (!bearer) return res.status(401).json({ error: 'missing token' });
const claims = await bb.verifyToken(bearer); if (!claims.app_admin.includes(process.env.APP_ID!)) { return res.status(403).json({ error: 'app admin required' }); }
req.claims = claims; next(); }
// Usage router.get('/admin/installs', requireAppAdmin, async (req, res) => { // ... }); ~~~
---
Platform Admin Check
Platform admin routes are guarded server-side by ButtrBase itself. If you are building a self-hosted management tool that needs to distinguish platform admins from regular users:
~~~typescript const claims = await bb.verifyToken(bearer); if (!claims.platform_admin) { return res.status(403).json({ error: 'platform admin required' }); } ~~~
---
Token Refresh After Grant Changes
Role grants (app_admin, entitlements) are embedded at token issuance. If you
grant or revoke access, the user's current token remains valid until it expires
(15 minutes by default). For non-time-critical changes this is acceptable.
For immediate effect, tell the user to refresh:
~~~http POST /api/auth/refresh { "refresh_token": "..." } ~~~
The new access token will reflect the updated claims.