Autenticação e perfis
Existem quatro perfis de principal, e eles nunca se misturam — nem no cookie, nem no JWT, nem na validação.
principal_type | Quem | Login | Claims extras |
|---|---|---|---|
management | Gestor/admin/auditor de organização | E-mail + senha | — |
user | Participante | Telefone + OTP (sem senha) | — |
operator, operator_type=pdv | PDV | Usuário + senha (conta provisionada pela gestão) | operator_account_id, event_id |
operator, operator_type=cashier | Caixa | Usuário + senha (conta provisionada pela gestão) | operator_account_id, event_id |
Cookies isolados por perfil
Todo login (exceto os que ainda não emitem cookie — ver cada seção de perfil) seta três cookies com nomes próprios daquele perfil:
wallet_management_access_token wallet_management_refresh_token wallet_management_csrf_token
wallet_user_access_token wallet_user_refresh_token wallet_user_csrf_token
wallet_pdv_access_token wallet_pdv_refresh_token wallet_pdv_csrf_token
wallet_cashier_access_token wallet_cashier_refresh_token wallet_cashier_csrf_token
Os dois primeiros de cada trinca são HttpOnly. O terceiro (CSRF) não é —
ele existe justamente para que o JavaScript da mesma origem leia o valor e
devolva no header X-CSRF-Token em requisições que mudam estado
(double-submit cookie pattern). Cliente que usa Bearer token no header
Authorization pode ignorar os três cookies completamente.
Por que a rota decide o perfil esperado, não o cookie que veio
A wallet-edge mantém uma função (authenticationProfileForPath) que mapeia
o caminho da URL para o perfil esperado — não importa qual cookie o
navegador mandou. Isso é o que impede um token de gestão de funcionar contra
GET /v1/auth/wallet/me, por exemplo: a rota exige perfil wallet, o token
é management, a Edge rejeita com 401 AUTHENTICATION_PROFILE_MISMATCH
antes mesmo de chamar a API de origem. A própria API de origem valida de
novo (nunca confia só na validação da Edge).
/v1/me compartilhado foi aposentado
Até pouco tempo, GET/PATCH /v1/me atendia gestor e participante ao mesmo
tempo. Isso foi separado em dois endpoints isolados — cada um com seu
próprio guard, que só aceita o principal_type certo:
| Antes | Agora |
|---|---|
GET/PATCH /v1/me | GET/PATCH /v1/auth/management/me (só gestão) |
| — (não existia) | GET/PATCH /v1/auth/wallet/me (só participante) |
PDV e caixa não têm (e não está planejado ter por enquanto) um endpoint
.../me equivalente. É decisão deliberada: essas contas não têm um "perfil
pessoal" em app.user_profiles — o que o app de PDV/caixa precisa
(identificador, tipo, evento) já vem nas claims do próprio JWT.