OrbitSenderDocs

PKCE (S256)

Como gerar o code_verifier e o code_challenge (SHA-256/BASE64URL) e onde enviá-los no fluxo OAuth do OrbitSender.

O PKCE (Proof Key for Code Exchange) é uma extensão do OAuth 2.0 que protege o código de autorização (orb_ac_...) contra interceptação. No OrbitSender usamos exclusivamente o método S256.

Por que o PKCE existe

No fluxo Authorization Code, o /authorize devolve um código temporário na URL de redirecionamento. Se esse código for interceptado, um atacante poderia tentar trocá-lo por um token de acesso.

O PKCE resolve isso amarrando o código a um segredo efêmero que só o seu app conhece:

  • Antes de iniciar, o app gera um code_verifier (segredo aleatório) e dele deriva um code_challenge.
  • O code_challenge viaja no /authorize; o code_verifier fica guardado no app.
  • Na troca no /token, o app envia o code_verifier original. O OrbitSender recalcula o challenge e só libera o token se bater.

Obrigatório para apps public; recomendado para confidential

Apps do tipo public (SEM client_secret) precisam usar PKCE — é a única proteção do código. Apps confidential (com client_secret) devem usar PKCE também, como camada extra além do secret.

Como o par é construído

ElementoRegra
code_verifierString aleatória de 43 a 128 caracteres. Gerada e guardada pelo app.
code_challengeBASE64URL( SHA256(code_verifier) )
code_challenge_methodSempre S256 (único método aceito).

O BASE64URL é o Base64 "URL-safe" sem padding (sem os = no final, com - e _ no lugar de + e /).

Gerando o par no seu código

Node.js

import crypto from "node:crypto";

// 1) code_verifier: aleatório, URL-safe, dentro de 43–128 chars
const codeVerifier = crypto.randomBytes(32).toString("base64url");

// 2) code_challenge = BASE64URL( SHA256(code_verifier) )
const codeChallenge = crypto
  .createHash("sha256")
  .update(codeVerifier)
  .digest("base64url");

console.log({ codeVerifier, codeChallenge, codeChallengeMethod: "S256" });

Python

import secrets
import hashlib
import base64

# 1) code_verifier: aleatório, URL-safe, dentro de 43–128 chars
code_verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).rstrip(b"=").decode()

# 2) code_challenge = BASE64URL( SHA256(code_verifier) )
digest = hashlib.sha256(code_verifier.encode()).digest()
code_challenge = base64.urlsafe_b64encode(digest).rstrip(b"=").decode()

print({"code_verifier": code_verifier, "code_challenge": code_challenge, "method": "S256"})

Guarde o code_verifier

Você precisará do mesmo code_verifier na etapa de troca no /token. Gere-o e associe ao state da requisição (por exemplo, na sessão do usuário) para recuperá-lo quando o callback voltar.

Onde cada valor é enviado

No /authorize vão o challenge e o método

Ao mandar o usuário para a tela de consentimento, inclua nos query params:

GET https://app.orbitsender.com/oauth/authorize?response_type=code
  &client_id=cli_abc123
  &redirect_uri=https://seuapp.com/callback
  &scope=statistics:read%20campaigns:read
  &state=xyz123
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256

Envie apenas code_challenge e code_challenge_method=S256. Nunca envie o code_verifier aqui.

No /token vai o code_verifier

Na troca do código pelo token, envie o code_verifier correspondente no corpo form-urlencoded:

curl -X POST https://api.orbitsender.com/api/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=cli_abc123" \
  -d "code=orb_ac_..." \
  -d "redirect_uri=https://seuapp.com/callback" \
  -d "code_verifier=SEU_CODE_VERIFIER_ORIGINAL"

O OrbitSender recalcula BASE64URL(SHA256(code_verifier)) e compara com o code_challenge recebido no /authorize. Se não bater, a resposta é o erro invalid_grant.

Um par por fluxo

Gere um code_verifier/code_challenge novo a cada início de fluxo. O código (orb_ac_...) é de uso único e expira em 60 segundos.

Próximos passos

Nesta página