[{"data":1,"prerenderedAt":464},["ShallowReactive",2],{"blog-pt-which-api-keys-are-safe-in-your-frontend":3},{"id":4,"title":5,"body":6,"category":420,"cover":421,"coverAlt":421,"description":422,"draft":423,"extension":424,"faq":425,"image":441,"keywords":442,"meta":451,"navigation":452,"ogTitle":453,"path":454,"published":455,"seo":456,"stem":457,"tldr":458,"updated":462,"__hash__":463},"blog_pt\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend.md","Quais chaves de API são seguras no navegador e quais não são",{"type":7,"value":8,"toc":410},"minimark",[9,13,21,26,29,32,48,51,55,58,61,64,73,79,83,206,209,228,232,254,260,276,288,291,301,306,316,323,327,335,338,345,348,355,359,395,403],[10,11,12],"p",{},"Quem criou o app com Lovable, Bolt, v0, Cursor ou Replit uma hora passa por\nisto: alguém abre o site, aperta F12 e avisa que a sua chave de API está\n\"exposta\". É uma notícia assustadora sobre um app cujo código você não consegue\nler.",[10,14,15,16,20],{},"Aqui está o que guia após guia erra: ",[17,18,19],"strong",{},"algumas dessas chaves deveriam mesmo\nestar ali."," Tratar toda chave visível como um vazamento leva ou a um susto sem\nmotivo ou, bem pior, a aprender a ignorar o aviso, e a ignorá-lo também no dia\nem que ele importa.",[22,23,25],"h2",{"id":24},"é-ruim-que-minha-chave-de-api-esteja-visível","É ruim que minha chave de API esteja visível?",[10,27,28],{},"Normalmente não. Depende inteiramente de qual chave é.",[10,30,31],{},"Todo serviço que conversa com um navegador entrega dois tipos diferentes de\ncredencial. Um é um endereço. O outro é o molho de chaves do prédio. Os dois se\nchamam \"chave de API\", e é daí que vem quase toda a confusão.",[10,33,34,35,38,39,42,43,47],{},"Um ",[17,36,37],{},"endereço"," pode ser publicado sem risco. Ele só diz a qual projeto um\npedido pertence; a checagem de permissão acontece em outro lugar. Um ",[17,40,41],{},"molho de\nchaves"," não pode, porque ele ",[44,45,46],"em",{},"é"," a checagem de permissão: quem o tiver faz tudo\no que ele permite, de qualquer lugar.",[10,49,50],{},"Seu app precisa do endereço no navegador para funcionar. Ele nunca deveria\nprecisar do molho de chaves ali.",[22,52,54],{"id":53},"por-que-seu-app-manda-chaves-para-o-navegador","Por que seu app manda chaves para o navegador",[10,56,57],{},"Porque o pedido sai do navegador do seu visitante, não do seu servidor.",[10,59,60],{},"Quando seu app carrega a lista de pedidos dos seus usuários, esse pedido sai\ndireto do navegador do visitante para o seu provedor de banco de dados. Ele\nprecisa dizer a qual projeto pertence, e esse identificador precisa estar na\npágina, porque é de lá que o pedido é feito.",[10,62,63],{},"Não existe versão disso em que o identificador seja secreto. Ele chega a todo\nvisitante por projeto. E é exatamente por isso que os provedores dividem as\ncredenciais em duas: eles sabem que uma delas vai ser pública, então fizeram\nessa ser inofensiva.",[10,65,66,67,72],{},"A segurança não vem de esconder o endereço. Vem das regras que você define do\noutro lado: no caso do Supabase, o Row Level Security, que decide linha a linha\nquem pode ver o quê. São essas regras que valem a conferida, e\n",[68,69,71],"a",{"href":70},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","ligá-las não é a mesma coisa que estar protegido",".",[74,75],"diagram",{"alt":76,"caption":77,"src":78},"Dois caminhos até a mesma tabela. A chave anon para na barreira do Row Level Security e alcança só as duas linhas que as regras permitem. A chave service_role passa por uma brecha na barreira e alcança as seis.","É o Row Level Security que torna a chave anon segura. Uma chave service_role passa direto por ele.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fwhat-each-key-reaches-1600x820.png",[22,80,82],{"id":81},"as-duas-famílias-de-chave","As duas famílias de chave",[84,85,86,105],"table",{},[87,88,89],"thead",{},[90,91,92,96,99,102],"tr",{},[93,94,95],"th",{},"Provedor",[93,97,98],{},"Chave",[93,100,101],{},"Segura no navegador?",[93,103,104],{},"O que ela faz",[106,107,108,135,156,174,191],"tbody",{},[90,109,110,114,125,132],{},[111,112,113],"td",{},"Supabase",[111,115,116,120,121,124],{},[117,118,119],"code",{},"sb_publishable_…",", ou ",[117,122,123],{},"anon"," em projetos antigos",[111,126,127],{},[128,129,131],"key-verdict",{"type":130},"safe","É o lugar dela",[111,133,134],{},"Diz de qual projeto se trata. Todo pedido continua filtrado pelas suas regras de Row Level Security.",[90,136,137,139,147,153],{},[111,138,113],{},[111,140,141,120,144,124],{},[117,142,143],{},"sb_secret_…",[117,145,146],{},"service_role",[111,148,149],{},[128,150,152],{"type":151},"danger","Nunca",[111,154,155],{},"Ignora o Row Level Security por completo. Lê e escreve em toda linha de toda tabela, independentemente das suas regras.",[90,157,158,161,167,171],{},[111,159,160],{},"Stripe",[111,162,163,166],{},[117,164,165],{},"pk_live_…"," (publicável)",[111,168,169],{},[128,170,131],{"type":130},[111,172,173],{},"Cria formulários de pagamento. Não move dinheiro nem lê clientes.",[90,175,176,178,184,188],{},[111,177,160],{},[111,179,180,183],{},[117,181,182],{},"sk_live_…"," (secreta)",[111,185,186],{},[128,187,152],{"type":151},[111,189,190],{},"Acesso total à conta: cobranças, reembolsos, repasses, cadastros de clientes.",[90,192,193,196,199,203],{},[111,194,195],{},"OpenAI \u002F Anthropic",[111,197,198],{},"qualquer chave",[111,200,201],{},[128,202,152],{"type":151},[111,204,205],{},"Não existe versão publicável. Toda chave cobra direto da sua conta.",[10,207,208],{},"O padrão vale além desses três. Se um provedor oferece só um tipo de chave,\nassuma que ela é secreta e que o lugar dela é um servidor.",[210,211,213],"callout",{"type":212},"warn",[10,214,215,218,219,221,222,224,225,227],{},[17,216,217],{},"A que mais pega gente é a chave secreta do Supabase."," Num projeto antigo ela\nse chama ",[117,220,146],{}," e é quase idêntica à chave anon: mesmo formato, mesmo\ntamanho, mesmo lugar no painel, uma do lado da outra. Copiar a errada é um único\nclique fora do lugar, e depois nada quebra: seu app funciona exatamente como\nantes. É isso que torna o erro tão fácil de passar batido. Nos projetos novos\nfoi justamente isso que melhorou: ",[117,223,143],{}," e ",[117,226,119],{}," dizem qual é\nqual já nos primeiros caracteres.",[22,229,231],{"id":230},"como-diferenciar-em-60-segundos","Como diferenciar em 60 segundos",[10,233,234,237,238,241,242,245,246,249,250,253],{},[17,235,236],{},"No Stripe, e na maioria dos provedores, basta o prefixo."," ",[117,239,240],{},"pk_"," é publicável\ne segura. ",[117,243,244],{},"sk_"," é secreta e não é. Alguns provedores colocam ",[117,247,248],{},"_test_"," ou\n",[117,251,252],{},"_live_"," no meio: uma chave de teste vazada é um problema bem menor do que uma\nde produção, mas troque as duas.",[10,255,256,259],{},[17,257,258],{},"No Supabase depende de quão antigo é o seu projeto."," O Supabase já emitiu\ndois formatos diferentes de chave, e os dois estão hoje em apps no ar.",[10,261,262,237,265,267,268,270,271,275],{},[17,263,264],{},"Projetos novos: leia o prefixo, igual ao Stripe.",[117,266,119],{}," é a que\ntem lugar no seu app. ",[117,269,143],{}," é a que se troca hoje. Não há nada a\ndecodificar: para que serve a chave está escrito na frente dela.\n",[68,272,274],{"href":273},"\u002Fblog\u002Fsupabase-new-api-keys","O que mudou e o que isso significa para o seu app",",\ncaso você ainda não tenha esbarrado nelas.",[10,277,278,281,282,284,285,287],{},[17,279,280],{},"Projetos antigos: é preciso olhar dentro da chave."," O par original, ",[117,283,123],{}," e\n",[117,286,146],{},", são JWTs: três blocos de rabisco separados por pontos, e o do\nmeio é informação legível, não criptografia. Ali está o papel da chave em texto\nclaro.",[10,289,290],{},"Em nenhum dos casos você precisa de ferramenta. Abra Settings → API Keys no\npainel do Supabase e ele diz qual é qual. Se preferir conferir a chave que você\nrealmente achou no seu app, a parte do meio de uma chave antiga decodifica em\nalgo assim.",[292,293,298],"pre",{"className":294,"code":296,"language":297},[295],"language-text","{\n  \"iss\": \"supabase\",\n  \"ref\": \"abcdefghij…\",\n  \"role\": \"anon\",          ← é esta palavra que importa\n  \"iat\": 1750000000\n}\n","text",[117,299,296],{"__ignoreMap":300},"",[74,302],{"alt":303,"caption":304,"src":305},"Uma chave antiga do Supabase desenhada como três seções separadas por pontos. A do meio está destacada e decodifica em role anon, marcada como segura, ou em role service_role, marcada como perigosa.","Numa chave antiga a seção do meio é texto legível, não criptografia. Uma palavra ali decide se a chave podia ser publicada.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fread-the-role-1600x640.png",[10,307,308,311,312,315],{},[117,309,310],{},"\"role\": \"anon\""," é a segura. ",[117,313,314],{},"\"role\": \"service_role\""," é a que se troca hoje.\nNuma chave antiga essa única palavra é toda a diferença, e é por isso que um\nscanner que só procura textos com cara de chave devolve ruído em vez de\nresposta: ele não consegue dizer qual de duas chaves idênticas você publicou.",[10,317,318,319,72],{},"Se você prefere não vasculhar seu app chave por chave, nosso scan gratuito lê seu\nsite no ar e diz quais dessas dá para ver de fora. Leva uns 20 segundos e não\nprecisa de conta: ",[68,320,322],{"href":321},"\u002F#scan","escaneie seu app",[22,324,326],{"id":325},"o-que-acontece-de-fato-quando-uma-chave-secreta-vaza","O que acontece de fato quando uma chave secreta vaza",[10,328,329,330,120,332,334],{},"Toda linha do seu banco de dados passa a poder ser lida e alterada por quem\nencontrou a chave, incluindo tabelas que você nunca expôs ao app e os dados\npessoais dos seus usuários. O Row Level Security não se aplica a uma chave\nsecreta do Supabase (",[117,331,143],{},[117,333,146],{}," num projeto antigo). Esse é\no propósito da chave.",[10,336,337],{},"O estrago também não é teórico. Normalmente ele aparece como uma mensagem de\nsuporte sobre dados que mudaram sozinhos, ou como uma tabela que de repente está\nvazia.",[10,339,340,341,344],{},"Uma chave ",[117,342,343],{},"sk_live_"," do Stripe vazada significa reembolsos, cobranças e cadastros\nde clientes. Uma chave vazada de um provedor de IA significa uma fatura, às vezes\nbem alta, chegando antes de alguém perceber.",[10,346,347],{},"Nada disso exige um atacante sofisticado. Há scanners automáticos varrendo sites\npúblicos atrás exatamente desses textos, e eles não precisam saber quem você é\npara achar a sua.",[10,349,350,351,72],{},"Se quiser a versão específica da plataforma sobre o que conferir, temos um guia\nem linguagem simples para ",[68,352,354],{"href":353},"\u002Fis-your-supabase-app-safe","apps com Supabase",[22,356,358],{"id":357},"o-que-fazer-agora","O que fazer agora",[360,361,362],"key-takeaways",{},[363,364,365,373,380,383,392],"ul",{},[366,367,368,369,372],"li",{},"Ache cada chave do seu app e identifique cada uma. O prefixo no Stripe e nas chaves novas do Supabase; o campo ",[117,370,371],{},"role"," dentro das chaves antigas do Supabase.",[366,374,375,376,379],{},"Se achar uma chave secreta no navegador, ",[17,377,378],{},"troque primeiro",". Apagar do código não fecha a porta: o valor antigo continua no seu histórico de versões e em cópias em cache do seu site.",[366,381,382],{},"Mova para um servidor o que precisava daquela chave: uma edge function, uma rota serverless, qualquer coisa que não seja o navegador.",[366,384,385,386,388,389,391],{},"Ligue o Row Level Security em todas as tabelas e depois confira se ele realmente funciona. Uma chave publicável (",[117,387,119],{}," ou ",[117,390,123],{},") só é segura por causa dessas regras; sem elas, ela lê o seu banco inteiro.",[366,393,394],{},"Confira cobrança e registros depois de qualquer exposição de chave secreta. Trocar a chave impede o que vem depois, não o que já aconteceu.",[10,396,397,398,402],{},"Se preferir ir por uma lista, o\n",[68,399,401],{"href":400},"\u002Fchecklist","checklist de segurança de 10 minutos"," cobre isso e as outras coisas\nque vale desligar num app recém-lançado.",[10,404,405,406,72],{},"E se um vazamento chegar a esvaziar uma tabela, recuperá-la depende inteiramente\nde ",[68,407,409],{"href":408},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","o que você estava copiando",{"title":300,"searchDepth":411,"depth":411,"links":412},3,[413,415,416,417,418,419],{"id":24,"depth":414,"text":25},2,{"id":53,"depth":414,"text":54},{"id":81,"depth":414,"text":82},{"id":230,"depth":414,"text":231},{"id":325,"depth":414,"text":326},{"id":357,"depth":414,"text":358},"Noções de segurança",null,"Sua chave anon do Supabase foi feita para ser pública. Sua chave service_role não, e ela ignora todas as regras que você criar. Como diferenciar as duas.",false,"md",[426,429,432,435,438],{"q":427,"a":428},"Disseram que minha chave de API está exposta. Devo me preocupar?","Não até saber de qual chave se trata. Se começa com pk_ ou é uma chave anon do Supabase, ela foi feita para ser pública e está tudo certo. Se começa com sk_ ou é uma chave service_role, gere uma nova agora e depois veja o que ela conseguia alcançar.",{"q":430,"a":431},"Posso simplesmente esconder a chave para ninguém achar?","Não. Tudo o que o seu navegador consegue usar, um visitante consegue ler: minificar, renomear ou ofuscar só atrasa alguém por alguns segundos. A solução nunca é esconder uma chave secreta no navegador, e sim movê-la para um servidor ou usar uma chave publicável que já era segura de expor desde o início.",{"q":433,"a":434},"Por que o Supabase me dá uma chave que qualquer um pode ler?","Porque não é a chave anon que protege seus dados. Ela só diz com qual projeto você está falando. A proteção de verdade é o Row Level Security, que decide linha a linha o que cada visitante pode ver. Por isso uma chave anon com RLS ligado não é problema, e a mesma chave sem RLS é um banco de dados aberto.",{"q":436,"a":437},"Minha chave do Supabase começa com sb_publishable_. É a mesma coisa que a chave anon?","Ela faz o mesmo trabalho. O Supabase renomeou suas chaves: sb_publishable_ substituiu a chave anon e sb_secret_ substituiu a service_role. Então uma chave que começa com sb_publishable_ foi feita para viver no seu app, e uma que começa com sb_secret_ nunca foi. Projetos antigos continuam carregando as chaves anon e service_role originais, e elas ainda funcionam; você pode até ver os dois pares lado a lado no painel.",{"q":439,"a":440},"Eu já colei uma chave secreta no meu app. E agora?","Gere uma nova primeiro: no painel do provedor, crie uma chave nova e revogue a antiga. É isso que fecha a porta de verdade; tirar do código não basta, porque o valor antigo continua no seu histórico de versões e em cópias em cache. Depois mova para um servidor o que precisava daquela chave e confira a cobrança e os registros à procura de algo que não foi você.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",[443,444,445,446,447,448,449,450],"chave anon supabase","chave service_role","chave sb_publishable","chave sb_secret","novas chaves api supabase","chave publicável stripe","chaves api no navegador","chave api exposta",{},true,"Quais chaves de API são seguras no navegador?","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","2026-08-09",{"title":5,"description":422},"blog\u002Fwhich-api-keys-are-safe-in-your-frontend",[459,460,461],"Encontrar uma chave de API no código do seu app não é automaticamente um problema. Algumas chaves foram feitas para estar ali.","Chaves publicáveis são seguras no navegador. Chaves secretas não: uma chave secreta no navegador é um caixa aberto.","Duas conferências separam as duas em menos de um minuto: ler o prefixo e, numa chave antiga do Supabase, decodificar o papel.","2026-08-12","dji-MPX24ugqzxgffQpEMGF2sEXkjA07XfrreixtLKY",1787826050921]