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 (
userEmailpara humanos,agentIdpara 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étodo | Quem usa | Header | Storage |
|---|---|---|---|
| OAuth2 Google | Devs e operadores no console web | Cookie de sessão Next-Auth | JWT assinado |
| Bearer AgentCredential | Coding agents, CI, Pulse runs | Authorization: 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_FLOORQuando 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:readO 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 agentescopes[]— scopes vindos diretamente deAgentCredential.scopesrateLimit— 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
401 Unauthorized
Token ausente ou inválido. Verifique o header Authorization: Bearer ... e, no caso de OAuth, se o cookie de sessão está presente e não expirou.
403 Forbidden — scope ausente
Principal autenticado, mas hasScope(principal.scopes, required) retornou false. Resposta inclui requiredScope no body para facilitar diagnóstico.
403 Forbidden — tenant inválido
OAuth sign-in com e-mail fora de @simplafy.com.br. Em dev, configure DEV_BYPASS_EMAIL no .env.local.
429 Too Many Requests
AgentCredential.rateLimit excedido. Header Retry-After indica quando reabrir o canal. Ajuste rate limit via plataforma se necessário.
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.
Admin API — overview
Visão geral do Simplafy Admin: console interno (PM Board, BI, Knowledge Base, Lab) com REST API e MCP server irmão para coding agents.
MCP usage
Conecte coding agents ao Simplafy Admin MCP server via Streamable HTTP, incluindo headers, payload JSON-RPC e configuração para Claude Code, Cursor e Codex.