Exportação de permissões — API
Exporta, em CSV, quem tem cada permissão numa unidade e por qual papel — um relatório de auditoria de acesso pronto para download, sem paginação (a unidade inteira sai numa só resposta).
Funcionamento
- Confirma que o ator autenticado tem
permission:readnaquela unidade (ResolveIdentityEffectivePermissionService.resolveAuthorizedUnit); sem isso, nega comIDENTITY_PERMISSION_EXPORT_FORBIDDEN— umerrorCodede negócio próprio, não o 403 genérico do guard, porque o filtro de escopo (kind: 'unit') por si só permitiria a chamada; a rejeição final é decidida no serviço. - Busca toda atribuição de papel ativa naquela unidade (direta na unidade ou tenant-wide que alcança a unidade), agrupada por usuário.
- Para cada usuário e cada permissão do catálogo atribuível (opcionalmente filtrada por
permission), verifica se algum papel atribuído a ele concede aquele bit. Se sim, gera uma linha com o(s) nome(s) de papel que concedem, e a origem (TENANT_WIDEse algum papel veio de um grant de tenant,UNIT_SCOPEDcaso contrário). - Usuários inativos e atribuições expiradas são excluídos antes de montar as linhas — não entram no CSV mesmo que o registro exista no banco.
- Nomes de usuário são neutralizados contra injeção de fórmula de planilha: um valor que
começa com
=,+,-,@, tab ou retorno de carro é escapado antes de entrar no CSV (proteção confirmada em teste: "neutralizes spreadsheet formulas in user names").
Endpoints
| Método | Rota | Descrição |
|---|---|---|
| GET | /v1/units/:unitId/users/permissions-export | Exporta as permissões efetivas da unidade em CSV |
Versão: v1
Swagger: identityPermissionExportExport · Rota (Dev): http://localhost:3000/v1/units/{unitId}/users/permissions-export
Permissões
| Rota | Guards | Permissão exigida (escopo unit) |
|---|---|---|
GET .../permissions-export | IdentityOAuthAccessTokenGuard, AuthorizationGuard | permission:read, e confirmação adicional no serviço (resolveAuthorizedUnit) |
Headers
| Header | Obrigatório | Descrição |
|---|---|---|
Authorization | Sim | Bearer <access_token> |
Content-Type (resposta) | — | text/csv; charset=utf-8 |
Content-Disposition (resposta) | — | attachment; filename="user-permissions.csv" |
Path parameters
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
unitId | uuid | Sim | Unidade a exportar |
Query parameters
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
permission | string | Não | Filtra a exportação a uma única permissão; formato recurso:ação (@Matches(/^\S+:\S+$/)) |
Body
Nenhum (rota GET).
Response
200 — corpo text/csv (IdentityPermissionExport, header real do CSV):
csvuser_id,user_name,roles,permission,source0197...,Ana Souza,read_only,exam:read,UNIT_SCOPED0198...,Carlos Lima,manager,exam:read,TENANT_WIDE
O exemplo do @ApiOkResponse no Swagger mostra apenas permission,unit_id — está desatualizado
em relação ao schema real montado por IdentityPermissionExport (ver "Divergências" abaixo); o
header e as colunas acima são os que o código de fato escreve (CSV_HEADER em
identity-permission-export.ts).
Mapa de campos
| Coluna do CSV | Tipo | Valores possíveis | Descrição |
|---|---|---|---|
user_id | uuid | — | Identificador do usuário |
user_name | string | — | Nome de exibição do usuário; neutralizado contra fórmula de planilha |
roles | string | — | Nome(s) de exibição do(s) papel(éis) que concedem a permissão, unidos por ; , em ordem alfabética |
permission | string | catálogo atribuível | Permissão concedida (recurso:ação) |
source | string | TENANT_WIDE, UNIT_SCOPED | Se a concessão vem de um grant de tenant ou só da unidade |
Erros
| Classe de erro | errorCode | Status | Quando ocorre |
|---|---|---|---|
| (validação de query/UUID) | BAD_REQUEST / INVALID_UUID | 400 | unitId inválido, permission fora do formato recurso:ação |
UnauthenticatedError | IDENTITY_INVALID_OAUTH_ACCESS_TOKEN | 401 | access token ausente/inválido/expirado/inativo |
ForbiddenAction | IDENTITY_PERMISSION_EXPORT_FORBIDDEN | 403 | ator sem permission:read efetivo naquela unidade (checagem de negócio, além do guard) |
Regras de negócio
| ID | Regra | Comportamento esperado |
|---|---|---|
| RN-01 | Exportação restrita ao escopo do ator | precisa de permission:read efetivo na unidade exportada; ausência gera IDENTITY_PERMISSION_EXPORT_FORBIDDEN, não 404 |
| RN-02 | Usuários inativos não aparecem | mesmo com atribuição ativa no banco, um usuário inativo é excluído da exportação |
| RN-03 | Atribuições expiradas não aparecem | uma atribuição com expiresAt no passado não gera linha |
| RN-04 | Revogação reflete na próxima exportação | uma atribuição revogada é removida do CSV imediatamente (confirmado em teste) |
| RN-05 | CSV neutraliza fórmula de planilha no nome do usuário | valores começando com =, +, -, @, tab ou retorno de carro são escapados — mitigação de CSV injection |
| RN-06 | permission filtra sem mudar a autorização | passar um nome de permissão só restringe as linhas retornadas; não amplia nem reduz a permissão exigida para chamar a rota |
Compliance
| Órgão / norma | Exigência | Como a rota atende |
|---|---|---|
| LGPD | Minimização e segurança no tratamento de dado exportado | escopo restrito à unidade autorizada; neutralização de fórmula evita execução de conteúdo malicioso ao abrir o CSV numa planilha |
| HIPAA / ANVISA | Relatório de acesso auditável | a exportação em si é a ferramenta de auditoria (quem pode o quê, por qual papel); não há evento de auditoria adicional para o ato de exportar confirmado no código (ver NFR) |
Variáveis de ambiente
Nenhuma variável de ambiente é consumida diretamente por esta rota.
Tempo médio de resposta
A confirmar — responsável: time de Identity; data: 24/09/2026. Sem medição publicada — o cálculo
percorre todas as atribuições e todo o catálogo atribuível por usuário, então tende a crescer com
o tamanho da unidade.
Requisitos não funcionais
| Requisito | Definição |
|---|---|
| Idempotência | Sim (leitura pura) |
| Paginação | Não — a unidade inteira é exportada numa só resposta |
| Rate limit | Não identificado |
| Cache | Não identificado |
| Auditoria | Não identificado evento de auditoria específico para o ato de exportar, neste levantamento |
Divergências e lacunas confirmadas
- O exemplo do Swagger (
ApiOkResponse) mostra apenaspermission,unit_idcomo colunas do CSV, mas o modelo real (IdentityPermissionExport, a partir das linhas montadas no serviço) inclui usuário, papéis e origem — o exemplo do Swagger está desatualizado em relação ao schema real; divergência de documentação, não de comportamento.
Relacionado
- 📂 Módulo: Authorization
- 🔁 Ver também: Membros de unidade (mesma unidade, visão sem export) e Atribuição de papéis