Roles & permissions
Summary
The seven endpoints you'll touch most, plus scopes and common errors.
Endpoints you'll use most
| Operation | Method | Path | Permission |
|---|---|---|---|
| List roles | GET | /api/v1/roles | roles:read |
| Create a role | POST | /api/v1/roles | roles:create |
| Assign a role to a user | POST | /api/v1/roles/assign | roles:assign |
| Remove a role from a user | POST | /api/v1/roles/remove | roles:revoke |
| Attach permissions to a role | POST | /api/v1/roles/:id/permissions | roles:update |
| Grant a permission directly | POST | /api/v1/permissions/grant | permissions:grant |
| Check the caller's permission live | POST | /api/v1/permissions/check | — |
Curl quick reference
# Assign a role
curl -X POST https://auth.febasi.com.br/api/v1/roles/assign \
-H "Authorization: Bearer $ADMIN_JWT" \
-H "Content-Type: application/json" \
-d '{ "userId": "01HXY...", "roleId": "01HX5..." }'
# Grant a single permission
curl -X POST https://auth.febasi.com.br/api/v1/permissions/grant \
-H "Authorization: Bearer $ADMIN_JWT" \
-H "Content-Type: application/json" \
-d '{ "userId": "01HXY...", "permissionId": "01HZ1..." }'
# Live permission check (caller's own)
curl -X POST https://auth.febasi.com.br/api/v1/permissions/check \
-H "Authorization: Bearer $USER_JWT" \
-H "Content-Type: application/json" \
-d '{ "permissionName": "reports:export" }'The body field on /permissions/check is permissionName (matches the regex ^[a-z][a-z0-9_]*:[a-z][a-z0-9_]*$). The endpoint checks the caller's own permissions, reading effective permissions from the database — useful right after a grant when the JWT cache is still stale.
Common errors
| Code | Status | When |
|---|---|---|
HIERARCHY_VIOLATION | 403 | Trying to manage a role/user at or above the actor's level. Carries actorLevel and targetLevel. |
PROTECTED_RESOURCE | 403 | Trying to modify a system role (super_admin, …). |
USER_CONTEXT_REQUIRED | 400 | /permissions/check called by a Client Key with no user context. |
ROLE_NOT_FOUND | 404 | The roleId does not exist in the caller's tenant. |
PERMISSION_NOT_FOUND | 404 | The permissionId does not exist. |
When edits take effect
| Where | Latency |
|---|---|
/permissions/check | Immediate — reads the live database. |
| The user's own session (their JWT) | Next /refresh or /login — JWT carries the snapshot at issuance. |
| Downstream services that verify the JWT locally | Same — they only see what's in the token. |
If a permission change must propagate now, either force the user to refresh or rely on /permissions/check for that single decision.