Gerenciar, revogar e boas práticas
Como remover vínculos, revogar tokens, tratar os erros do fluxo OAuth, respeitar rate limits e proteger sua integração.
Esta página é o guia de operação e segurança da sua integração: como você (parceiro) e o usuário revogam acessos, o que significa cada erro do fluxo OAuth, como lidar com rate limits e a checklist de boas práticas.
Gerenciar contas vinculadas (Portal do Dev)
No Portal do Dev (dentro do app, em https://app.orbitsender.com), a aba Contas Vinculadas mostra quais contas autorizaram cada um dos seus apps.
A partir dessa tela você pode remover o vínculo de uma conta. A remoção é imediata:
- revoga a autorização do usuário para aquele app;
- invalida na hora os tokens (access e refresh) daquela conta.
Revogação é instantânea
Ao remover um vínculo, os tokens deixam de funcionar imediatamente. Qualquer chamada seguinte com aquele access_token retorna erro de autenticação, e o refresh_token da família também para de valer.
O usuário também controla o acesso
O acesso é sempre do usuário. No app, em Apps Conectados, o próprio usuário pode desconectar o seu app quando quiser — sem passar por você.
Revogar de qualquer lado (você pelo Portal do Dev, ou o usuário em Apps Conectados) mata os tokens imediatamente. Depois disso, para voltar a operar em nome daquele usuário é preciso passar de novo pela tela de consentimento (/authorize).
Você também pode revogar um token específico via endpoint padrão RFC 7009:
curl -X POST https://api.orbitsender.com/api/oauth/revoke \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "token=orb_rt_..."revoke sempre responde 200
O endpoint /api/oauth/revoke responde sempre 200, independentemente de o token existir ou já estar inválido. Não use a resposta para inferir a validade de um token.
Erros do fluxo OAuth
Os erros seguem a RFC 6749 no campo error. No /authorize, o erro pode voltar como query param no redirect_uri ({redirect_uri}?error=...&state=...); no /token, vem no corpo JSON da resposta.
error | Quando acontece | O que fazer |
|---|---|---|
invalid_request | Parâmetro ausente ou malformado. | Revise os parâmetros obrigatórios (response_type, client_id, redirect_uri, code_challenge, etc.). |
unauthorized_client | App inexistente ou ainda não aprovado. | Confirme o client_id e se o app está com status approved (Criar app). |
invalid_scope | Scope solicitado não foi aprovado. | Peça apenas scopes aprovados para o app (Scopes). |
invalid_client | Falha na validação do client_secret. | Verifique o secret do app confidential; rotacione no portal se necessário. |
invalid_grant | code/refresh_token inválido, expirado, já usado, ou PKCE inválido. | Reinicie o fluxo de autorização; garanta o code_verifier correto e não reutilize codes/refresh. |
unsupported_grant_type | grant_type não suportado. | Use authorization_code ou refresh_token. |
invalid_account | Conta sem tenant tentou consentir. | O usuário precisa de uma conta com tenant ativo para autorizar. |
access_denied | O usuário recusou o consentimento na tela /authorize. | Volta no redirect como {redirect_uri}?error=access_denied&state=.... Trate como cancelamento normal — sem retry automático. |
Reuse de refresh token revoga a família
O refresh_token é rotativo: cada uso invalida o anterior. Reapresentar um refresh já usado é tratado como detecção de reuse e revoga a família inteira de tokens. Sempre substitua o refresh guardado pelo novo retornado a cada troca. Veja Gerar token.
Rate limits
Há limites por app tanto nos endpoints de OAuth quanto na API externa. Ao estourar um limite, a API responde HTTP 429 com corpo { "success": false, "error": "rate_limited" }, o header Retry-After (em segundos até liberar) e os headers RateLimit-Limit, RateLimit-Remaining e RateLimit-Reset (limite, restante e segundos até a janela resetar).
| Grupo de endpoints | Limite | Janela | Bucket (chave do limite) |
|---|---|---|---|
POST /api/oauth/token | 30 req | 60 s | por client_id |
POST /api/oauth/revoke | 30 req | 60 s | por IP (o corpo do revoke não tem client_id) |
GET /api/oauth/authorize (consentimento) | 60 req | 60 s | por IP |
/api/external/* (todas as chamadas de recurso) | 300 req | 60 s | por credencial (api-key ou access token) |
Trate o 429 com backoff (idealmente exponencial) e re-tentativas espaçadas. Não faça retry imediato em loop.
async function chamarComBackoff(fn: () => Promise<Response>, tentativas = 4) {
let espera = 1000; // ms
for (let i = 0; i < tentativas; i++) {
const res = await fn();
if (res.status !== 429) return res;
await new Promise((r) => setTimeout(r, espera));
espera *= 2; // backoff exponencial
}
throw new Error("Rate limit persistente (429)");
}Limites do portal
No Portal do Dev há também limites operacionais: no máximo 5 apps por parceiro e no máximo 2 envios para revisão por dia.
Boas práticas de segurança
- Guarde o
client_secretsó no servidor. Nunca exponha em app público, mobile ou front-end. App public não tem secret — use PKCE. - Use
statecomo anti-CSRF em toda ida ao/authorizee valide-o no retorno (compare com o valor que você gerou). redirect_urisempre em HTTPS e com exact-match a uma URI registrada no app — sem barra, porta ou query a mais.- Use PKCE (S256), obrigatório para apps public e recomendado sempre. Veja PKCE.
- Rotacione e armazene o
refresh_tokencom segurança e sempre troque pelo novo retornado a cada refresh (o anterior deixa de valer). - Trate
401(access token expirado) fazendo refresh do token; trate403(scope faltando) revisando os scopes consentidos. - Peça o mínimo de scopes. Menos permissão = revisão mais rápida e menor superfície de risco. Consulte a referência de scopes.