RBAC & Permissions on Access Tokens
Role → permission → permissionsclaim · a real allow/deny decision, not just a session check
Role
reports-editor-demo / reports-viewer-demo
Permissions
read:reports, write:reports (attached to the role)
RBAC on
Access Token
permissions claim, real & signed
A trap, not a feature
It is easy to assume a role assigned tenant-wide "just works" once Organizations gets added to a login flow. It doesn't — the org-context permissions below are visibly narrower than the tenant-context ones for the exact same user, because the org-scoped role (reports-viewer-demo) genuinely only has read:reports attached, unlike the tenant-wide role (reports-editor-demo).
Auth0 blog — 5 Reasons Why Your Permissions Are Not in the Token.
This demo needs a specific, pre-built role setup to show the contrast below — a tenant-wide role that differs on purpose from an org-scoped one, on the same person — so it isn't self-serve for a brand-new account the way most of this suite's demos are. Sign in with the shared test account:
- rbac-demo@atko.email
- password
- RbacDemo!2026#Zx
That account has reports-editor-demo (read + write) assigned tenant-wide, and only reports-viewer-demo (read only) assigned inside this demo's pre-provisioned Organization — the two scenarios below only make sense with that specific mismatch already in place.
Strengths
- The permissions claim on the access token is signed and computed server-side by Auth0 at token-mint time from the actual role assignments in effect for that login — an API checking it isn't trusting anything the client asserted about itself.
- RBAC + Organizations composes cleanly at the data-model level: org-scoped role assignments are a distinct, first-class object from tenant-wide ones, not a bolt-on filter over the same role list.
Risks & Considerations
- Enabling RBAC on a resource server is two separate toggles ("Enable RBAC" and "Add Permissions in the Access Token") — either alone silently produces a token with no permissions claim at all, which looks identical to "user has no permissions" rather than "misconfigured resource server."
- Tenant-level and organization-level role assignments are separate Auth0 objects. Assigning a role tenant-wide has no effect on what permissions show up when that same user logs in with an organization parameter — a real, confirmed trap (not a hypothetical one) when a demo tenant or a real deployment already has global RBAC roles set up and someone assumes those carry over into an org context.
- A role with no permissions attached still "successfully" assigns — there is no error at role-assignment time to warn that the resulting token will carry an empty permissions array for that role.
Hardening Checklist
- Check both RBAC toggles are on together when a permissions claim is unexpectedly missing — don't assume one implies the other.
- When debugging org-context permissions, check the role assignment at organizations/{id}/members/{user}/roles specifically, not just the user's tenant-wide roles endpoint — they are genuinely different data.
- Treat "delete:reports" (or any permission nobody currently holds) as a deliberate negative test case in any RBAC-gated API, the same way this demo does — confirming the deny path actually denies is as important as confirming the allow path allows.