Gerenciar sessão e consultar identidade — API
Cobre a checagem da sessão atual, a troca de conta ativa dentro de uma mesma sessão (contas com sessão no mesmo dispositivo) e a consulta de identidade no padrão OIDC UserInfo. Todas as rotas exigem um access token válido.
Lacuna confirmada: não existe mais uma rota de listagem de todas as sessões ativas do usuário (o antigo equivalente a "ver minhas sessões, com IP e aplicação de cada uma"). Um
greppelo repositório inteiro por um serviço de listagem de sessões não encontrou nada. Se sua integração depende disso, é uma funcionalidade que precisa ser (re)confirmada com o time de Identity.
Funcionamento
HEAD /sessions/current: só valida o access token; não tem corpo de resposta. Existe para o
front confirmar rapidamente se a sessão ainda está ativa (ex.: antes de renderizar uma tela que
depende de autenticação).
GET /sessions/switchable-accounts: lista as contas que têm uma sessão ativa no mesmo
dispositivo físico do usuário autenticado (mesmo deviceId) — não é uma tabela de "contas
vinculadas" por relação de organização, é literalmente "quais contas já estão logadas neste
aparelho".
POST /sessions/switch: troca a conta ativa dentro do mesmo dispositivo. Confirma que a conta
alvo tem uma sessão ativa nesse mesmo dispositivo e emite um novo authorization_code (mesmo
mecanismo de Autorizar aplicação) para a sessão da conta alvo — não é um
endpoint de "impersonar" administrativo, é a troca comum entre contas já logadas no aparelho.
GET /userinfo: lê o header Authorization e autentica o access token pelo mesmo caminho do
guard padrão; devolve os atributos mínimos do usuário — sub, email, email_verified, name.
Se o usuário do token não existir mais (desativado/excluído após o token ser emitido), a rota
recusa mesmo com um token tecnicamente válido.
Endpoints
| Método | Rota | Descrição |
|---|---|---|
| HEAD | /v1/sessions/current | Confirma que a sessão do access token está ativa (sem corpo) |
| GET | /v1/sessions/switchable-accounts | Lista contas com sessão ativa no mesmo dispositivo |
| POST | /v1/sessions/switch | Troca a conta ativa (emite authorization_code para outra conta) |
| GET | /v1/userinfo | Retorna a identidade do usuário autenticado (OIDC) |
Versão: v1
Swagger:
Rota (Dev): http://localhost:3000/v1/sessions/current, http://localhost:3000/v1/userinfo
Lógica de decisão das quatro rotas:
Permissões
| Rota | Guards | Acesso |
|---|---|---|
HEAD /sessions/current | IdentityOAuthAccessTokenGuard | Usuário autenticado |
GET /sessions/switchable-accounts | IdentityOAuthAccessTokenGuard | Usuário autenticado |
POST /sessions/switch | IdentityOAuthAccessTokenGuard | Usuário autenticado |
GET /userinfo | nenhum decorator de guard — autenticação feita dentro do use-case, mesmo efeito prático | Usuário autenticado (via header Authorization) |
Headers
| Header | Obrigatório | Descrição |
|---|---|---|
Authorization | Sim | Bearer <access_token> |
Path parameters
Nenhum.
Query parameters
Nenhum.
Body
POST /sessions/switch — IdentitySessionSwitchRequest:
json{"account_id": "8f2a...-uuid","client_id": "web-portal","code_challenge": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM","code_challenge_method": "S256","redirect_uri": "https://app.exemplo.com/callback","scope": "openid profile","state": "random-state","nonce": "random-nonce"}
| Campo | Tipo | Obrigatório | Validação |
|---|---|---|---|
account_id | string | Sim | @IsUUID — conta alvo da troca |
client_id | string | Sim | @IsUUID |
code_challenge | string | Sim | @Length(43, 128) |
code_challenge_method | string | Sim | @IsIn(['S256']) — só S256 (diferente do início do QR-code, que aceita qualquer valor) |
redirect_uri | string | Sim | @IsUrl({ require_tld: false }) |
scope | string | Não | @Length(1, 1024) (separado por espaço) |
state | string | Não | @Length(1, 512) |
nonce | string | Não | @Length(1, 255) |
HEAD /sessions/current, GET /sessions/switchable-accounts e GET /userinfo não recebem corpo.
Response
GET /sessions/switchable-accounts — 200:
json[{ "account_id": "8f2a...-uuid", "display_name": "Maria Souza", "email": ["maria@exemplo.com"] }]
POST /sessions/switch — 200:
json{ "code": "opaque-authorization-code", "redirect_uri": "https://app.exemplo.com/callback", "state": "random-state" }
GET /userinfo — 200:
json{ "sub": "8f2a...-uuid", "email": "usuario@exemplo.com", "email_verified": true, "name": "Maria Souza" }
Erros
| Rota | Classe de erro | errorCode | Status | Quando ocorre |
|---|---|---|---|---|
| todas | IdentityInvalidOAuthAccessTokenError | IDENTITY_INVALID_OAUTH_ACCESS_TOKEN | 401 | access token ausente/inválido/expirado; em userinfo, também se o usuário do token não existe mais |
switchable-accounts, switch | IdentitySessionSwitchDeniedError | IDENTITY_SESSION_SWITCH_DENIED | 403 | a sessão autenticada não tem deviceId, ou a conta alvo não tem sessão ativa no mesmo dispositivo |
Regras de negócio
| ID | Regra | Comportamento |
|---|---|---|
| RN-01 | Trocar de conta exige sessão ativa da conta alvo no mesmo dispositivo | não é uma relação de vínculo entre contas — é literalmente checar se o dispositivo já tem outra sessão logada |
| RN-02 | switch reaproveita a emissão de authorization_code | mesmo mecanismo OAuth do authorize — a resposta é um código para trocar em /oauth/token, não uma sessão pronta |
| RN-03 | userinfo só popula 4 campos | sub, email, email_verified, name — mesmo que o DTO declare outros campos OIDC opcionais, eles não são preenchidos |
| RN-04 | HEAD /sessions/current não tem corpo por design | usado só para checar "ainda estou logado?" |
Compliance
| Órgão / norma | Exigência | Como a rota atende |
|---|---|---|
| LGPD | minimização de dados de identidade | userinfo devolve só os 4 campos mínimos, não o perfil completo |
| HIPAA | controle de troca de conta ativa | troca exige sessão ativa da conta alvo no mesmo dispositivo, não é livre |
| ANVISA (indireto) | identidade do usuário autenticado verificável | userinfo sempre reflete o dono real do token, revalidado a cada chamada |
Variáveis de ambiente
Nenhuma variável de ambiente específica destas quatro rotas foi identificada neste levantamento.
Tempo médio de resposta
A confirmar — responsável: time de Identity; data: 24/09/2026. Sem medição publicada.
Requisitos não funcionais
| Requisito | Definição |
|---|---|
| Idempotência | HEAD/GET são idempotentes por natureza; POST /switch gera sempre um novo authorization_code |
| Rate limit | Não identificado @Throttle específico nestas rotas neste levantamento |
| Cache | Não |
| Auditoria | Não identificado evento de auditoria dedicado à troca de conta ou ao userinfo neste levantamento |
Divergências e lacunas confirmadas
- Não existe mais listagem de sessões ativas (
GET /sessions/users/{userId}de uma versão antiga, com IP/aplicação/dispositivo de cada sessão). Confirmar com o time de Identity se isso é uma remoção deliberada ou uma lacuna a repor. - Não existem specs unitários dedicados para
switch-identity-session.service,list-identity-switchable-accounts.serviceouget-identity-oauth-user-info.service. - Existe uma capacidade separada de elevação de sessão (step-up), em
identity/privileged-access(POST /identity/sessions/:sessionId/step-up-challengeseGET /identity/privileged-capabilities), que reautentica com TOTP para liberar ações sensíveis administrativas por um tempo limitado. Não é uma rota de sessão comum (não revoga nem cria sessões) e não tem página própria nesta documentação — pendência de documentação, fora do escopo desta página.
Relacionado
- 📂 Módulo: Authentication
- 🔑 Login
- 🔑 Encerrar sessão
- 🔁 Autorizar aplicação (OAuth) — mesmo mecanismo de emissão de código usado pela troca de conta