simpla.fydocs
Admin API

Autenticação

OAuth2 Google (RFC 7591) para devs e Bearer AgentCredential para agentes server-to-server na Admin API.

Autenticação

A Admin API aceita dois mecanismos de autenticação, sempre normalizados para a mesma abstração de Principal com scopes[] antes do dispatch das tools.

Para coding agents server-to-server, prefira o MCP server irmão em https://mcp-admin.simplafy.com.br/mcp. O REST descrito aqui é primariamente consumido pelo frontend admin; alguns endpoints administrativos exigem OAuth dance que não compensa para agentes.

Visão geral

Toda requisição autenticada é resolvida em um Principal, que carrega:

  • Identidade (userEmail para humanos, agentId para agentes)
  • Lista de scopes efetivos
  • Origem do binding (OAuth user, AgentCredential ou floor default)

O gate de autorização é sempre o mesmo helper hasScope(principal.scopes, requiredScope), independente de como o Principal foi obtido. Isso significa que adicionar um scope a um agente ou a um usuário tem efeito idêntico.

MétodoQuem usaHeaderStorage
OAuth2 GoogleDevs e operadores no console webCookie de sessão Next-AuthJWT assinado
Bearer AgentCredentialCoding agents, CI, Pulse runsAuthorization: Bearer ...AgentCredential.keyHash (bcrypt)

OAuth2 Google para devs

O console web usa Next-Auth com provider Google. O sign-in está restrito ao tenant simplafy.com.br.

Início do fluxo. O frontend chama GET /api/auth/signin/google, que redireciona ao Google OAuth.

Callback do Google. Google chama /api/auth/callback/google?code=.... O handler troca o code por tokens e roda o callback signIn.

Validação de tenant. Apenas e-mails que terminam em @simplafy.com.br são aceitos. Em NODE_ENV=development existe bypass via env var DEV_BYPASS_EMAIL.

Upsert do usuário. O registro em User é criado/atualizado com email, name, image e role: 'admin'.

Emissão do JWT. O token inclui email, id e role do banco. Sessões subsequentes carregam esses campos via callback session.

Resolução de scopes para usuários OAuth:

// pseudocódigo do dispatcher
const binding = await db.userScopeBinding.findUnique({
  where: { userEmail: principal.userEmail },
})

principal.scopes = binding?.scopes ?? DEFAULT_SCOPES_FLOOR

Quando o usuário não tem UserScopeBinding, o sistema aplica o DEFAULT_SCOPES_FLOOR (read-only). Escritas exigem binding explícito feito por um admin.

DEFAULT_SCOPES_FLOOR =
  admin:pm:read,
  admin:bi:read,
  admin:kb:read,
  admin:openapi:read,
  admin:hub-langfuse:read,
  admin:lab:read

O JWT é validado no edge runtime. Não importe o módulo Node crypto em handlers de auth — use os helpers em @/lib/auth/timing-safe. O segredo MCP_JWT_SECRET é obrigatório em produção; sem ele o MCP server crasha no boot.

Bearer AgentCredential para agentes

Agentes server-to-server (Codex CI, Pulse, jobs internos) não passam pelo fluxo OAuth. Eles enviam um token estático no header Authorization.

curl https://admin.simplafy.com.br/api/v1/pm/stories?module=admin \
  -H "Authorization: Bearer ${AGENT_BEARER_TOKEN}"

O token recebido é comparado via bcrypt contra AgentCredential.keyHash. Em hit, o dispatcher monta o Principal com:

  • agentId — chave estável do agente
  • scopes[] — scopes vindos diretamente de AgentCredential.scopes
  • rateLimit — limites por minuto/dia, aplicados antes do dispatch

A verificação acontece em apps/mcp-server/src/lib/scopes.ts via hasScope.

AgentCredential.expiresAt é opcional. null significa que o token não expira — use com responsabilidade e prefira rotação periódica documentada em runbook.

Pedindo um token novo:

Abra uma issue no repo Simplafy-tec/simplafy-admin com label agent-credential, descrevendo agente, scopes necessários e expiração desejada.

O time de plataforma gera a credencial no console admin e devolve o token via canal seguro (Infisical ou 1Password vault correspondente).

Armazene o token apenas em secret manager. Nunca commite em repositórios.

Scopes

Scopes seguem o formato:

<domain>:<resource>:<action>[:<qualifier>]

Exemplos canônicos:

admin:pm:read            list/get stories, epics, themes
admin:pm:write           create/update/delete em PM
admin:bi:read            BI dashboards
admin:kb:read            KB references
admin:kb:write           criar/editar references
admin:lab:read           lab scenarios e runs
admin:lab:write          executar scenarios
admin:openapi:read       registry legacy (deprecado, ADR-0006)
admin:openapi:write      registry legacy (deprecado, ADR-0006)
proxy:*                  todas proxied tools (full profile)

Wildcard de sufixo :* é suportado. Por exemplo, admin:db:read:* libera leitura em todos os databases registrados.

Scopes legacy admin:openapi:* continuam funcionando, mas devem migrar para docs.* no proxy conforme ADR-0006. Novas integrações não devem depender deles.

Erros comuns

Em produção, o boot falha se MCP_JWT_SECRET não estiver configurado. Sintoma: container reinicia em loop sem aceitar tráfego. Confirme o secret no Infisical antes de promover deploys.

On this page