Skip to main content

Perfil e segurança do próprio usuário — API

Permite ao usuário autenticado ler e atualizar seus próprios dados: perfil (nome, telefone, CPF, data de nascimento), registro profissional (CRM ou licença estrangeira), configurações de segurança (e-mail verificado, e-mail de recuperação) e verificação de e-mail. Todas as rotas atuam sobre o próprio subject do access token — não recebem userId na URL.

Funcionamento​

  • Ler perfil (GET /users/me): busca o usuário ativo pelo id do token; usuário inativo ou inexistente é tratado como não encontrado.
  • Atualizar perfil (PATCH /users/me): aceita display_name, phone_number, cpf_number e birth_date, todos opcionais, mas ao menos um deve vir preenchido. Só os campos enviados são comparados com o valor atual; um campo idêntico ao já salvo não gera mudança nem evento de auditoria.
  • Substituir registro profissional (PUT /users/me/professional-license): valida a UF do CRM contra a tabela de estados brasileiros e impede que a mesma conta tenha simultaneamente um CRM brasileiro e uma licença estrangeira.
  • Ler configurações de segurança (GET /users/me/security): devolve e-mail, se o e-mail primário foi verificado e o e-mail de recuperação atual.
  • Solicitar verificação do e-mail primário (POST /users/me/email-verification): se o e-mail já está verificado, não reenvia nada e informa isso na resposta; senão emite um token de uso único e envia e-mail transacional.
  • Definir/trocar e-mail de recuperação (PATCH /users/me/recovery-email): sempre envia um e-mail de confirmação para o novo endereço antes de ele valer; o e-mail de recuperação atual só muda quando o link de confirmação é usado (fluxo fora desta página — ver authentication).
  • Limpar e-mail de recuperação (DELETE /users/me/recovery-email): mesmo endpoint interno de troca, chamado com recoveryEmail: null; remove imediatamente o e-mail de recuperação e qualquer confirmação pendente.

Endpoints​

MétodoRotaDescrição
GET/v1/users/meLê o perfil do usuário autenticado
PATCH/v1/users/meAtualiza campos do próprio perfil
PUT/v1/users/me/professional-licenseSubstitui CRM/UF ou licença estrangeira do próprio usuário
GET/v1/users/me/securityLê e-mail, verificação de e-mail e e-mail de recuperação
POST/v1/users/me/email-verificationSolicita o envio do e-mail de verificação do e-mail primário
PATCH/v1/users/me/recovery-emailSolicita a troca do e-mail de recuperação (envia confirmação)
DELETE/v1/users/me/recovery-emailRemove o e-mail de recuperação

Versão: v1

Swagger: Identity — User administration and profile · Rota (Dev): http://localhost:3000/v1/users/me

Lógica de decisão da rota mais complexa deste grupo (PATCH /users/me):

Permissões​

Rotas privadas ao próprio usuário: exigem apenas um access token OAuth válido (IdentityOAuthAccessTokenGuard). Não há permissão nomeada adicional — o escopo é sempre o subject do token, nunca um userId de terceiro.

RotaGuardsAcesso
GET/PATCH /users/me, PUT /users/me/professional-license, GET /users/me/security, POST /users/me/email-verification, PATCH/DELETE /users/me/recovery-emailIdentityOAuthAccessTokenGuardQualquer usuário autenticado, apenas sobre si mesmo

Headers​

HeaderObrigatórioDescrição
AuthorizationSimBearer <access_token>
Content-TypeSim (PATCH/PUT)application/json

Body​

PATCH /users/me — IdentityOwnUserProfileUpdateRequest:

json
{
"display_name": "Ana Beatriz Silva",
"phone_number": "+5511999999999",
"cpf_number": "12345678900",
"birth_date": "1990-05-20"
}
CampoTipoObrigatórioValidação
display_namestringNão1–160 caracteres
phone_numberstringNãostring, até 20 caracteres
cpf_numberstringNãostring, até 14 caracteres
birth_datestring (data ISO)Nãodata válida, não pode ser futura

Ao menos um campo deve ser enviado; corpo totalmente vazio é rejeitado com IDENTITY_USER_PROFILE_UPDATE_EMPTY.

PUT /users/me/professional-license — IdentityUserProfessionalLicenseRequest:

json
{ "medical_license": 123456, "medical_license_state": "SP", "foreign_medical_license": null }
CampoTipoObrigatórioValidação
medical_licenseint | nullNãointeiro ≥ 1; deve vir junto com medical_license_state
medical_license_statestring | nullNãoexatamente 2 letras; UF deve existir na tabela de estados
foreign_medical_licensestring | nullNãoaté 50 caracteres; não pode coexistir com medical_license

PATCH /users/me/recovery-email — IdentityRecoveryEmailRequest:

