Autenticação

Todos os endpoints autenticados do sistema usam JWT bearer token. O login retorna o token tanto no corpo da resposta quanto em um cookie httpOnly (pacs_access_token), que é injetado automaticamente pelo frontend via Axios. Claims do JWT: tenant_id, unit_id, is_super_admin, is_tenant_admin — usados pelos scopes Eloquent para isolar dados multi-tenant. TTL padrão: 60 minutos. Refresh window: 14 dias.

POST /api/login

Autentica um usuário e retorna um JWT. Auth: público Rate limit: 10 requisições por minuto (por IP)

Request body

email
string
required
Email do usuário.
password
string
required
Senha do usuário.

Response 200

{
  "token_type": "bearer",
  "expires_in": 3600,
  "user": {
    "id": "uuid",
    "email": "joao@clinica.com",
    "name": "Dr. João",
    "tenant_id": "uuid | null",
    "unit_id": "uuid | null",
    "is_super_admin": false,
    "is_tenant_admin": false
  }
}
O JWT também é retornado em cookie httpOnly chamado pacs_access_token, com lifetime igual ao expires_in.

Erros

StatusSituaçãoBody
401Credenciais inválidas{"error": "Credenciais inválidas."}
403Conta ou tenant desativado{"error": "Conta desativada."}
422Validação falhou{"message": "...", "errors": {...}}

Notas

  • O login verifica user.is_active E user.tenant.is_active — se qualquer um for false, o usuário é deslogado e recebe 403
  • Campos sensíveis (password, remember_token, signature) são omitidos do objeto user retornado

POST /api/logout

Invalida o token JWT atual (adiciona à blacklist) e remove o cookie. Auth: auth:api

Request

Apenas o header Authorization: Bearer <token>. Sem body.

Response 200

{
  "message": "Logout realizado com sucesso."
}

Erros

StatusSituaçãoBody
401Token inválido, expirado ou ausente{"message": "Unauthenticated."}

Notas

  • O token fica blacklisted após logout (JWT_BLACKLIST_ENABLED=true) e não pode ser reutilizado
  • O cookie pacs_access_token é removido do response

POST /api/refresh

Emite um novo JWT a partir de um token ainda dentro da refresh window. Auth: auth:api Rate limit: 30 requisições por minuto

Request

Apenas o header Authorization: Bearer <token>. Sem body.

Response 200

{
  "token_type": "bearer",
  "expires_in": 3600,
  "user": {
    "id": "uuid",
    "email": "joao@clinica.com",
    "name": "Dr. João",
    "tenant_id": "uuid | null",
    "unit_id": "uuid | null",
    "is_super_admin": false,
    "is_tenant_admin": false
  }
}

Erros

StatusSituaçãoBody
401Refresh window expirada{"message": "Token Refresh window has expired"}
401Token já estava blacklisted{"message": "The token has been blacklisted"}

Notas

  • O token antigo é invalidado (blacklist) após a emissão do novo
  • Refresh window padrão: 14 dias (JWT_REFRESH_TTL=20160 minutos)
  • O cookie pacs_access_token é atualizado com o novo token

GET /api/me

Retorna os dados do usuário autenticado, incluindo tenant e unit relacionados. Auth: auth:api

Request

Apenas o header Authorization: Bearer <token>. Sem body.

Response 200

{
  "id": "uuid",
  "email": "joao@clinica.com",
  "name": "Dr. João",
  "tenant_id": "uuid | null",
  "unit_id": "uuid | null",
  "is_super_admin": false,
  "is_tenant_admin": false,
  "tenant": {
    "id": "uuid",
    "name": "Clínica ABC"
  },
  "unit": {
    "id": "uuid",
    "name": "Unidade Centro"
  }
}
tenant e unit podem ser null se o usuário não estiver vinculado (ex.: super admin sem tenant).

Erros

StatusSituaçãoBody
401Token inválido ou expirado{"message": "Unauthenticated."}