Chaves de API e OAuth resolvem problemas diferentes, e a escolha entre elas começa por uma única pergunta: existe um terceiro no esquema?
Se o seu servidor chama a API de outra pessoa em nome próprio, você quer uma chave. Se o aplicativo de outra pessoa chama a sua API em nome do seu usuário, você quer OAuth. Sem um terceiro envolvido, OAuth acrescenta cerimônia sem acrescentar segurança.
A seguir: em que de fato diferem, o que mudou no OAuth nos últimos anos e uma propriedade das chaves de API sobre a qual quase ninguém escreve, apesar de ser ela que define como você vai conviver com elas em produção.
A chave de API: uma cadeia que diz "este programa pode"
Uma chave é uma cadeia longa e aleatória que você coloca num cabeçalho da requisição:
X-Api-Key: lix_live_9f2c...
O servidor encontra a chave, descobre a qual conta ela pertence e deixa a requisição passar. O mecanismo é só isso.
As propriedades que decorrem daí:
- a chave não expira sozinha. Ela vive até que alguém a revogue;
- a chave identifica um programa, não uma pessoa. Quem do time fez a chamada costuma ser invisível;
- a chave concede tudo o que a conta pode fazer, a menos que você limite as permissões à parte;
- a chave é o único segredo. Se vazou, o acesso vazou — não há etapas intermediárias.
OAuth: um protocolo sobre consentimento
O OAuth 2.0 (RFC 6749) responde a outra pergunta. Ele tem quatro participantes: o dono dos dados, o aplicativo que os quer, um servidor de autorização e o servidor que guarda os dados.
O percurso é mais ou menos assim. O aplicativo manda a pessoa para a página do próprio serviço. Ela vê quem está pedindo e para quê, e concorda. O aplicativo recebe um código, troca por um token de acesso e chama a API com ele. O token dura pouco — minutos ou horas; quando expira, o aplicativo troca um token de atualização por um novo.
O que isso entrega e uma chave não consegue entregar por princípio:
- a senha do usuário nunca chega ao aplicativo. É aí que está o sentido todo;
- as permissões se dividem em escopos. "Ler links" e "apagar links" são concessões distintas;
- o consentimento é visível e revogável. O usuário vê a lista de aplicativos conectados e pode desconectar um sem mexer nos demais;
- os tokens expiram sozinhos. Um token de acesso roubado não serve para nada uma hora depois.
O preço é a complexidade: um servidor de autorização, cadastro de aplicativos, uma tela de consentimento, guardar e rotacionar tokens de atualização e tratar a expiração a cada chamada.
Comparação pelos eixos que realmente decidem
| Chave de API | OAuth 2.0 | |
|---|---|---|
| Quem ela atesta | o programa | o usuário em nome de quem o programa age |
| Tempo de vida | indefinido | token de acesso: minutos a horas |
| Como o acesso termina | revogar a chave | revogar o consentimento ou o token |
| Alcance das permissões | em geral a conta inteira | escopos por ação |
| Segredo em poder do terceiro | a própria chave | apenas tokens, nunca a senha |
| Esforço de integração | um cabeçalho | um servidor de autorização e o ciclo completo |
| Onde encaixa | servidor a servidor, scripts, integrações internas | apps públicos, marketplaces, "Entrar com…" |
A regra de escolha
A pergunta não é qual é mais seguro no abstrato, e sim quem delega acesso a quem.
Seu servidor → API alheia, conta sua
→ chave de API
App alheio → sua API, conta do seu usuário
→ OAuth
Tarefa agendada, CI, integração de backend
→ chave de API
O usuário precisa ver e revogar o acesso por aplicativo
→ OAuth
Receber postbacks é o caso de manual para uma chave. Quando o seu servidor avisa o nosso de que um pedido foi pago, não há usuário nenhum nessa troca, não há quem consinta nem onde colocar uma tela de consentimento. O mesmo vale para os webhooks no sentido contrário.
O que mudou no OAuth enquanto você não olhava
Metade dos artigos sobre o tema descreve o OAuth de 2015. De lá para cá ele estreitou bastante.
Em janeiro de 2025 a IETF publicou a RFC 9700, Best Current Practice for OAuth 2.0 Security. O documento reúne anos de experiência com ataques reais e declara formalmente obsoletos dois fluxos que antes eram tidos como aceitáveis:
- o implicit grant — aquele que devolvia o token direto na barra de endereços;
- resource owner password credentials — em que o aplicativo pedia usuário e senha diretamente. Exatamente aquilo que o OAuth veio evitar.
Ao mesmo tempo, o PKCE passou a ser obrigatório para todos os tipos de cliente, inclusive os de servidor, e não só para os móveis como antes.
Vale saber à parte: o OAuth 2.1 continua sendo um rascunho, não uma RFC publicada. Ele junta essas mesmas mudanças num único documento — PKCE obrigatório, comparação exata da redirect URI, sem implicit nem password grant, sem tokens na query string. Citá-lo como padrão vigente é prematuro.
Conclusão prática: se um tutorial de OAuth recomenda o fluxo implícito, o tutorial está desatualizado.
O ponto fraco das chaves de que pouco se fala
Uma chave não expira. Isso faz da revogação a sua única alavanca. E aqui aparece o incômodo: a revogação costuma não ser instantânea.
Verificar a chave a cada requisição significa ir ao banco de dados. Em qualquer API com tráfego real esse resultado vai para cache. No nosso caso, a correspondência entre chave e conta fica cinco minutos em cache. Portanto, entre clicar em "revogar" e o acesso realmente parar passam até cinco minutos, durante os quais uma chave comprometida continua funcionando.
Não é descuido, é uma troca: sem cache, cada requisição bate no banco. Quase toda API baseada em chaves faz um acordo parecido, só que não se costuma dizer isso em voz alta. Importa por dois motivos. Primeiro, num vazamento real revogar a chave é a primeira ação, não a última: depois convém conferir o que aconteceu nesses minutos. Segundo, é exatamente o problema que os tokens de vida curta do OAuth atacam pelo outro lado — eles expiram sozinhos, sem banco de dados envolvido.
Conviver com chaves sem se machucar
Se as chaves bastam — e na maioria das integrações bastam —, o mínimo é este:
- Guarde só o hash. O servidor compara o hash da chave apresentada com o armazenado; a cadeia original é mostrada uma única vez, na criação. As nossas são conferidas por SHA-256.
- Dê um prefixo à chave. Uma cadeia no formato
lix_live_...é reconhecida pelos varredores de segredos em repositórios e em pipelines de log. - Uma chave por integração. Assim revogar uma não derruba as outras, e o histórico mostra exatamente o que foi comprometido.
- Nunca coloque a chave na query string. Endereços vão parar nos logs do servidor web, no cabeçalho
Referere no histórico do navegador. Só cabeçalho. - Rotacione por calendário, não por incidente. Uma chave que já foi rotacionada uma vez rotaciona rápido. Uma que nunca foi vai acabar fixa em quatro lugares.
- Acompanhe o último uso. Uma chave intocada por meio ano não é reserva, é porta aberta.
O que usamos
A API da Lix.li autentica por chave: cabeçalho X-Api-Key, chaves criadas e revogadas no painel, conferência por hash, limite de requisições próprio por chave. Não há OAuth, e isso é deliberado: os cenários da API são de servidor — criar um link, puxar estatísticas, aceitar uma conversão — e em nenhum deles existe um terceiro a quem o usuário precise dar consentimento.
Se surgisse a necessidade de deixar aplicativos de terceiros entrarem nas contas dos nossos clientes, as chaves deixariam de bastar: o usuário precisa enxergar a quem permitiu o quê e conseguir desconectar um aplicativo sem quebrar os demais. É aí que o OAuth deixa de ser cerimônia e passa a ser a única opção honesta.
As chamadas em si estão descritas na documentação da API, inclusive os códigos de resposta que voltam para uma chave inválida e para uma revogada. Num tema vizinho, por que um redirecionamento 301 transforma um POST em GET merece a leitura de quem está montando o recebimento de postbacks: uma requisição autenticada pode chegar por um método diferente daquele com que saiu.