---
title: "Supabase anon key vs service role key: o que cada uma abre"
description: "A anon key (publishable) só é segura no browser por trás do RLS; a service role key (secret) ignora-o. Onde vai cada uma, testado numa stack local."
url: "https://madsalt.tech/pt/blog/supabase-anon-key-vs-service-role-key/"
author: "Denys Zaichenko"
language: "pt"
published: 2026-10-25
---

# Supabase anon key vs service role key: o que cada uma abre

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](https://supabase.com/docs/guides/api/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:

![Em que função do Postgres se transforma cada chave. E se as suas políticas de RLS veem o pedido. Publishable key, sem sessão: Publishable key → função anon → O RLS aplica-se; Publishable key, com sessão: Publishable key + token → função authenticated → O RLS aplica-se; Secret key: Secret key → função service_role → RLS ignorado.](https://madsalt.tech/charts/pt/supabase-anon-key-vs-service-role-key.svg)

*Figura 1. Do guia de API keys do Supabase, verificado numa stack local, 23 de outubro de 2026.*

| 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](https://mattpalmer.io/posts/2025/05/statement-on-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-Agent` e devolve `401`. O JWT antigo de `service_role` nã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.

1. Crie uma nova secret key, passe os seus servidores para ela e só depois apague a divulgada. Se a fuga foi de uma `service_role` key 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.
2. Procure `sb_secret_` e `service_role` no 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](https://escape.tech/blog/methodology-how-we-discovered-vulnerabilities-apps-built-with-vibe-coding/), a maioria em bundles de frontend.
3. Reveja o que mudou enquanto esteve exposta: utilizadores novos, alterações de função, linhas apagadas.

A [Auditoria de segurança Supabase](https://madsalt.tech/pt/tools/supabase-security-check/) 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](https://madsalt.tech/pt/blog/vibe-coding-security-risks/), e a lista completa que executo numa app está na minha [lista de segurança para apps Lovable](https://madsalt.tech/pt/blog/lovable-app-security-checklist/).

Não sabe que chave a sua app envia?

Gostava de dar uma vista de olhos e trocar impressões. Sem pitch.

[Fale comigo](https://madsalt.tech/pt/#contact)
