Em resumo
A anon key, agora chamada publishable key, foi feita para ser pública: corresponde à função anon ou authenticated, e as suas políticas de RLS decidem o que ela vê. A service role key, agora secret key, corresponde a service_role, que ignora o RLS por completo. Na minha tabela de teste local com o RLS ligado e sem política, a chave pública obteve 0 linhas e a secreta as 3. Ponha a publishable key no browser, mantenha a secret key num servidor e rode-a se alguma vez tiver sido publicada.
Sou o Denys, engenheiro full-stack e de IA. Uma secret key divulgada é a primeira coisa que procuro quando pego numa app Supabase, porque com ela todas as outras proteções são decoração. Este artigo explica o que cada chave abre, com os pedidos que executei para o verificar.
O que é a anon key do Supabase?
A anon key identifica a sua app, não o seu utilizador. Todos os pedidos de um browser ou de uma app móvel a levam, por isso tem de ser pública: qualquer pessoa a pode ler no código-fonte da página. Um pedido só com esta chave corre como a função do Postgres anon. Quando um utilizador inicia sessão pelo Supabase Auth, a mesma chave viaja com o token do utilizador e o pedido corre como authenticated. As suas políticas de RLS são escritas para essas duas funções.
O Supabase está a mudar o nome às chaves. O guia de API keys chama publishable (sb_publishable_…) e secret (sb_secret_…) às novas, e dá por obsoletas, até ao fim de 2026, as antigas anon e service_role, baseadas em JWT. As funções por trás delas mantêm-se.
| Chave | Nome antigo | Função do Postgres | O RLS aplica-se? | Onde vai |
|---|---|---|---|---|
Publishable sb_publishable_… |
anon key |
anon, ou authenticated com um token de utilizador |
Sim | Browser, app móvel, tudo o que distribui |
Secret sb_secret_… |
service_role key |
service_role |
Não, a função tem BYPASSRLS |
Só servidor, Edge Function ou tarefa agendada |
É seguro expor a anon key do Supabase?
Sim, se todas as tabelas, vistas e funções a que ela chega estiverem protegidas. A chave em si não concede nada de especial; os grants e as políticas do seu schema decidem tudo. Verifiquei-o numa stack local do Supabase (CLI 2.109.1, Postgres 17.6) com uma tabela de três encomendas falsas:
| Estado da tabela | Publishable key | Secret key |
|---|---|---|
| RLS desligado | As 3 linhas, e um insert devolveu 201 Created |
As 3 linhas |
| RLS ligado, sem política | [] |
As 3 linhas |
RLS ligado, política using (true) |
As 3 linhas | As 3 linhas |
Sem grant para anon |
42501 permission denied, com uma dica que nomeia o GRANT em falta |
As 3 linhas |
Por isso, a publishable key é tão segura quanto a sua tabela mais fraca. Uma tabela sem RLS, ou com uma política que permite todas as linhas, é legível por qualquer pessoa que abra o DevTools. Essa é a falha por trás do CVE-2025-48757, em que 170 de 1645 apps de demonstração do Lovable serviam dados à chave pública.
O que é a service role key e porque é perigosa?
A secret key é a chave-mestra. Corre como service_role, que tem o atributo BYPASSRLS, por isso nenhuma política que escreva alguma vez se lhe aplica. Na última coluna da tabela acima, leu as três linhas em todos os estados. O guia do Supabase indica onde ela pertence: servidores que fazem as suas próprias verificações de autorização, Edge Functions, tarefas em segundo plano e ferramentas de administração. Dois detalhes do guia contam na prática:
- A nova secret key recusa pedidos de um browser: o Supabase verifica o
User-Agente devolve401. O JWT antigo deservice_rolenão tem essa verificação, por isso uma chave antiga divulgada funciona de qualquer lado. A minha stack local, que não tem essa verificação no gateway, respondeu com as 3 linhas a um script que usava a secret key. - Uma secret key ignora o RLS apenas quando o pedido não leva o token de um utilizador. Com o token de um utilizador com sessão iniciada, o pedido corre sob as políticas desse utilizador.
Uma Edge Function que use a secret key tem de verificar quem chama e filtrar ela própria por dono ou por empresa, porque nada por baixo o fará.
Onde se encontram as chaves?
No Dashboard, abra o diálogo Connect do seu projeto para ver o URL e a publishable key, ou Settings → API Keys para ver todas as chaves, incluindo as antigas. Em local, supabase start e supabase status mostram uma publishable key e uma secret key. Guarde-as em variáveis de ambiente: no Next.js, só a publishable key pode levar o prefixo NEXT_PUBLIC_, porque o bundler envia para o browser tudo o que o tenha.
O que fazer se a service role key foi divulgada?
Trate-a como comprometida: cada linha de cada tabela pôde ser lida e escrita por quem a encontrou.
- Crie uma nova secret key, passe os seus servidores para ela e só depois apague a divulgada. Se a fuga foi de uma
service_rolekey antiga, a saída é a migração para as chaves novas: crie uma publishable key e uma secret key, mude a app e depois desative as chaves antigas em Settings → API Keys, onde de outra forma continuam válidas. - Procure
sb_secret_eservice_roleno JavaScript compilado e no histórico do Git. A análise da Escape a 5600 apps de vibe coding encontrou mais de 400 segredos expostos, a maioria em bundles de frontend. - Reveja o que mudou enquanto esteve exposta: utilizadores novos, alterações de função, linhas apagadas.
A Auditoria de segurança Supabase gratuita não lê o seu frontend, mas lê o lado da base de dados do mesmo problema: funções que contornam o RLS, tabelas com o RLS desligado, políticas que permitem todas as linhas e colunas que parecem sensíveis e que os visitantes anónimos conseguem ler. Para verificar o que a sua chave pública alcança na prática, os passos estão em riscos de segurança do vibe coding, e a lista completa que executo numa app está na minha lista de segurança para apps Lovable.
Não sabe que chave a sua app envia?
Gostava de dar uma vista de olhos e trocar impressões. Sem pitch.
Fale comigo