Febasidocs
Roles & permissions

Summary

The seven endpoints you'll touch most, plus scopes and common errors.

Endpoints you'll use most

OperationMethodPathPermission
List rolesGET/api/v1/rolesroles:read
Create a rolePOST/api/v1/rolesroles:create
Assign a role to a userPOST/api/v1/roles/assignroles:assign
Remove a role from a userPOST/api/v1/roles/removeroles:revoke
Attach permissions to a rolePOST/api/v1/roles/:id/permissionsroles:update
Grant a permission directlyPOST/api/v1/permissions/grantpermissions:grant
Check the caller's permission livePOST/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

CodeStatusWhen
HIERARCHY_VIOLATION403Trying to manage a role/user at or above the actor's level. Carries actorLevel and targetLevel.
PROTECTED_RESOURCE403Trying to modify a system role (super_admin, …).
USER_CONTEXT_REQUIRED400/permissions/check called by a Client Key with no user context.
ROLE_NOT_FOUND404The roleId does not exist in the caller's tenant.
PERMISSION_NOT_FOUND404The permissionId does not exist.

When edits take effect

WhereLatency
/permissions/checkImmediate — 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 locallySame — 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.

On this page