Skip to main content

Vínculo do usuário com serviço externo — API

Gerencia o vínculo entre um usuário e uma integração externa nomeada (instant, laudite ou iara) — um token de serviço opaco, ativo/inativo, com expiração opcional — e expõe um endpoint interno, autenticado por segredo compartilhado, para que o próprio serviço externo resolva esse token de volta para um userId da Identity.

Funcionamento​

  1. Listar (GET /users/:userId/external-services): o próprio usuário sempre pode ver seus vínculos; para ver os de um terceiro, o ator precisa ser administrador de plataforma.
  2. Registrar/atualizar (PUT /users/:userId/external-services/:serviceName): cria o vínculo se não existir, ou atualiza os campos enviados sobre o vínculo existente (campos omitidos mantêm o valor atual — undefined preserva, null limpa). O service_token em claro nunca é persistido nem devolvido: só o hash SHA-256 é gravado, e a resposta expõe apenas has_token: true/false.
  3. serviceName só aceita os valores do catálogo fixo (instant, laudite, iara); qualquer outro valor é rejeitado antes de tocar o banco.
  4. Resolver (GET /internal/v1/external-services/:serviceName/resolve): rota sem guard de OAuth — a autenticação é o header X-Service-Token comparado (por hash) contra o vínculo ativo daquele serviço. Um vínculo inativo, expirado, ou de um serviço diferente, sempre resulta em "não encontrado" (nunca distingue o motivo).

Endpoints​

MétodoRotaDescrição
GET/v1/users/:userId/external-servicesLista os vínculos de um usuário
PUT/v1/users/:userId/external-services/:serviceNameCria ou atualiza um vínculo
GET/internal/v1/external-services/:serviceName/resolveResolve um token de serviço para um userId (uso S2S)

Versão: v1 (as duas primeiras) · VERSION_NEUTRAL com v1 fixo no path (a última)

Swagger: Identity — User administration and profile e Identity — Internal external-service resolution · Rota (Dev): http://localhost:3000/v1/users/:userId/external-services

Permissões​

RotaGuardsRegra de acesso
GET /users/:userId/external-servicesIdentityOAuthAccessTokenGuardpróprio usuário, ou administrador de plataforma para terceiro
PUT /users/:userId/external-services/:serviceNameidemidem
GET /internal/v1/external-services/:serviceName/resolvenenhum guard OAuthheader X-Service-Token válido para o serviço nomeado

Headers​

HeaderObrigatórioDescrição
AuthorizationSim (rotas /users/...)Bearer <access_token>
X-Service-TokenSim (rota /internal/...)token opaco do serviço externo (comparado por hash)

Path parameters​

NomeTipoObrigatórioDescrição
userIduuidSim (GET/PUT de /users)Usuário dono do vínculo
serviceNameinstant | laudite | iaraSimNome da integração

Body​

PUT /users/:userId/external-services/:serviceName — IdentityUserExternalServiceRequest:

json
{ "is_active": true, "service_token": "opaque-service-token", "expires_at": null, "extra_config": { "environment": "production" } }
CampoTipoObrigatórioValidação
is_activebooleanSim—
service_tokenstring | nullNão1–500 caracteres; null limpa o token; omitido mantém o atual
expires_atstring (ISO 8601) | nullNãonull remove expiração; omitido mantém a atual
extra_configobjeto JSON | nullNãoobjeto plano, sem ciclos, serializado até 16.384 caracteres

Response​

200 — IdentityUserExternalServiceResponse:

json
{
"id": "8e061c1d-...-52f90", "service_name": "laudite", "is_active": true,
"has_token": true, "activated_at": "2026-08-26T12:00:00.000Z", "expires_at": null
}

200 — resolução interna:

json
{ "userId": "8e061c1d-b2fa-4f55-92ee-54208e152f90" }

Erros​

Classe de erroerrorCodeStatusQuando ocorre
ValidationErrorIDENTITY_EXTERNAL_SERVICE_INVALID400serviceName fora do catálogo (instant/laudite/iara)
ValidationErrorIDENTITY_EXTERNAL_SERVICE_TOKEN_INVALID400service_token fora de 1–500 caracteres
ValidationErrorIDENTITY_EXTERNAL_SERVICE_CONFIGURATION_INVALID400extra_config não é objeto JSON plano ou excede o tamanho serializado
ValidationErrorIDENTITY_EXTERNAL_SERVICE_EXPIRATION_INVALID400expires_at não é uma data válida
ForbiddenActionIDENTITY_EXTERNAL_SERVICE_FORBIDDEN403ator não é o dono nem administrador de plataforma
IdentityUserNotFoundErrorIDENTITY_USER_NOT_FOUND404usuário alvo inativo
— (validação de request)BAD_REQUEST400header X-Service-Token ausente na rota interna
IdentityExternalServiceBindingNotFoundErrorIDENTITY_EXTERNAL_SERVICE_BINDING_NOT_FOUND404token não corresponde a um vínculo ativo e válido daquele serviço
—IDENTITY_INVALID_OAUTH_ACCESS_TOKEN401token ausente, inválido, expirado ou revogado (rotas /users/...)

Regras de negócio​

IDRegraComportamento esperado
RN-01Token de serviço nunca é devolvidoresposta expõe só has_token; persistência guarda apenas o hash SHA-256
RN-02Campo omitido preserva, null limpadistinção feita a nível de undefined vs. null no corpo da requisição
RN-03Catálogo de serviços é fixo no códigoinstant, laudite, iara — qualquer outro nome é rejeitado antes de qualquer acesso a dado
RN-04Resolução nunca distingue o motivo da falhatoken errado, vínculo inativo, expirado ou usuário inativo resultam todos em 404

Compliance​

Órgão / normaExigênciaComo a rota atende
LGPD/HIPAAsegredo de integração nunca em claroapenas o hash do token é armazenado; resposta nunca inclui o valor

Variáveis de ambiente​

Nenhuma específica a esta rota identificada no código (o segredo é por vínculo, não por variável de ambiente global).

Requisitos não funcionais​

RequisitoDefinição
IdempotênciaPUT é idempotente para o mesmo payload
AuditoriaSim — identity.user.external_service.updated

Relacionado​

  • 🖥️ Tela: A confirmar — responsável: time de frontend; data: 24/09/2026.
  • 📂 Módulo: Usuário