Inspeção de autorização — API
Quatro rotas de diagnóstico para suporte, automação e telas administrativas: verificar se outro usuário teria uma permissão (sem de fato executar a ação), ver a autorização efetiva completa de um usuário com a origem de cada permissão, e checar se o catálogo persistido está consistente com o catálogo esperado em código.
Funcionamento
POST /tenants/:tenantId/authorization/checks: roda a mesma lógica que oAuthorizationGuardusaria para autorizar uma requisição real (RBAC + política), mas devolve o resultado como dado (allowed,granted_permissions,denied_permissions,reason_code) em vez de deixar passar ou lançar 403. É síncrona e não tem efeito colateral. Qualquer erro interno durante a checagem (claim indisponível, política indisponível) é convertido emallowed: false, reason_code: authorization-unavailable— a rota nunca lança 500 por causa da checagem em si.POST /tenants/:tenantId/authorization/bulk-checks: até 50 checagens no mesmo formato acima, cada uma resolvida independentemente (uma checagem inválida/negada não afeta as outras).GET /tenants/:tenantId/authorization/users/:userId/effective: a visão mais completa — devolve o bitmask do tenant e da unidade (se informada), cada permissão efetiva com a lista de atribuições que a concedem (sources[]: qual papel, qual escopo), os papéis ativos do usuário naquele tenant/unidade e as políticas ativas do tenant. Se o tenant não existe/está inativo, ou a unidade informada não pertence a ele, devolve um resultado vazio (200), não um erro — a rota é pensada para nunca revelar por erro se um tenant/unidade existe.GET /tenants/:tenantId/authorization/consistency: compara o catálogo de permissões e os nove papéis de sistema persistidos contra o que o código espera (PermissionCatalog.assignable()eIdentitySystemRoleCatalog.reconciled()), reportandoconsistent: true/falsepor verificação. Serve para detectar bootstrap que não rodou ou dessincronia após um deploy.
Endpoints
| Método | Rota | Descrição |
|---|---|---|
| POST | /v1/tenants/:tenantId/authorization/checks | Verifica se um usuário teria uma ou mais permissões |
| POST | /v1/tenants/:tenantId/authorization/bulk-checks | Até 50 verificações numa só chamada |
| GET | /v1/tenants/:tenantId/authorization/users/:userId/effective | Autorização efetiva completa, com origem de cada permissão |
| GET | /v1/tenants/:tenantId/authorization/consistency | Compara o catálogo persistido com o esperado em código |
Versão: v1
Swagger: Identity — Authorization inspection · Rota (Dev): http://localhost:3000/v1/tenants/{tenantId}/authorization/checks
Permissões
| Rota | Guards | Permissão exigida (escopo tenant) |
|---|---|---|
POST /checks, POST /bulk-checks, GET /users/:userId/effective | IdentityOAuthAccessTokenGuard, AuthorizationGuard | permission:read e user:read (match: all) |
GET /consistency | idem | permission:read e role:read (match: all) |
Headers
| Header | Obrigatório | Descrição |
|---|---|---|
Authorization | Sim | Bearer <access_token> |
Path parameters
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
tenantId | uuid | Sim | Tenant no qual a checagem/consulta é feita |
userId | uuid | Sim, em GET .../effective | Usuário cuja autorização está sendo inspecionada |
Query parameters
GET /users/:userId/effective:
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
unit_id | uuid | Não | Restringe o cálculo a uma unidade; ausente = só tenant-wide |
Body
POST /checks — IdentityAuthorizationCheckRequest:
json{ "user_id": "77aa...uuid", "unit_id": "9b3c...uuid", "permissions": ["exam:read", "exam:write"], "match": "all" }
| Campo | Tipo | Obrigatório | Validação |
|---|---|---|---|
user_id | uuid | Sim | — |
unit_id | uuid | Não | se ausente, checa no escopo do tenant |
permissions | string[] | Sim | 1 a 100 itens, sem duplicatas |
match | all | any | Sim | — |
POST /bulk-checks — IdentityAuthorizationBulkCheckRequest:
json{ "checks": [ { "user_id": "77aa...", "permissions": ["exam:read"], "match": "all" } ] }
| Campo | Tipo | Obrigatório | Validação |
|---|---|---|---|
checks[] | IdentityAuthorizationCheckRequest | Sim | 1 a 50 itens |
Response
POST /checks e cada item de /bulk-checks — IdentityAuthorizationCheckResponse:
json{ "data": { "allowed": true, "granted_permissions": ["exam:read"], "denied_permissions": [], "reason_code": "policy-allowed" } }
GET /users/:userId/effective — 200 (IdentityEffectiveAuthorizationResponse):
json{"data": {"user_id": "77aa...uuid","tenant_id": "1f2a...uuid","unit_id": "9b3c...uuid","tenant_mask": "17","unit_masks": { "9b3c...uuid": "17" },"permissions": [{"name": "exam:read","resource": "exam","action": "read","bit_position": 0,"sources": [ { "assignment_id": "3c9e...uuid", "role_id": "0198f1a2-...", "role_name": "doctor", "scope": "tenant", "unit_id": null } ]}],"roles": [ { "assignment_id": "3c9e...uuid", "role_id": "0198f1a2-...", "name": "doctor", "display_name": "Doctor", "scope": "tenant", "unit_id": null, "expires_at": null } ],"active_policies": [ { "id": "5e1c...uuid", "name": "deny-read-only-export", "permission_name": "user:export", "effect": "deny", "priority": 100, "version": 1 } ]}}
GET /consistency — 200 (IdentityAuthorizationConsistencyResponse):
json{"data": {"consistent": true,"checks": [{ "name": "permission-catalog", "consistent": true, "expected": 104, "actual": 104 },{ "name": "system-role-catalog", "consistent": true, "expected": 9, "actual": 9 }]}}
Mapa de campos
| Campo | Tipo | Valores possíveis | Descrição |
|---|---|---|---|
reason_code (checks) | string | policy-allowed, policy-denied, rbac-denied, claim-unavailable, authorization-unavailable | Motivo da decisão simulada |
sources[].scope | string | tenant, unit | De onde vem a concessão daquela permissão |
checks[].name (consistency) | string | permission-catalog, system-role-catalog | Qual verificação de consistência |
checks[].expected / .actual | integer | — | Contagem esperada (em código) vs. persistida (no banco) |
Erros
| Classe de erro | errorCode | Status | Quando ocorre |
|---|---|---|---|
| (validação de payload/UUID) | BAD_REQUEST / INVALID_UUID | 400 | corpo ou tenantId/userId malformados; checks[] vazio ou acima de 50 |
UnauthenticatedError | IDENTITY_INVALID_OAUTH_ACCESS_TOKEN | 401 | access token ausente/inválido |
ForbiddenAction (guard) | — | 403 | ator sem permission:read+user:read (checks/effective) ou permission:read+role:read (consistency) no tenant |
POST /checks e /bulk-checks nunca propagam um erro de negócio para o corpo da resposta — uma
falha interna vira allowed: false, reason_code: "authorization-unavailable" com 200. A
autorização (ou falta dela) do usuário-alvo nunca vaza como 403/404 — só como um campo do
resultado.
Regras de negócio
| ID | Regra | Comportamento esperado |
|---|---|---|
| RN-01 | Checagem é uma simulação, não uma autorização real | não popula authorizationContext, não tem efeito colateral, pode ser chamada repetidamente |
| RN-02 | Checagem nunca lança erro de negócio | qualquer falha interna vira allowed:false com reason_code descritivo, sempre 200 |
| RN-03 | effective nunca revela por erro se um tenant/unidade existe | tenant inativo ou unidade fora do tenant → resultado vazio, 200 |
| RN-04 | effective explica a origem de cada permissão | cada permissão listada traz a(s) atribuição(ões)/papel(éis) que a concedem, não só o nome |
| RN-05 | consistency compara contagem e conteúdo, não só quantidade | system-role-catalog também compara o conjunto de permissões de cada papel de sistema persistido contra o esperado |
Compliance
| Órgão / norma | Exigência | Como a rota atende |
|---|---|---|
| LGPD | Minimização | effective/checks só devolvem os campos de autorização necessários ao diagnóstico, sem dado clínico |
| HIPAA / ANVISA | Auditabilidade da decisão de acesso | effective expõe a origem de cada permissão (papel/atribuição) para investigação de incidente |
Variáveis de ambiente
Nenhuma variável de ambiente é consumida diretamente por estas rotas.
Tempo médio de resposta
A confirmar — responsável: time de Identity; data: 24/09/2026. Sem medição publicada.
Requisitos não funcionais
| Requisito | Definição |
|---|---|
| Idempotência | Sim (leitura/simulação pura, sem efeito colateral) |
| Paginação | Não se aplica |
| Rate limit | Não identificado |
| Cache | Não identificado — cada checagem/consulta lê a claim atual |
| Auditoria | Não — rotas de leitura/diagnóstico, sem evento de auditoria dedicado |
Relacionado
- 📂 Módulo: Authorization
- 🔁 Usa a mesma lógica de:
AuthorizationGuarde Políticas de autorização - 🔁 Ver também: Minhas permissões (a mesma informação, mas só sobre o próprio ator, sem exigir permissão)