Skip to content

Autenticar com OAuth ​

O OAuth permite que uma aplicação chame a REST API em nome de um usuário que consente no navegador. O token fica vinculado a uma organização e a um projeto, e o usuário pode desmarcar escopos no momento do consentimento. O uso é cobrado dos créditos da organização exatamente como com uma chave API.

Para o caminho padrão com chave API, veja Autenticação.

Quando usar OAuth vs chave API ​

CasoUse
Uma app age em nome de um usuário logadoOAuth
Comunicação servidor a servidor sem humano no consentimentoChave API
Jobs de CI e integrações headlessChave API
Acesso delegado de curta duração a um projetoOAuth

O OAuth usa apenas clientes públicos. Não há client secret nem grant client_credentials.

Padrões ​

OAuth 2.1 com authorization code e PKCE (somente S256). O fluxo de autorização por dispositivo é usado apenas pela CLI da SipPulse. Leia as URLs dos endpoints nos metadados do servidor em vez de fixá-las no código:

  1. GET https://api.sippulse.ai/.well-known/oauth-protected-resource (RFC 9728) aponta para o servidor de autorização.
  2. Os metadados do servidor de autorização (RFC 8414) informam os endpoints de autorização, token e revogação.
  3. Passe o parâmetro resource (RFC 8707) com o valor https://api.sippulse.ai para a REST API.

Os escopos de inferência abaixo valem apenas para o resource da REST API. Clientes MCP não podem solicitá-los.

Registro de cliente com CIMD ​

Registre o cliente com um Client ID Metadata Document (CIMD). O client_id é uma URL HTTPS que serve um JSON descrevendo o cliente. O documento tem no máximo 16 KiB, e nenhum redirect é seguido. URIs de redirect de loopback podem usar qualquer porta. Não há registro dinâmico de clientes.

O documento contém client_id (a mesma URL), client_name, redirect_uris e token_endpoint_auth_method com o valor "none", além de opcionalmente application_type, grant_types e response_types.

json
{
  "client_id": "https://app.example.com/client.json",
  "client_name": "Example App",
  "redirect_uris": ["http://127.0.0.1:8090/callback"],
  "token_endpoint_auth_method": "none",
  "application_type": "native",
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"]
}

Fluxo de authorization code com PKCE ​

  1. Gere um code_verifier e seu code_challenge (S256). Guarde o verifier e envie apenas o challenge.
  2. Envie o usuário ao authorization_endpoint dos metadados com response_type=code, seu client_id, redirect_uri, code_challenge, code_challenge_method=S256, um valor state, resource=https://api.sippulse.ai e o scope pedido.
  3. O usuário faz login, escolhe uma organização e um projeto, e pode desmarcar escopos. O token fica vinculado a esse projeto.
  4. O callback para o seu redirect_uri traz code, state e iss. Confira state e iss antes de continuar.
  5. Troque o código no token_endpoint dos metadados:
bash
curl -X POST "$TOKEN_ENDPOINT" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=authorization_code" \
  --data-urlencode "code=$CODE" \
  --data-urlencode "redirect_uri=http://127.0.0.1:8090/callback" \
  --data-urlencode "client_id=https://app.example.com/client.json" \
  --data-urlencode "code_verifier=$CODE_VERIFIER"
  1. Chame a API com o access token apenas no header. Nunca coloque o token na URL:
bash
curl "https://api.sippulse.ai/v1/llms/models" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Solicite offline_access junto com os outros escopos para receber um refresh token.

Escopos para inferência de modelos ​

EscopoEndpoints liberados
spai:llm:executePOST /v1/llms/completion, POST /v1/chat/completions, GET /v1/llms/models, POST /v1/openai/chat/completions
spai:tts:executePOST /v1/tts/generate, POST /v1/audio/speech, GET /v1/tts/models, GET /v1/tts/voices, POST /v1/openai/audio/speech
spai:stt:executeEndpoints de fala para texto, agora também POST /v1/audio/transcriptions e POST /v1/openai/audio/transcriptions
spai:embeddings:executePOST /v1/openai/embeddings
spai:decisions:executePOST /v1/decisions, GET /v1/models
spai:models:readGET /v1/openai/models
spai:analytics:readGET /v1/analytics/catalog, POST /v1/analytics/query

spai:analytics:read também vale no recurso MCP, está incluído no login padrão da CLI e no login somente leitura, e nunca cobra. Sessões autorizadas antes do escopo existir precisam entrar de novo para ganhá-lo. Veja Análises de Uso.

Outros escopos existentes cobrem agentes (spai:agents:read|write|execute), secrets (spai:secrets:read|write), canais (spai:channels:read|write) e threads (spai:threads:read|write). Rotas não listadas para tokens OAuth respondem 403.

Usando um access token com o SDK da OpenAI ​

Passe o access token como chave API ou credencial bearer. O token expira após 1 hora, então a aplicação precisa renová-lo antes do vencimento.

python
from openai import OpenAI

client = OpenAI(
    api_key=access_token,  # access token OAuth, renovado antes do vencimento de 1h
    base_url="https://api.sippulse.ai/v1/openai",
)

Duração e renovação dos tokens ​

  • Access tokens duram 1 hora.
  • Refresh tokens exigem o escopo offline_access. Eles rotacionam a cada uso, com janela deslizante de 30 dias e limite absoluto de 90 dias.
  • Reutilizar um refresh token antigo revoga toda a concessão, e a app precisa levar o usuário ao consentimento de novo.

Revogação ​

  • Faça POST do token no endpoint de revogação dos metadados do servidor, ou
  • peça ao usuário para revogar a app em Configurações > Acessos OAuth (veja Acessos OAuth).

CLI ​

spai auth login mantém seus escopos padrão. Comandos de inferência exigem escopos explícitos: --scope <llm|tts|embeddings|decisions> é repetível e não pode ser combinado com --read-only.

sh
spai auth login --scope llm --scope tts
spai llm complete "Resuma esta chamada" --model MODEL
spai tts synthesize "Olá" --model MODEL --voice VOICE --output ola.mp3
spai embeddings create "Um texto" --model MODEL
spai decisions ask '{"question": "..."}'

spai llm models lista modelos LLM; spai llm complete [prompt] não usa streaming, lê stdin quando o prompt é omitido e aceita --model, --system, --temperature e --max-tokens. spai tts voices aceita --model; spai tts synthesize [text] exige --model, --voice e --output FILE. spai embeddings create [text] aceita --model. spai decisions ask [request] aceita um argumento JSON ou stdin. Um comando cujo escopo não foi concedido falha antes de qualquer requisição com a correção exata, por exemplo This command needs spai:llm:execute. Run: spai auth login --scope llm; com uma chave API não há verificação local. Veja CLI.

Limites ​

  • Tokens OAuth funcionam apenas nas rotas liberadas pelos seus escopos. Qualquer outra responde 403.
  • Escopos de inferência são só da REST API; clientes MCP não podem solicitá-los.
  • Envie o token apenas como header Authorization: Bearer <token>, nunca na URL.
  • Integrações sem humano no consentimento continuam usando chaves API.