Noções de segurança
Esconder uma chave de API: mova para uma Edge Function do Supabase
Esconder uma chave de API é tirá-la do navegador, e uma Edge Function do Supabase é o menor lugar para guardá-la. Dois passos em volta pesam mais.

Em resumo
- Nada no navegador sabe guardar segredo, então esconder uma chave de API é movê-la para algo que saiba. Uma Edge Function do Supabase é o menor servidor que você consegue ter.
- A mudança são quatro passos. Troque antes a chave que você já publicou, porque a cópia no seu bundle antigo continua legível depois que você a tira de lá.
- Uma function publicada exige um token por padrão, e a chave pública do seu próprio frontend atende essa exigência. Conferir quem está chamando é um passo à parte, e é ele que impede um desconhecido de gastar a sua cota.
Todo guia sobre uma chave de API vazada termina no mesmo lugar: mova para um servidor. Aí ele para. Você fica com um app que construiu no Lovable, no Bolt ou no Cursor, nenhum servidor à vista, e uma frase que presume que você já sabe o que fazer em seguida.
Esta é a parte que guia após guia deixa de fora. Mover a chave para uma Edge Function do Supabase tira ela da sua página, e sozinho isso não impede um desconhecido de usar. A própria documentação do Supabase diz por quê: a checagem que uma function publicada faz por padrão também aceita sua chave pública, e sua chave pública está no seu frontend, ao alcance de quem quiser copiar. Esconder a chave é a metade fácil. Sobre a outra metade ninguém escreve: decidir para quem a sua nova function responde.
Pense na chave como a chave-mestra de um estoque. Agora ela está colada por dentro da vitrine, onde qualquer um que parar consegue ler. Uma Edge Function é um quartinho dos fundos com um guichê: a chave vai para lá, e os visitantes pedem no guichê em vez de entrar e se servir. Se isso é uma melhora depende de para quem o guichê abre.
Onde coloco minha chave de API, se não é no frontend?
Em qualquer lugar que não seja o navegador. Uma Edge Function é a versão menor disso.
Um navegador não sabe guardar segredo. Tudo que sua página precisa para funcionar
é baixado por cada visitante, e um visitante consegue ler tudo: o código, as
imagens, os valores compilados dentro do código. Isso não é um defeito da sua
ferramenta. É o que uma página web é.
Quais chaves de API são seguras no frontend
é a versão longa; a curta é que uma chave sk_, uma chave da OpenAI ou uma chave
secreta do Supabase nunca ia sobreviver a uma viagem até o navegador.
Uma Edge Function do Supabase é um pedacinho de código que roda nas máquinas do Supabase. Ela consegue ler os segredos que você definiu no projeto, responde num endereço web próprio, e seu app chama ela pelo nome. Você escreve um arquivo, o Supabase executa, e não há servidor nenhum para alugar, atualizar ou manter acordado.
Troque a chave que você já publicou, antes de mover qualquer coisa
A chave que está hoje no seu frontend já é pública, e continua pública depois que você tira ela do código.
Cada visitante que carregou seu site baixou ela. Cada robô também, e existem robôs automáticos percorrendo a web inteira atrás exatamente dessas sequências. Seu bundle antigo ainda está, além disso, no seu histórico de versões e em qualquer cache com uma cópia da sua página. Apagar uma linha de um arquivo que é seu não muda nada sobre um valor que já foi distribuído.
Então a ordem é: criar uma chave nova no fornecedor, segurar ela um instante, e revogar a antiga assim que a function abaixo estiver no ar. Depois leia sua página de cobrança e seus registros de uso de todo o período em que a chave antiga esteve solta. Trocar barra o que vem a seguir; sobre o que já aconteceu não tem efeito nenhum. Se a chave era uma chave secreta do Supabase, a ordem em que trabalhar tem um detalhe que vale ler antes.
Os quatro passos
Guardar o segredo, escrever a function, publicar, e mudar seu app para chamar a function em vez do fornecedor.
| Passo | Na linha de comando | No painel |
|---|---|---|
| 1. Guardar o segredo | supabase secrets set MY_API_KEY=… | Edge Functions → Secrets, depois Key e Value |
| 2. Escrever a function | supabase functions new forward-request | Edge Functions → Deploy a new function → Via Editor |
| 3. Publicar | supabase functions deploy | O botão Deploy embaixo do editor |
| 4. Chamar do seu app | supabase.functions.invoke('…') | Igual, no código do seu app |
Dentro da function o segredo chega como variável de ambiente, ou seja, um valor com nome que o código consegue ler e ninguém de fora. A documentação do Supabase sobre segredos de Edge Functions tem a referência completa, e três detalhes de lá poupam uma hora de confusão:
- O nome de um segredo não pode começar com
SUPABASE_. Esse prefixo é reservado para os valores que o Supabase define por você, e tanto o painel quanto a API recusam. - Um segredo novo já pode ser lido na hora. Você não precisa publicar a function de novo depois de trocar um.
- Local e produção são separados. A pilha local lê
supabase/functions/.env, que é um lugar diferente dos segredos do seu projeto no ar, então defina o valor nos dois, ou a function funciona na sua máquina e falha depois de publicada.
Depois apague a variável antiga do seu frontend. Se ela se chamava VITE_,
NEXT_PUBLIC_ ou EXPO_PUBLIC_, esse prefixo era a instrução de compilar o
valor dentro do bundle, e o prefixo é a história
inteira de como ele foi parar lá.
Exigir um token quer dizer que só meus usuários conseguem chamar?
Não, e este é o ponto deste artigo que vale ler duas vezes.
O Supabase liga por padrão uma checagem chamada verify_jwt. Ela olha o
cabeçalho Authorization antes do seu código rodar e recusa a requisição se não
houver nada válido ali. Parece uma porta que só seus usuários abrem. Não é,
porque o Supabase documenta também que a mesma checagem
aceita uma chave pública ou secreta
em qualquer um dos dois cabeçalhos, por compatibilidade com projetos mais
antigos, e acrescenta com todas as letras que a checagem sozinha não autentica
quem chama mandando só uma chave de API.
Sua chave pública está no seu frontend. Isso está certo e é para ser assim. Também quer dizer que quem abrir seu site, ler a chave e mandar ela para a sua function nova passa pela checagem da plataforma e entra no seu código.
No estoque, verify_jwt é um porteiro que confere se você está com um crachá de
visitante. Todo visitante tem um, porque é você quem distribui na entrada. Quem
está no guichê faz outro serviço, e é essa pessoa que pergunta qual visitante
você é.
Trancar a function, para não ter construído um proxy aberto
Decida quais chamadores sua function aceita, e escreva essa decisão dentro da function.
O Supabase entrega um invólucro para isso, então é uma linha e não um projeto.
Coloque auth: 'user' e a function aceita o token de um usuário logado e entrega
ao seu código um cliente de banco já limitado às regras de Row Level Security
desse usuário:
import { withSupabase } from 'npm:@supabase/server@1'
export default {
fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => {
// ctx.userClaims diz quem está chamando. Recuse aqui o que você não quer,
// e então chame o fornecedor com o segredo vindo do ambiente.
return Response.json({ ok: true })
}),
}
A página Securing Edge
Functions lista os outros
modos, e dois deles importam num app comum. Uma function chamada por outra
máquina e não por um navegador usa auth: 'secret', com a chave secreta mandada
no cabeçalho apikey. Uma function que recebe webhooks da Stripe ou do GitHub
não pode usar nenhum dos dois, porque esses fornecedores não têm token nenhum
seu; ela coloca verify_jwt = false e confere a assinatura do fornecedor dentro
do handler.
Seja qual for a escolha, decida com cuidado o que acontece quando aparece um chamador que você não esperava. O exemplo que o Supabase dá de uma function que pode aceitar qualquer um é uma verificação de saúde, e uma verificação de saúde não custa nada quando um desconhecido chama. Uma function que repassa uma chamada de API paga cobra de você cada uma delas.
Posso usar service_role numa Edge Function?
Pode. Uma function é o único lugar em que uma chave secreta do Supabase cabe.
E você nem precisa colar ela. O Supabase coloca as chaves do projeto no ambiente
da function, então o código lê de lá e não de um segredo definido por você.
Projetos novos recebem SUPABASE_SECRET_KEYS e SUPABASE_PUBLISHABLE_KEYS, cada
um um pequeno dicionário de chaves com nome; projetos mais antigos recebem
SUPABASE_SERVICE_ROLE_KEY e SUPABASE_ANON_KEY com os nomes de sempre. O que
mudou quando o Supabase renomeou as chaves diz qual
par você tem.
Use a chave secreta para o trabalho que realmente precisa ver cada linha, como gravar um registro de auditoria que o usuário não possa editar. Para tudo que um usuário lê sobre si mesmo, use o token dele e deixe suas regras de Row Level Security filtrarem, que é para isso que elas existem.
Conferir pelo navegador, a única prova que vale
Carregue seu site no ar, abra a aba de rede, e veja o que seu navegador manda de verdade.
As duas coisas para conferir:
- Nenhuma requisição leva a chave. Passe pela parte do seu app que antes
chamava o fornecedor. A requisição de saída tem que ir para
…supabase.co/functions/v1/sua-function, e a única credencial lá dentro tem que ser sua chave pública ou o token do seu usuário. - A chave não está no código baixado. Use a busca do navegador em todos os arquivos carregados e cole a primeira dúzia de caracteres da chave antiga. Nenhum resultado é a resposta que você quer.
Só uma nova compilação e uma nova publicação tiram um valor do bundle. Uma chave que ainda aparece na busca costuma querer dizer que o frontend saiu antes de a variável sair dele.
Nosso scan gratuito faz a segunda conferência de fora e diz o que consegue ler no seu bundle no ar, inclusive qual chave do Supabase você publicou. Leva uns 20 segundos e não precisa de conta: escaneie seu app.
Como fazer isso a partir do Lovable, Bolt ou Replit
Use o painel do Supabase. Não tem nenhum passo de terminal ali.
Abra seu projeto, escolha Edge Functions na barra lateral e depois Deploy a new function → Via Editor. O guia rápido do painel do Supabase percorre tudo com capturas de tela, e entre os modelos oferecidos há um para repassar a um fornecedor de IA, que é exatamente o formato deste trabalho. A publicação leva entre dez e trinta segundos, e a function fica no ar num endereço próprio. Seu segredo vai na página Edge Function Secrets, na mesma seção.
Uma ressalva que vale conhecer antes de confiar nisso: o Supabase escreve que o editor do painel não tem controle de versão, nem versões, nem volta atrás, e recomenda ele para trabalho rápido e não para código que vai ficar. Apertar Deploy sobrescreve o que estava lá. Se a function acabar fazendo algo que importa para você, baixe ela por essa página e guarde o arquivo.
Existe também uma versão desta pergunta no formato Replit, porque o Replit tem um armazém de segredos próprio e seu app roda um servidor próprio lá. O que os Replit Secrets fazem de verdade é essa versão.
Quando uma Edge Function é a resposta errada
Dois casos, e nos dois a mudança custa trabalho e não traz nada.
A chave era pública de propósito. Uma chave pk_live_ da Stripe, uma chave
pública do Supabase ou uma chave anon, um token público do Mapbox: essas são
feitas para ficar num navegador, e a proteção está em outro lugar. Colocar uma
delas atrás de uma function acrescenta um desvio e não tira risco nenhum. Quais
chaves são essas é a lista.
A chave pode ser restrita ao seu próprio site. As chaves de navegador do Google são o exemplo mais comum: no console do Google você limita uma delas aos seus domínios, e é justamente essa a solução que o Google prevê para esse caso. A chave continua legível e deixa de servir para quem a copiar.
Todo o resto fica num servidor. Uma chave da OpenAI ou da Anthropic não tem variante pública, e é por isso que uma chave de fornecedor de IA no seu frontend não tem ajuste nenhum que a salve, e nenhuma minificação esconde uma chave secreta da Stripe de quem ler sua página.
O que fazer agora
O que fazer
- Troque a chave primeiro. Crie uma nova no fornecedor, coloque no segredo da function, e revogue a antiga assim que a function estiver no ar.
- Guarde o segredo no seu projeto do Supabase, não no seu repositório e não numa variável
VITE_. Defina separadamente para desenvolvimento local e para produção. - Publique uma function que usa o segredo, e mude seu app para chamar a function pelo nome em vez do fornecedor.
- Acrescente uma checagem de quem está chamando.
verify_jwtsozinho aceita a chave pública do seu próprio frontend, então não barra um desconhecido. - Apague a variável antiga, compile de novo, e confirme na aba de rede do navegador que nada que sai leva a chave.
- Leia cobrança e uso de todo o período em que a chave antiga ficou pública. Trocar barra a próxima cobrança e não a última.
Se você prefere revisar o app inteiro em vez de uma chave só, a checklist de segurança em 10 minutos cobre isso junto com as outras coisas que vale fechar num app recém-lançado.
Perguntas frequentes
Onde coloco minha chave de API, se não é no frontend?
Em qualquer lugar que não seja o navegador. Uma Edge Function do Supabase é a opção menor: você guarda a chave como segredo no seu projeto, escreve um arquivo pequeno que usa ela, e seu app chama essa function pelo nome em vez de chamar o fornecedor direto. Uma rota serverless na sua hospedagem ou um servidor seu funcionam igual. O que elas têm em comum é que a chave é lida onde seu visitante não vê.
O que é uma Edge Function do Supabase?
Um pedacinho de código que roda nas máquinas do Supabase e não no navegador do seu visitante. Ela responde num endereço web próprio, consegue ler os segredos que você definiu no projeto, e seu app chama ela com supabase.functions.invoke. Você escreve um arquivo, o Supabase executa, e não há servidor nenhum para alugar ou manter.
Preciso trocar a chave depois de mover?
Precisa, e antes de tudo. A chave que estava no seu frontend foi baixada por cada visitante e por cada robô que leu seu site, e tirar ela do código não muda nada sobre essas cópias. Crie uma chave nova no fornecedor, coloque no segredo da sua Edge Function e revogue a antiga. Depois confira cobrança e uso em todo o período em que a chave antiga esteve valendo.
Qualquer pessoa pode chamar minha Edge Function?
Por padrão uma function recusa uma requisição sem token nenhum, mas essa checagem é mais fraca do que parece. O Supabase documenta que a checagem da plataforma aceita também sua chave pública ou secreta, e sua chave pública está no seu frontend, onde qualquer um consegue ler. Então a checagem barra uma requisição vazia e não uma decidida. Para aceitar só seus usuários logados, verifique quem chamou dentro da function.
Posso usar service_role numa Edge Function?
Pode. Uma Edge Function é o único lugar em que uma chave secreta do Supabase cabe, e o Supabase coloca as chaves do projeto no ambiente da function para você, então você nunca cola nenhuma. Use para o trabalho que precisa ver cada linha, e use o token de quem chamou para tudo que deve respeitar suas regras de Row Level Security.
Dá para fazer isso sem terminal?
Dá. O painel do Supabase tem uma seção Edge Functions onde você escreve uma function no navegador, aperta Deploy e define seu segredo na página Edge Function Secrets. O Supabase avisa que o editor do painel não guarda histórico de versões, então recomenda ele para trabalho rápido e deixa a linha de comando para o que você pretende manter.