json
{ "recovery_email": "recuperacao@exemplo.com" }
CampoTipoObrigatórioValidação
recovery_emailstringSimformato de e-mail

DELETE /users/me/recovery-email não recebe corpo.

Response​

200 — GET /users/me (IdentityUserProfileResponse):

json
{
"id": "8f2a...-uuid",
"displayName": "Ana Beatriz Silva",
"email": "ana.silva@exemplo.com",
"birthDate": "1990-05-20",
"cpfNumber": "12345678900",
"foreignMedicalLicense": null,
"medicalLicense": 123456,
"medicalLicenseState": "SP",
"phoneNumber": "+5511999999999"
}

200 — PATCH /users/me, PUT .../professional-license (IdentityUserChangeResponse):

json
{ "message": "User profile updated." }

200 — GET /users/me/security (IdentityUserSecurityResponse):

json
{ "email": "ana.silva@exemplo.com", "email_verified": false, "recovery_email": null }

200 — POST /users/me/email-verification (IdentityEmailVerificationRequestResponse):

json
{ "sent": true, "already_verified": false }

200 — PATCH /users/me/recovery-email (IdentityRecoveryEmailChangeResponse):

json
{ "pendingConfirmation": true }

Erros​

Classe de erroerrorCodeStatusQuando ocorre
IdentityUserProfile (validação)IDENTITY_USER_PROFILE_INVALID400nome resultante vazio após normalização
IdentityUserProfileUpdate (validação)IDENTITY_USER_PROFILE_UPDATE_EMPTY400PATCH /users/me sem nenhum campo
IdentityUserBirthDate/IdentityUserDisplayName (validação)IDENTITY_USER_BIRTH_DATE_INVALID / IDENTITY_USER_DISPLAY_NAME_INVALID400valor de campo inválido
IdentityProfessionalLicense (validação)IDENTITY_PROFESSIONAL_LICENSE_INVALID400CRM sem UF (ou vice-versa), ou CRM + licença estrangeira juntos
IdentityUserNotFoundErrorIDENTITY_USER_NOT_FOUND404usuário do token não existe mais ou está inativo
ValidationError (verificação de e-mail)IDENTITY_EMAIL_VERIFICATION_USER_UNAVAILABLE400usuário ou credencial indisponível para o fluxo de verificação
—IDENTITY_INVALID_OAUTH_ACCESS_TOKEN401token ausente, inválido, expirado ou revogado

Regras de negócio​

IDRegraComportamento esperado
RN-01Atualização parcial e idempotentesó os campos enviados e efetivamente diferentes do valor salvo geram mudança
RN-02Nome não pode ficar vaziodisplay_name é normalizado (trim); vazio após normalização é rejeitado
RN-03CRM e UF são um parinformar medical_license sem medical_license_state (ou o contrário) é erro
RN-04CRM brasileiro e licença estrangeira são mutuamente exclusivosa mesma conta não pode ter os dois preenchidos ao mesmo tempo
RN-05UF do CRM é validada contra o catálogo de estadosUF inexistente no catálogo brasileiro é rejeitada
RN-06Trocar o e-mail de recuperação nunca é imediatoo valor só passa a valer quando o link enviado ao novo endereço é confirmado
RN-07Pedir verificação de e-mail já verificado não reenvia nadaresposta sent: false, already_verified: true

Compliance​

Órgão / normaExigênciaComo a rota atende
LGPDdireito de retificação (Art. 18, III)o próprio titular corrige nome, telefone, CPF e data de nascimento sem depender de terceiro
LGPDminimizaçãoresposta de GET /users/me/security não inclui senha nem segredos de MFA

Variáveis de ambiente​

VariávelUsoObrigatória
IDENTITY_EMAIL_VERIFICATION_URL (nome de config identity.authentication.emailVerificationUrl)base da URL enviada no e-mail de verificaçãoSim
Config identity.authentication.emailVerificationTtlInHoursvalidade do token de verificação de e-mailSim
Config identity.authentication.passwordRecoveryUrl / passwordRecoveryTtlInMinutesbase da URL e validade do link de confirmação do e-mail de recuperaçãoSim

Requisitos não funcionais​

RequisitoDefinição
IdempotênciaPATCH /users/me é idempotente para o mesmo payload (sem mudança, sem evento)
Rate limitNão identificado nestas rotas especificamente
AuditoriaSim — identity.user.profile_updated, identity.user.professional_license_changed, auth.email.verification_requested, auth.recovery_email.change_requested/cleared

Relacionado​

  • 🖥️ Tela: A confirmar — responsável: time de frontend; data: 24/09/2026. (levantamento cobriu apenas o backend)
  • 📂 Módulo: Usuário
  • 🔑 MFA (TOTP e SafeID) — resetar TOTP de um terceiro é feito em Gerenciar usuário