Appearance
GrydAuth CRUD Endpoints (V1)
Referencia oficial dos endpoints de gestao do modulo Auth (V1).
Escopo
Este documento cobre:
UsersController(/api/v1/users/*)AdminUsersController(/api/v1/admin/users/*)RolesController(/api/v1/roles/*)PermissionsController(/api/v1/permissions/*)TenantsController(/api/v1/tenants/*)AdminTenantsController(/api/v1/admin/tenants/*)
De/Para frontend (migracao)
Endpoints removidos
GET /api/v1/users/{id}/tenant-accessPUT /api/v1/users/{id}/tenant-accessPUT /api/v1/admin/users/{id}/tenant-access(nao existe no contrato final)
Endpoints alterados
GET /api/v1/admin/users/{id}- Agora retorna
UserDtocom matriz completa emtenants.
- Agora retorna
PUT /api/v1/admin/users/{id}- Contrato unico de atualizacao admin com blocos opcionais.
tenants(quando enviado) executafull replaceda matriz tenant/roles do usuario.
Endpoints principais para tela admin de usuarios
POST /api/v1/admin/usersGET /api/v1/admin/usersGET /api/v1/admin/users/{id}PUT /api/v1/admin/users/{id}GET /api/v1/admin/tenants/{tenantId}/roles(apoio para montar selecao de roles por tenant)
Contrato HTTP
- Base path:
/api/v1 - Sucesso: payload direto (sem envelope
Result<T>no body) - Erro:
ProblemDetails(application/problem+json)
Shape de erro
json
{
"type": "https://gryd.io/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "User not found",
"instance": "/api/v1/admin/users/550e8400-e29b-41d4-a716-446655440000",
"traceId": "00-...",
"code": "USER_NOT_FOUND",
"errors": ["User not found"]
}Query params comuns (QueryParameters)
page(default1)pageSize(default20, max100)sortBy(opcional)sortDirection(Ascending|Descending)search(opcional)includeDeleted(defaultfalse)
DTOs principais
CreateUserDto
json
{
"email": "novo@empresa.com",
"password": "SenhaForte123!",
"isPasswordEncrypted": false,
"firstName": "Novo",
"lastName": "Usuario",
"phoneNumber": "+5511999999999",
"tenants": [
{
"tenantId": "11111111-1111-1111-1111-111111111111",
"roleIds": [
"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
],
"isDefault": true
}
],
"appIds": ["APP_WEB"],
"isActive": true
}UpdateUserDto (tenant-scoped)
json
{
"firstName": "Nome",
"lastName": "Sobrenome",
"phoneNumber": "+5511999999999",
"appIds": ["APP_WEB"],
"isActive": true
}AdminUpdateUserDto (contrato unico de update admin)
json
{
"firstName": "Nome",
"lastName": "Sobrenome",
"phoneNumber": "+5511999999999",
"appIds": ["APP_WEB"],
"isActive": true,
"tenants": [
{
"tenantId": "11111111-1111-1111-1111-111111111111",
"roleIds": [
"aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
],
"isDefault": true
},
{
"tenantId": "22222222-2222-2222-2222-222222222222",
"roleIds": [],
"isDefault": false
}
]
}Regra de tenants no PUT /api/v1/admin/users/{id}:
tenants = null(ou omitido): nao altera matriz tenant/roles.tenants = []: remove todos os vinculos tenant/roles do usuario.tenantspreenchido: substitui a matriz inteira (full replace).
AdminUserEditDto (retorno de edicao admin)
Shape usado por:
GET /api/v1/admin/usersGET /api/v1/admin/users/{id}PUT /api/v1/admin/users/{id}
Campos:
id,email,firstName,lastName,phoneNumber,isActivecreatedAt,updatedAtappIdstenants:tenantId,roleIds,isDefault
Obs:
POST /api/v1/admin/usersainda retornaUserDto.- Fluxo recomendado para front: apos criar, chamar
GET /api/v1/admin/users/{id}para hidratar a tela de edicao no contrato unificado.
Admin Users
Base route: /api/v1/admin/users
Permissao padrao: admin:system
Regras de autorizacao para rotas cross-tenant (/api/v1/admin/users*):
- Requer claim/permissao
admin:system. - Requer
User.AllowCrossTenantAccess = true(controle de seguranca para bypass de tenant filter). - Falha nessas regras retorna
403comcode = CROSS_TENANT_FORBIDDEN.
| Metodo | Rota | Request | Response sucesso |
|---|---|---|---|
| GET | /api/v1/admin/users | Query UsersQueryParameters + tenantId opcional | 200 PagedResult<AdminUserEditDto> |
| POST | /api/v1/admin/users | Body CreateUserDto | 201 UserDto + Location |
| GET | /api/v1/admin/users/{id} | Path id | 200 AdminUserEditDto |
| PUT | /api/v1/admin/users/{id} | Path id + Body AdminUpdateUserDto | 200 AdminUserEditDto |
| DELETE | /api/v1/admin/users/{id} | Path id | 200 vazio |
| GET | /api/v1/admin/users/{id}/tenants | Path id | 200 UserTenantDto[] |
Users (tenant-scoped)
Base route: /api/v1/users
| Metodo | Rota | Permissao | Request | Response sucesso |
|---|---|---|---|---|
| GET | /api/v1/users | read:users | Query UsersQueryParameters | 200 PagedResult<UserDto> |
| GET | /api/v1/users/{id} | read:users | Path id | 200 UserDto |
| GET | /api/v1/users/by-email/{email} | read:users | Path email | 200 UserDto |
| POST | /api/v1/users | create:users | Body CreateUserDto | 201 UserDto + Location |
| PUT | /api/v1/users/{id} | update:users | Path id + Body UpdateUserDto | 200 UserDto |
| DELETE | /api/v1/users/{id} | delete:users | Path id | 200 vazio |
| GET | /api/v1/users/{userId}/permissions | read:users | Path userId | 200 string[] |
| GET | /api/v1/users/{userId}/roles | read:users | Path userId | 200 RoleDto[] |
| GET | /api/v1/users/{userId}/tenants | read:users | Path userId | 200 UserTenantDto[] |
| POST | /api/v1/users/{id}/activate | update:users | Path id | 200 vazio |
| POST | /api/v1/users/{id}/deactivate | update:users | Path id | 200 vazio |
Admin Tenants
Base route: /api/v1/admin/tenants
Permissao: admin:system
| Metodo | Rota | Request | Response sucesso |
|---|---|---|---|
| GET | /api/v1/admin/tenants/{tenantId}/roles | Path tenantId + Query RolesQueryParameters | 200 PagedResult<RoleDto> |
Roles
Base route: /api/v1/roles
| Metodo | Rota | Permissao | Request | Response sucesso |
|---|---|---|---|---|
| GET | /api/v1/roles | read:roles | Query RolesQueryParameters | 200 PagedResult<RoleDto> |
| GET | /api/v1/roles/{id} | read:roles | Path id | 200 RoleDto |
| POST | /api/v1/roles | create:roles | Body CreateRoleDto | 201 RoleDto + Location |
| PUT | /api/v1/roles/{id} | update:roles | Path id + Body UpdateRoleDto | 200 RoleDto |
| DELETE | /api/v1/roles/{id} | delete:roles | Path id | 200 vazio |
UpdateRoleDto agora suporta sincronizacao da lista de permissoes (permissionIds) no proprio PUT /api/v1/roles/{id}:
permissionIds = null(ou omitido): nao altera permissoes do role.permissionIds = []: remove todas as permissoes do role.permissionIdspreenchido: substitui integralmente a lista (full replace).
Permissions
Base route: /api/v1/permissions
| Metodo | Rota | Permissao | Request | Response sucesso |
|---|---|---|---|---|
| GET | /api/v1/permissions | read:permissions | Query PermissionsQueryParameters | 200 PagedResult<PermissionDetailsDto> |
| GET | /api/v1/permissions/catalog | read:permissions | Query PermissionCatalogQueryParameters | 200 PagedResult<PermissionCatalogGroupDto> |
| GET | /api/v1/permissions/catalog/categories | read:permissions | Query PermissionCategorySuggestionsQueryParameters | 200 PermissionCategorySuggestionResultDto |
| GET | /api/v1/permissions/{id} | read:permissions | Path id | 200 PermissionDetailsDto |
| GET | /api/v1/permissions/by-code/{code} | read:permissions | Path code | 200 PermissionDetailsDto |
| POST | /api/v1/permissions | create:permissions | Body CreatePermissionDto (code, description, category) | 201 PermissionDetailsDto + Location |
| GET | /api/v1/permissions/import/template | create:permissions | Query format (Csv/Json) + mode (Permissions/Catalog) | 200 arquivo (text/csv ou application/json) |
| POST | /api/v1/permissions/import | create:permissions | Body PermissionImportRequestDto + Query mode, upsert, dryRun | 200 PermissionImportResultDto |
| POST | /api/v1/permissions/import/file | create:permissions | Multipart (file) + Query mode, upsert, dryRun | 200 PermissionImportResultDto |
| PUT | /api/v1/permissions/{id} | update:permissions | Path id + Body UpdatePermissionDto (description, category) | 200 PermissionDetailsDto |
| DELETE | /api/v1/permissions/{id} | delete:permissions | Path id | 200 vazio |
Tenants
Base route: /api/v1/tenants
| Metodo | Rota | Permissao | Request | Response sucesso |
|---|---|---|---|---|
| GET | /api/v1/tenants | read:tenants | Query TenantsQueryParameters | 200 PagedResult<TenantDto> |
| GET | /api/v1/tenants/{id} | read:tenants | Path id | 200 TenantDto |
| POST | /api/v1/tenants | create:tenants | Body CreateTenantDto | 201 TenantDto + Location |
| PUT | /api/v1/tenants/{id} | update:tenants | Path id + Body UpdateTenantDto | 200 TenantDto |
| DELETE | /api/v1/tenants/{id} | delete:tenants | Path id | 200 vazio |
Observacoes frontend
- Guia detalhado de migracao (catalogo de permissoes e breaking changes):
docs/modules/auth/frontend-permissions-migration.md
- Fluxo recomendado de criacao/edicao admin:
POST /api/v1/admin/userspara criar.GET /api/v1/admin/users/{id}para carregar tela de edicao (incluitenants).PUT /api/v1/admin/users/{id}para salvar tudo em uma chamada unica.
- Para montar seletor de roles por tenant em tela admin:
- use
GET /api/v1/admin/tenants/{tenantId}/roles.
- use
- Para tela de permissao por funcionalidade:
- use
GET /api/v1/permissions/catalog(lista agrupada por categoria). - use
GET /api/v1/permissions/catalog/categories(autocomplete de categorias). - para carga em massa, use
POST /api/v1/permissions/importouPOST /api/v1/permissions/import/file.
- use
- Trate erros sempre por
ProblemDetails(detail,code,errors,traceId).
Erros de autenticacao/autorizacao (regra de consumo)
401(TOKEN_MISSING,TOKEN_INVALID,TOKEN_EXPIRED,TOKEN_REVOKED,SESSION_INVALIDATED): sessao invalida, fluxo de reautenticacao.403(FORBIDDEN,MISSING_PERMISSION,TENANT_FORBIDDEN,CROSS_TENANT_FORBIDDEN): usuario autenticado sem permissao/contexto, sem logout automatico.