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
| Caso | Use |
|---|---|
| Uma app age em nome de um usuário logado | OAuth |
| Comunicação servidor a servidor sem humano no consentimento | Chave API |
| Jobs de CI e integrações headless | Chave API |
| Acesso delegado de curta duração a um projeto | OAuth |
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:
GET https://api.sippulse.ai/.well-known/oauth-protected-resource(RFC 9728) aponta para o servidor de autorização.- Os metadados do servidor de autorização (RFC 8414) informam os endpoints de autorização, token e revogação.
- Passe o parâmetro
resource(RFC 8707) com o valorhttps://api.sippulse.aipara 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.
{
"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
- Gere um
code_verifiere seucode_challenge(S256). Guarde o verifier e envie apenas o challenge. - Envie o usuário ao
authorization_endpointdos metadados comresponse_type=code, seuclient_id,redirect_uri,code_challenge,code_challenge_method=S256, um valorstate,resource=https://api.sippulse.aie oscopepedido. - O usuário faz login, escolhe uma organização e um projeto, e pode desmarcar escopos. O token fica vinculado a esse projeto.
- O callback para o seu
redirect_uritrazcode,stateeiss. Confirastateeissantes de continuar. - Troque o código no
token_endpointdos metadados:
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"- Chame a API com o access token apenas no header. Nunca coloque o token na URL:
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
| Escopo | Endpoints liberados |
|---|---|
spai:llm:execute | POST /v1/llms/completion, POST /v1/chat/completions, GET /v1/llms/models, POST /v1/openai/chat/completions |
spai:tts:execute | POST /v1/tts/generate, POST /v1/audio/speech, GET /v1/tts/models, GET /v1/tts/voices, POST /v1/openai/audio/speech |
spai:stt:execute | Endpoints de fala para texto, agora também POST /v1/audio/transcriptions e POST /v1/openai/audio/transcriptions |
spai:embeddings:execute | POST /v1/openai/embeddings |
spai:decisions:execute | POST /v1/decisions, GET /v1/models |
spai:models:read | GET /v1/openai/models |
spai:analytics:read | GET /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.
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
POSTdo 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.
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.
