[{"data":1,"prerenderedAt":1278},["ShallowReactive",2],{"blog-pt-invalid-claim-missing-sub-claim":3,"blog-index-pt":753},{"id":4,"title":5,"body":6,"category":711,"cover":712,"coverAlt":713,"description":714,"draft":715,"extension":716,"faq":717,"image":733,"keywords":734,"meta":741,"navigation":742,"ogTitle":743,"path":744,"published":745,"seo":746,"stem":747,"tldr":748,"updated":745,"__hash__":752},"blog_pt\u002Fblog\u002Finvalid-claim-missing-sub-claim.md","Supabase \"invalid claim: missing sub claim\": ninguém está logado",{"type":7,"value":8,"toc":698},"minimark",[9,13,24,36,41,44,59,77,83,86,97,103,107,110,119,129,135,142,148,174,182,186,189,203,211,219,226,236,260,265,269,272,283,331,343,346,350,353,362,368,384,390,404,408,411,430,437,447,451,454,568,587,591,597,606,620,630,647,651,683],[10,11,12],"p",{},"O seu app tem uma Supabase Edge Function que faz algo pela pessoa que o usa, como\nsalvar as configurações dela ou chamar a OpenAI em nome dela. Nos seus testes,\nfuncionava. Aí o log da função começa a encher com esta linha, e o app mostra um\nerro ou nada:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","AuthApiError: invalid claim: missing sub claim\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26,27,30,31,35],{},"Pesquise \"invalid claim: missing sub claim\" e vão dizer para você gerar suas\nchaves de novo, desligar o Verify JWT ou colocar a chave ",[21,28,29],{},"service_role",". Cada um\ndesses conselhos trata o token como quebrado. ",[32,33,34],"strong",{},"O token estava certo."," O\nSupabase verificou a assinatura e aceitou. O que faltava nele era um nome,\nqualquer um.",[37,38,40],"h2",{"id":39},"o-que-significa-invalid-claim-missing-sub-claim","O que significa \"invalid claim: missing sub claim\"?",[10,42,43],{},"Perguntaram ao Supabase Auth qual usuário está chamando; ele achou o token\nautêntico e nenhum usuário escrito nele.",[10,45,46,47,50,51,58],{},"Os tokens que o Supabase Auth lê são JWTs: três blocos de texto separados por\npontos, em que o bloco do meio são dados legíveis. Cada item desses dados se\nchama claim. ",[21,48,49],{},"sub",", abreviação de subject, é o claim que guarda o id de um\nusuário, e a\n",[52,53,57],"a",{"href":54,"rel":55},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fjwt-fields",[56],"nofollow","referência de JWT do Supabase","\ndescreve ele como o ID do usuário, um UUID.",[10,60,61,62,65,66,69,70,72,73,76],{},"A mensagem está escrita no próprio código-fonte do Supabase Auth, numa função\nchamada ",[21,63,64],{},"maybeLoadUserOrSession"," em ",[21,67,68],{},"internal\u002Fapi\u002Fauth.go",". Quando essa função\nroda, a assinatura do token já foi verificada e passou. Ela então procura o\n",[21,71,49],{},", e quando o claim está vazio ela para com um HTTP 403, o código de erro\n",[21,74,75],{},"bad_jwt"," e esta frase. A resposta que o seu código recebe fica assim:",[14,78,81],{"className":79,"code":80,"language":19},[17],"{\"code\":403,\"error_code\":\"bad_jwt\",\"msg\":\"invalid claim: missing sub claim\"}\n",[21,82,80],{"__ignoreMap":23},[10,84,85],{},"Pense numa recepção que recebe uma única pergunta: que visitante é este? Você\nentrega um crachá. A recepção confere primeiro o carimbo, e o carimbo é\nautêntico. Depois lê a linha do nome, e a linha do nome está vazia. A recepção\nnão tem com o que responder, então recusa, e a recusa aponta a linha vazia.",[10,87,88,89,92,93,96],{},"Qualquer chamada que precise de uma pessoa logada pode receber essa resposta.\n",[21,90,91],{},"getUser()"," e ",[21,94,95],{},"updateUser()"," são as duas em que você mais provavelmente vai\nvê-la, e adicionar um segundo fator ou vincular outro método de login passa\npela mesma verificação.",[98,99],"diagram",{"alt":100,"caption":101,"src":102},"Dois crachás vão à mesma recepção. Os dois têm um selo autêntico e os dois passam na verificação do selo. O de cima, marcado authenticated, tem rosto e nome, e a recepção responde com uma pessoa e 200. O de baixo, marcado anon, tem a foto e a linha do nome vazias e tracejadas, e a recepção responde 403.","O selo é conferido primeiro, e os dois crachás passam. A pergunta que falha é a segunda: de quem é o nome que está nele.","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fthe-name-line-1600x720.png",[37,104,106],{"id":105},"uma-chave-nomeia-o-seu-app-um-token-de-sessão-nomeia-uma-pessoa","Uma chave nomeia o seu app. Um token de sessão nomeia uma pessoa.",[10,108,109],{},"A chave de API do seu projeto é o crachá com a linha do nome vazia, e ela foi\nfeita assim de propósito.",[10,111,112,113,118],{},"A ",[52,114,117],{"href":115,"rel":116},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fgetting-started\u002Fapi-keys",[56],"documentação de chaves de API","\ndiz isso numa linha: segundo o Supabase, uma chave de API não distingue\nusuários, e sim aplicações. A chave diz ao Supabase qual app está chamando. Quem\nestá usando esse app é outra pergunta, respondida por um token que o Supabase\nAuth emite para cada pessoa quando ela faz login.",[10,120,121,122,125,126,128],{},"A referência de JWT do Supabase mostra os dois. A chave ",[21,123,124],{},"anon"," de um projeto mais\nantigo decodifica para isto, e não existe ",[21,127,49],{}," em lugar nenhum:",[14,130,133],{"className":131,"code":132,"language":19},[17],"{\n  \"iss\": \"supabase\",\n  \"ref\": \"abcdefghijklmnopqrst\",\n  \"role\": \"anon\",\n  \"iat\": 1640991600,\n  \"exp\": 1640995200\n}\n",[21,134,132],{"__ignoreMap":23},[10,136,137,138,141],{},"O token de acesso de uma pessoa logada traz o id dela, o papel ",[21,139,140],{},"authenticated"," e\na sessão a que pertence (cortado aqui para as linhas que importam):",[14,143,146],{"className":144,"code":145,"language":19},[17],"{\n  \"sub\": \"123e4567-e89b-12d3-a456-426614174000\",\n  \"role\": \"authenticated\",\n  \"session_id\": \"123e4567-e89b-12d3-a456-426614174000\",\n  \"email\": \"user@example.com\"\n}\n",[21,147,145],{"__ignoreMap":23},[10,149,150,151,153,154,157,158,160,161,92,164,167,168,173],{},"A chave ",[21,152,29],{}," é de novo a primeira forma, com ",[21,155,156],{},"\"role\": \"service_role\"","\ne ainda sem ",[21,159,49],{},". As chaves mais novas ",[21,162,163],{},"sb_publishable_",[21,165,166],{},"sb_secret_"," nem são\nJWTs, mas a\n",[52,169,172],{"href":170,"rel":171},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Ftroubleshooting\u002Fauth-error-401-invalid-claim-missing-sub--AFwMR",[56],"página de soluções do Supabase para este erro","\ndiz que o Auth as reconhece e que elas também não trazem o claim sub. Então\nqualquer chave do seu projeto, antiga ou nova, pública ou secreta, produz esta\nmensagem quando é entregue ao Auth como se fosse uma pessoa. A mesma página\naponta o erro com todas as letras: usar sem querer uma chave de API do Supabase\nno lugar do token de acesso do Auth.",[10,175,176,177,181],{},"Se chaves e prefixos são novidade para você,\n",[52,178,180],{"href":179},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","quais chaves de API podem ir no seu frontend","\nexplica como separar a pública da secreta.",[37,183,185],{"id":184},"onde-a-chave-é-enviada-no-lugar-de-uma-sessão","Onde a chave é enviada no lugar de uma sessão",[10,187,188],{},"Três caminhos levam até aqui, e o primeiro é o que uma Edge Function percorre.",[10,190,191,194,195,198,199,202],{},[32,192,193],{},"1. Uma Edge Function chamada de uma página onde ninguém está logado."," Quando\no supabase-js tem uma sessão, ele coloca o token da pessoa no cabeçalho\n",[21,196,197],{},"Authorization",". Quando não tem, não tem mais nada para pôr ali, então com uma\nchave antiga ele manda a chave do seu projeto nesse cabeçalho. O arquivo\n",[21,200,201],{},"fetch.ts"," dele diz exatamente isso: o token de sessão, se houver, senão a\nchave.",[10,204,205,206,210],{},"A verificação Verify JWT da plataforma deixa essa requisição entrar. Uma chave\nantiga é um JWT que o seu projeto assinou, e o Supabase documenta que a\nverificação aceita as chaves novas também: é a brecha que\n",[52,207,209],{"href":208},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","mover um segredo para uma Edge Function","\nexplica por inteiro. A sua função então repassa o cabeçalho ao Auth, que é o que\nestas linhas fazem:",[14,212,217],{"className":213,"code":215,"language":216,"meta":23},[214],"language-ts","const supabase = createClient(\n  Deno.env.get('SUPABASE_URL')!,\n  Deno.env.get('SUPABASE_ANON_KEY')!,\n  { global: { headers: { Authorization: req.headers.get('Authorization')! } } },\n)\nconst { data: { user } } = await supabase.auth.getUser()\n","ts",[21,218,215],{"__ignoreMap":23},[10,220,221,222,225],{},"O Auth lê a chave, encontra a linha do nome vazia e responde 403. Se a função\ndevolve essa falha, o seu app mostra ",[21,223,224],{},"Edge Function returned a non-2xx status code",", com esta mensagem esperando no log da função.",[10,227,228,231,232,235],{},[32,229,230],{},"2. Uma chamada feita antes de o login terminar."," A página de soluções do\nSupabase também aponta este caso: um usuário que começou a se cadastrar ou a\nfazer login e não tinha terminado quando ",[21,233,234],{},"getUser"," foi chamado. Uma forma disso\né um cadastro que ainda espera o e-mail de confirmação. Ainda não há sessão,\nentão o que chegou ao Auth não era o token de uma pessoa.",[10,237,238,241,242,245,246,249,250,253,254,256,257,259],{},[32,239,240],{},"3. O seu próprio servidor entrega o valor errado ao Auth."," Uma rota que chama\n",[21,243,244],{},"getUser(token)"," com a chave em ",[21,247,248],{},"token",", ou uma automação no n8n, no Make ou no\nPostman que chama ",[21,251,252],{},"\u002Fauth\u002Fv1\u002Fuser"," com a chave no cabeçalho ",[21,255,197],{},". A\nsolução que a página do Supabase dá para este caso é garantir que o token\npassado para ",[21,258,91],{}," seja o token de acesso da pessoa.",[98,261],{"alt":262,"caption":263,"src":264},"Uma página sem ninguém logado envia dois crachás vazios idênticos, um marcado apikey e outro Authorization. Os dois passam na verificação da plataforma com um visto e chegam à Edge Function. A função repassa o crachá de Authorization à recepção, que responde 403 com um xis.","Sem ninguém logado, a página manda a mesma chave nos dois cabeçalhos. Toda verificação antes do Auth deixa passar, e só a pergunta do Auth encontra a linha do nome vazia.","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fthe-same-key-twice-1600x760.png",[37,266,268],{"id":267},"como-ver-o-que-a-sua-função-recebeu","Como ver o que a sua função recebeu",[10,270,271],{},"Compare dois cabeçalhos da requisição no seu navegador.",[10,273,274,275,278,279,282],{},"Abra o seu app publicado, aperte F12, escolha a aba ",[32,276,277],{},"Network"," e repita o que\nfalhou. Clique na requisição cujo endereço contém ",[21,280,281],{},"\u002Ffunctions\u002Fv1\u002F"," e o nome da\nsua função, e leia os cabeçalhos da requisição:",[284,285,286,303,314],"ul",{},[287,288,289,302],"li",{},[32,290,291,293,294,297,298,301],{},[21,292,197],{}," traz ",[21,295,296],{},"Bearer"," e depois a mesma sequência que ",[21,299,300],{},"apikey","."," A\npágina não tinha sessão para enviar, então mandou a chave duas vezes. Você\nestá no caminho 1 ou 2.",[287,304,305,313],{},[32,306,307,309,310,301],{},[21,308,197],{}," traz outra sequência longa que começa com ",[21,311,312],{},"eyJ"," O token\nde uma pessoa saiu. A função ou o seu servidor perdeu ele no caminho, então\nvocê está no caminho 3.",[287,315,316,321,322,326,327,330],{},[32,317,318,319,301],{},"Não há cabeçalho ",[21,320,197],{}," Então não é esta a mensagem que você vai\nver. Com o Verify JWT ligado, a plataforma recusa a requisição com um 401\nantes de o seu código rodar, e\n",[52,323,325],{"href":324},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","o post do erro non-2xx","\nlê isso. Desligado, o Auth responde ",[21,328,329],{},"This endpoint requires a valid Bearer token",", a primeira linha da tabela mais abaixo.",[10,332,333,334,337,338,342],{},"Se a mensagem estiver no console do navegador e disser\n",[21,335,336],{},"Auth session missing!",", nenhuma requisição chegou ao Auth: o supabase-js não\nachou sessão nenhuma e parou antes de enviar uma, e\n",[52,339,341],{"href":340},"\u002Fblog\u002Fauth-session-missing","o artigo dela"," cobre esse caso.",[10,344,345],{},"Leia os valores onde estão. Não cole nenhum dos dois num site que se oferece\npara decodificar: a sua chave é pública de qualquer jeito, mas o token de acesso\nde uma pessoa deixa quem o tiver agir como ela até ele expirar.",[37,347,349],{"id":348},"a-solução-perguntar-só-quando-há-alguém-logado","A solução: perguntar só quando há alguém logado",[10,351,352],{},"Decida o que a função deve fazer com um visitante que não fez login, e escreva\nessa decisão na função.",[10,354,355,358,359,361],{},[32,356,357],{},"Se só pessoas logadas devem usá-la,"," duas mudanças. A página chama a função\nsó depois que alguém fez login. E a função responde um 401 claro quando\n",[21,360,91],{}," não encontra usuário, para que uma chamada perdida vinda de uma\npágina sem login receba uma recusa clara em vez de uma pane:",[14,363,366],{"className":364,"code":365,"language":216,"meta":23},[214],"const { data: { user } } = await supabase.auth.getUser()\nif (!user) {\n  return new Response(JSON.stringify({ error: 'Sign in first' }), {\n    status: 401,\n    headers: { ...corsHeaders, 'Content-Type': 'application\u002Fjson' },\n  })\n}\n",[21,367,365],{"__ignoreMap":23},[10,369,370,371,375,376,379,380,383],{},"Mantenha os cabeçalhos CORS nessa resposta também, senão o navegador a esconde\ndo seu app e você dá de cara com\n",[52,372,374],{"href":373},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\"","\nno lugar. O Supabase também oferece um wrapper, ",[21,377,378],{},"withSupabase({ auth: 'user' })",",\nque faz a mesma verificação antes de o seu handler rodar; o\n",[52,381,382],{"href":208},"post da Edge Function"," mostra a\nconfiguração.",[10,385,386,389],{},[32,387,388],{},"Se visitantes sem login também devem usá-la,"," pergunte ao Auth só no caminho\nque precisa de uma pessoa. Trate uma recusa ali como \"isto é um visitante\" e\nsiga com o que um visitante pode fazer, em vez de deixar o erro parar a\nrequisição.",[10,391,392,395,396,399,400,403],{},[32,393,394],{},"No seu próprio servidor,"," mande o token de acesso da pessoa a partir do\nnavegador, como a página do Supabase descreve: coloque ele num cabeçalho\n",[21,397,398],{},"Authorization: Bearer"," da sua requisição, leia no servidor e chame\n",[21,401,402],{},"supabase.auth.getUser(token)"," com esse valor. A chave do seu projeto nunca\nentra nessa chamada.",[37,405,407],{"id":406},"duas-soluções-que-pioram-tudo","Duas soluções que pioram tudo",[10,409,410],{},"As duas são sugeridas para este erro, e as duas deixam você pior do que o erro\ndeixava.",[10,412,413,416,417,419,420,422,423,425,426,301],{},[32,414,415],{},"Trocar pela chave secreta."," Não tem como ajudar, porque ",[21,418,29],{}," e\n",[21,421,166],{}," também não trazem ",[21,424,49],{},", então o Auth responde do mesmo jeito. O\nestrago está em onde a chave vai parar. Peça a um builder para \"usar a chave de\nserviço\" e passar por um erro, e ele pode muito bem colocá-la na página que os\nseus visitantes baixam, onde ela lê e escreve cada linha do seu banco, não\nimporta o que as suas regras digam. Se isso já aconteceu,\n",[52,427,429],{"href":428},"\u002Fblog\u002Frotate-supabase-service-role-key","faça a rotação dela primeiro",[10,431,432,433,301],{},"Esse deslize dá para ver de fora. O nosso scan gratuito lê o JavaScript do seu\napp publicado do jeito que um estranho leria e aponta cada chave que encontra,\ndizendo se ela deveria estar ali. Leva uns 20 segundos e não precisa de conta:\n",[52,434,436],{"href":435},"\u002Fsecurity-scanner","escaneie o seu app",[10,438,439,442,443,446],{},[32,440,441],{},"Apagar a verificação e pegar o id do usuário da requisição."," Uma função que\nlê ",[21,444,445],{},"userId"," do corpo da requisição acredita em quem quer que mande. Se essa\nfunção ainda escreve com a chave secreta, qualquer um que abra a sua página e\nleia como a função é chamada pode agir como qualquer um dos seus usuários, e\nnada nos seus logs diz que não foram eles. Com a verificação no lugar, um\nestranho que tenta a mesma chamada recebe este erro e mais nada.",[37,448,450],{"id":449},"as-outras-mensagens-da-mesma-verificação","As outras mensagens da mesma verificação",[10,452,453],{},"As verificações do Auth rodam numa ordem fixa e cada uma tem a sua frase, então\na mensagem diz até onde o token chegou.",[455,456,457,473],"table",{},[458,459,460],"thead",{},[461,462,463,467,470],"tr",{},[464,465,466],"th",{},"Mensagem",[464,468,469],{},"Status e código",[464,471,472],{},"O que aconteceu",[474,475,476,494,509,523,538,553],"tbody",{},[461,477,478,483,489],{},[479,480,481],"td",{},[21,482,329],{},[479,484,485,486],{},"401 ",[21,487,488],{},"no_authorization",[479,490,491,492,301],{},"Não chegou nenhum cabeçalho ",[21,493,398],{},[461,495,496,501,506],{},[479,497,498],{},[21,499,500],{},"invalid JWT: unable to parse or verify signature, …",[479,502,503,504],{},"403 ",[21,505,75],{},[479,507,508],{},"O carimbo está errado: um token danificado, um de outro projeto ou uma chave antiga.",[461,510,511,516,520],{},[479,512,513],{},[21,514,515],{},"invalid claim: missing sub claim",[479,517,503,518],{},[21,519,75],{},[479,521,522],{},"O carimbo está certo e a linha do nome, vazia: uma chave de API.",[461,524,525,530,535],{},[479,526,527],{},[21,528,529],{},"invalid claim: sub claim must be a UUID",[479,531,532,533],{},"400 ",[21,534,75],{},[479,536,537],{},"Há um nome, mas não no formato de um id de usuário do Supabase.",[461,539,540,545,550],{},[479,541,542],{},[21,543,544],{},"User from sub claim in JWT does not exist",[479,546,503,547],{},[21,548,549],{},"user_not_found",[479,551,552],{},"O token nomeia um usuário que já foi apagado.",[461,554,555,560,565],{},[479,556,557],{},[21,558,559],{},"Session from session_id claim in JWT does not exist",[479,561,503,562],{},[21,563,564],{},"session_not_found",[479,566,567],{},"O token sobreviveu à sua sessão, por exemplo depois de um logout em outro aparelho.",[10,569,570,571,573,574,577,578,582,583,301],{},"Cada linha vem do mesmo arquivo, ",[21,572,68],{},". A versão que o seu\npróprio banco dá para a linha do carimbo errado, ",[21,575,576],{},"PGRST301",", tem\n",[52,579,581],{"href":580},"\u002Fblog\u002Fsupabase-invalid-jwt","um post só dela",". A linha da sessão se lê junto com\n",[52,584,586],{"href":585},"\u002Fblog\u002Fsupabase-users-logged-out","por que os usuários do Supabase são deslogados",[37,588,590],{"id":589},"manter-a-verificação-depois-da-próxima-mudança","Manter a verificação depois da próxima mudança",[10,592,593,596],{},[32,594,595],{},"Uma verificação de quem está chamando pode sumir da próxima vez que você pedir\nao seu builder para fazer um erro sumir",", e os dois jeitos mais rápidos de\ncalar este são os dois aí de cima.",[10,598,599],{},[32,600,601,605],{},[52,602,604],{"href":603},"\u002Fwebsite-monitoring","O Reeve Monitor"," varre o seu app publicado de novo a cada hora:",[284,607,608,611,614,617],{},[287,609,610],{},"as nove verificações a cada hora, em até três apps",[287,612,613],{},"um e-mail no dia em que uma nova varredura avaliar o seu app pior que a anterior; uma chave secreta no seu JavaScript limita sozinha a nota a D",[287,615,616],{},"se o app está no ar, a cada 60 segundos",[287,618,619],{},"um relatório mensal do que ele viu",[10,621,622],{},[32,623,624,625,629],{},"Uma função que acredita no id de usuário que mandam para ela pode mudar as\nlinhas de qualquer um dos seus usuários para quem a chamar.\n",[52,626,628],{"href":627},"\u002Fsupabase-backups","O Reeve Care"," guarda uma cópia do seu banco Supabase de\nantes disso acontecer.",[284,631,632,635,638,641,644],{},[287,633,634],{},"uma cópia criptografada conforme uma agenda, guardada no armazenamento do próprio Reeve na UE, fora da sua conta Supabase",[287,636,637],{},"cada cópia verificada antes de contar, contando as linhas de cada tabela",[287,639,640],{},"uma restauração em um clique que salva o que está lá agora antes de substituir",[287,642,643],{},"também os seus arquivos enviados, assim que você conectar uma credencial de Storage",[287,645,646],{},"tudo o que o Monitor faz",[37,648,650],{"id":649},"o-que-fazer-agora","O que fazer agora",[652,653,654],"key-takeaways",{},[284,655,656,665,671,677,680],{},[287,657,658,659,661,662,664],{},"Abra a requisição que falha na aba Network. Se ",[21,660,197],{}," traz o mesmo valor que ",[21,663,300],{},", ninguém estava logado quando ela foi enviada.",[287,666,667,668,670],{},"Chame funções que precisam de uma pessoa só depois do login, e faça a função responder 401 quando ",[21,669,91],{}," não encontrar usuário.",[287,672,673,674,676],{},"No seu próprio servidor, passe para ",[21,675,91],{}," o token de acesso da pessoa. A chave do seu projeto não tem usuário nenhum dentro.",[287,678,679],{},"Deixe a chave secreta onde está. Ela também não nomeia ninguém, e na página ela lê e escreve cada linha.",[287,681,682],{},"Mantenha a verificação de quem está chamando. Uma função que pega o id do usuário da requisição acredita em qualquer um.",[10,684,685,686,688,689,692,693,697],{},"Se o seu app mostra ",[21,687,224],{}," enquanto esta\nmensagem está no log, a função está repassando a recusa, e\n",[52,690,691],{"href":324},"esse post"," lê a resposta a\npartir daí. O ",[52,694,696],{"href":695},"\u002Fchecklist","checklist de segurança de 10 minutos"," cobre o que mais\num app recém-lançado costuma deixar aberto.",{"title":23,"searchDepth":699,"depth":699,"links":700},3,[701,703,704,705,706,707,708,709,710],{"id":39,"depth":702,"text":40},2,{"id":105,"depth":702,"text":106},{"id":184,"depth":702,"text":185},{"id":267,"depth":702,"text":268},{"id":348,"depth":702,"text":349},{"id":406,"depth":702,"text":407},{"id":449,"depth":702,"text":450},{"id":589,"depth":702,"text":590},{"id":649,"depth":702,"text":650},"Noções de segurança","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcover-1200x630.png","Um crachá num cordão, com um selo autêntico e a linha do nome vazia, na frente de dois crachás que têm nome e rosto.","\"invalid claim: missing sub claim\": o Supabase Auth recebeu um token autêntico sem nenhum usuário, a chave do projeto no lugar de uma sessão.",false,"md",[718,721,724,727,730],{"q":719,"a":720},"O que significa \"invalid claim: missing sub claim\" no Supabase?","Significa que perguntaram ao Supabase Auth qual usuário está chamando e entregaram a ele um token sem usuário nenhum dentro. O token em si era autêntico e passou na verificação de assinatura. O que faltava era o claim sub, o campo que guarda o id de um usuário. É exatamente assim que são as chaves de API do seu projeto, e por isso a causa de costume é uma chave enviada onde deveria ir o token de um usuário logado.",{"q":722,"a":723},"É o mesmo que \"Auth session missing!\"?","Não. \"Auth session missing!\" vem do supabase-js no navegador, que não encontra sessão nenhuma e nem envia a requisição. \"invalid claim: missing sub claim\" volta do Supabase Auth, que recebeu uma requisição e encontrou uma chave onde deveria estar o token do usuário. O primeiro costuma indicar uma página sem login; o segundo, uma função ou um servidor que repassou a chave.",{"q":725,"a":726},"Desligar o Verify JWT resolve?","Não. Verify JWT é uma verificação que o Supabase faz numa Edge Function antes de o seu código começar, e esta mensagem vem depois, do Supabase Auth, quando o seu código pergunta quem está chamando. Desligar a verificação da plataforma deixa chegar ao seu código também as requisições sem token nenhum, e o erro continua exatamente onde estava.",{"q":728,"a":729},"Um login anônimo causa esse erro?","Não. Um login anônimo cria um usuário de verdade com id próprio, então o token dele traz um claim sub e is_anonymous como true. A chave anon é outra coisa, apesar do nome parecido: uma chave de projeto sem usuário dentro, e é ela que produz esta mensagem.",{"q":731,"a":732},"Por que algumas páginas dizem 401 e outras 403?","A página de soluções do Supabase para esta mensagem tem 401 no título. O código atual do Supabase Auth responde 403, com o código de erro bad_jwt. Se o seu código decide o que fazer só pelo status, confira também o código de erro e a mensagem.","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",[735,515,736,737,738,739,740],"invalid claim missing sub claim supabase","AuthApiError invalid claim missing sub claim","bad_jwt supabase","supabase getuser 403","erro getuser supabase edge function","supabase anon key getuser",{},true,"\"invalid claim: missing sub claim\" no Supabase","\u002Fblog\u002Finvalid-claim-missing-sub-claim","2026-11-04",{"title":5,"description":714},"blog\u002Finvalid-claim-missing-sub-claim",[749,750,751],"\"invalid claim: missing sub claim\" é o Supabase Auth respondendo 403 com o código bad_jwt. Perguntaram a ele quem está chamando, o token que recebeu era autêntico e não nomeava ninguém.","A própria página de soluções do Supabase aponta a causa comum: uma chave de API enviada onde deveria ir o token de acesso de um usuário logado. Uma chave diz qual app está chamando e não tem nenhuma pessoa dentro.","Chame a função só quando alguém estiver logado, e faça ela responder 401 quando ninguém estiver. Trocar pela chave secreta não muda nada, porque essa chave também não nomeia ninguém.","h3Fs0ezSxXIRO7tdkb6HCr2D_7ITba_N6RIMEP9ivXo",[754,760,766,772,778,783,784,789,795,801,807,814,820,826,831,837,843,849,855,861,867,873,878,884,890,895,901,907,913,919,925,931,937,943,949,955,960,966,972,978,984,990,996,1002,1008,1014,1019,1025,1031,1037,1043,1049,1055,1061,1067,1073,1079,1085,1091,1097,1103,1109,1115,1121,1126,1132,1138,1144,1150,1156,1162,1168,1174,1180,1186,1192,1198,1204,1210,1216,1222,1228,1234,1240,1245,1251,1257,1263,1268,1274],{"path":755,"title":756,"description":757,"published":758,"category":711,"image":759,"draft":715},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\", explicado","Supabase \"max client connections reached\": o pooler não tem lugar para mais um cliente. A porta da sua string de conexão define o limite.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":761,"title":762,"description":763,"published":764,"category":711,"image":765,"draft":715},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Erro do Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": o Google está desativado no seu projeto Supabase. Como ativar e corrigir o redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":767,"title":768,"description":769,"published":770,"category":711,"image":771,"draft":715},"\u002Fblog\u002Fviolates-foreign-key-constraint","Erro do Supabase \"violates foreign key constraint\" ao inserir","Supabase \"insert or update on table violates foreign key constraint\": sua linha aponta para uma linha que não existe. Qual, por quê, e como corrigir.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":773,"title":774,"description":775,"published":776,"category":711,"image":777,"draft":715},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Erro do Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": uma coluna obrigatória chegou vazia. De onde veio o null, e como corrigir.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":340,"title":779,"description":780,"published":781,"category":711,"image":782,"draft":715},"Supabase \"Auth session missing!\": para onde foi a sessão","\"Auth session missing!\" é o supabase-js sem achar nenhuma sessão logada e sem chegar a perguntar ao Supabase. Para onde foi a sessão, e a correção.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":744,"title":5,"description":714,"published":745,"category":711,"image":733,"draft":715},{"path":373,"title":785,"description":786,"published":787,"category":711,"image":788,"draft":715},"\"Failed to send a request to the Edge Function\": a causa real","\"Failed to send a request to the Edge Function\": o navegador não recebeu uma resposta legível. O console dele diz por quê e se a sua função rodou.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":790,"title":791,"description":792,"published":793,"category":711,"image":794,"draft":715},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Por que o Supabase redireciona links de e-mail para localhost:3000","Se o Supabase redireciona para localhost:3000, a Site URL nunca foi trocada ou o seu endereço falta em Redirect URLs. A solução, e o curinga a evitar.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":796,"title":797,"description":798,"published":799,"category":711,"image":800,"draft":715},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" num link novo","Num link enviado há um minuto, \"Email link is invalid or has expired\" no Supabase costuma significar que um filtro de e-mail o usou antes. Como resolver.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":802,"title":803,"description":804,"published":805,"category":711,"image":806,"draft":715},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\", explicado","Supabase \"canceling statement due to statement timeout\": uma consulta passou do limite do seu papel, 3 segundos para um visitante. Veja antes a política RLS.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":808,"title":809,"description":810,"published":811,"category":812,"image":813,"draft":715},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" no Supabase, e o que vai junto","\"Database error deleting user\" no Supabase: seu banco recusou a exclusão. O motivo está nos seus logs, e a correção decide o que mais é apagado.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":815,"title":816,"description":817,"published":818,"category":711,"image":819,"draft":715},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" no Supabase","O webhook do Stripe numa Edge Function do Supabase diz \"No signatures found matching the expected signature\"? São duas causas. Continue verificando.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":821,"title":822,"description":823,"published":824,"category":711,"image":825,"draft":715},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" no Supabase: as três causas","O Supabase diz \"Invalid login credentials\" para senha errada, e-mail desconhecido e conta Google. Como saber qual é, e por que é vago.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":324,"title":827,"description":828,"published":829,"category":711,"image":830,"draft":715},"\"Edge Function returned a non-2xx status code\": o erro real","\"Edge Function returned a non-2xx status code\" quer dizer que sua função do Supabase respondeu com um erro. Veja onde ler o erro real.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":832,"title":833,"description":834,"published":835,"category":711,"image":836,"draft":715},"\u002Fblog\u002Fcertificate-not-trusted","Certificado não confiável: três causas além do vencimento","Certificado não confiável mesmo com a data certa? Ele cita outro endereço, assinou a si mesmo ou falta um elo na cadeia. Veja como saber qual.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":838,"title":839,"description":840,"published":841,"category":711,"image":842,"draft":715},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": leia as aspas","Supabase \"invalid input syntax for type uuid\": seu app enviou algo que não é um id. Leia as aspas, segure a consulta, mantenha a coluna.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":844,"title":845,"description":846,"published":847,"category":711,"image":848,"draft":715},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\", explicado","Supabase \"duplicate key value violates unique constraint\": o valor já está em uso. Ache a coluna, escolha uma correção e tire o valor da tela.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":850,"title":851,"description":852,"published":853,"category":711,"image":854,"draft":715},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\" e a tabela está lá","Supabase \"relation does not exist\" ou PGRST205: nenhuma tabela tem esse nome nesse schema. Quatro verificações, e o que expor um schema abre.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":856,"title":857,"description":858,"published":859,"category":711,"image":860,"draft":715},"\u002Fblog\u002Fsupabase-function-not-found","Supabase PGRST202: \"Could not find the function in the schema cache\"","Supabase \"Could not find the function in the schema cache\" mostra os nomes de argumentos que seu app enviou. Compare-os com a função.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":862,"title":863,"description":864,"published":865,"category":711,"image":866,"draft":715},"\u002Fblog\u002Fsupabase-schema-cache-column-error","Supabase PGRST204: \"Could not find the column in the schema cache\"","Supabase \"Could not find the column in the schema cache\" costuma ser um nome que não bate. Quatro verificações e a linha que recarrega.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":868,"title":869,"description":870,"published":871,"category":711,"image":872,"draft":715},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": dois limites, um só código","Supabase \"Email Rate Limit Exceeded\" limita cada email que seu projeto envia: 2 por hora no remetente embutido. O que conta e como aumentar.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":585,"title":874,"description":875,"published":876,"category":711,"image":877,"draft":715},"Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 causas","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" desconecta seus usuários. Três causas, e como o log do Auth separa cada uma.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":879,"title":880,"description":881,"published":882,"category":711,"image":883,"draft":715},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": três causas","Supabase \"permission denied for schema public\" é um grant que falta no schema. O que o removeu, e a linha que o devolve.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":885,"title":886,"description":887,"published":888,"category":711,"image":889,"draft":715},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": as três coisas que isso significa","Supabase \"Bucket not found\" é uma de três coisas: um link público para um bucket privado, um nome que não bate exatamente ou o projeto errado.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":580,"title":891,"description":892,"published":893,"category":711,"image":894,"draft":715},"Supabase invalid JWT: qual chave parou de funcionar?","Um erro Supabase invalid JWT é o PGRST301: um token assinado não passou na verificação. Num projeto novo isso é a sessão, não a chave de API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":896,"title":897,"description":898,"published":899,"category":711,"image":900,"draft":715},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" quase sempre é nenhuma","O Supabase devolve PGRST116, \"JSON object requested, multiple (or no) rows returned\", quando a consulta não achou nada. Linha escondida parece ausente.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":902,"title":903,"description":904,"published":905,"category":711,"image":906,"draft":715},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" no Supabase: onde olhar","\"Database error saving new user\" quer dizer que algo preso ao seu cadastro no Supabase falhou e tudo foi desfeito. O erro real está nos seus logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":908,"title":909,"description":910,"published":911,"category":711,"image":912,"draft":715},"\u002Fblog\u002Fwhat-is-supabase","O que é Supabase? O banco de dados que seu builder escolheu","O que é Supabase: o banco de dados, o login e o armazenamento de arquivos do seu app. O Supabase cuida dos servidores; as regras das suas linhas são suas.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":914,"title":915,"description":916,"published":917,"category":711,"image":918,"draft":715},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Uma chave AWS exposta no seu frontend não é como uma chave OpenAI","Uma chave de acesso da AWS exposta no seu frontend lê e grava no seu armazenamento. A solução costuma ser uma presigned URL, não uma chave nova.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":920,"title":921,"description":922,"published":923,"category":711,"image":924,"draft":715},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" ao enviar","\"New row violates row-level security policy for table objects\" quer dizer que o seu envio não tem regra insert. Deixar o bucket público não cria nenhuma.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":926,"title":927,"description":928,"published":929,"category":711,"image":930,"draft":715},"\u002Fblog\u002Fbase44-security-scan","Scan de segurança do Base44: o que só ele enxerga","O scan de segurança do Base44 verifica sete tipos de problema por dentro. Esta é a metade que ele lê e mais ninguém, e a metade que ele nunca olha.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":932,"title":933,"description":934,"published":935,"category":711,"image":936,"draft":715},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Sua chave de API vazou. A ordem em que agir","Uma chave de API vazou e você não sabe o que fazer primeiro. Nem toda chave no seu frontend é um vazamento, e a ordem importa mais que a pressa.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":938,"title":939,"description":940,"published":941,"category":711,"image":942,"draft":715},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" sem desligar o RLS","\"Infinite recursion detected in policy for relation\" significa que a sua policy perguntou à tabela que ela protege. Veja como quebrar o círculo.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":944,"title":945,"description":946,"published":947,"category":711,"image":948,"draft":715},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" no Supabase, e a correção errada","\"No API key found in request\" significa que sua requisição chegou ao Supabase sem chave. Quase toda resposta aponta para as regras do seu banco.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":950,"title":951,"description":952,"published":953,"category":711,"image":954,"draft":715},"\u002Fblog\u002Fis-base44-safe","O Base44 é seguro? O que vimos em 5.442 apps Base44","O Base44 é seguro? Rodamos nove verificações em 5.442 apps Base44 no ar. Quase todas tiraram B por motivos que o dono nunca escolheu.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":208,"title":956,"description":957,"published":958,"category":711,"image":959,"draft":715},"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.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":961,"title":962,"description":963,"published":964,"category":711,"image":965,"draft":715},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Seu arquivo .env está exposto? Os doze caminhos para testar","Seu arquivo .env está exposto no seu próprio servidor web? Doze endereços dizem isso em um minuto, e um acerto significa que tudo nele já é público.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":967,"title":968,"description":969,"published":970,"category":711,"image":971,"draft":715},"\u002Fblog\u002Fis-v0-safe","Segurança do v0: os 1.790 aplicativos v0 escaneados tiraram A","A segurança do v0 medida em 1.790 aplicativos v0 no ar: todos tiraram A. Só 17 citavam um banco de dados, e é sobretudo isso que esse A mede.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":973,"title":974,"description":975,"published":976,"category":711,"image":977,"draft":715},"\u002Fblog\u002Fis-bolt-safe","O Bolt é seguro? O que vimos em 1.123 aplicativos Bolt","O Bolt é seguro? Passamos 1.123 aplicativos Bolt no ar por nove verificações. A hospedagem saiu limpa. Os achados: chaves e tabelas abertas nos aplicativos.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":979,"title":980,"description":981,"published":982,"category":711,"image":983,"draft":715},"\u002Fblog\u002Fis-supabase-down-or-your-app","O Supabase caiu ou o problema é o seu app? Como saber","O Supabase caiu ou o problema é o seu app? Um projeto pausado, um banco cheio e um erro seu parecem iguais. Quatro verificações separam os casos.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":985,"title":986,"description":987,"published":988,"category":711,"image":989,"draft":715},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","O Supabase criptografa meus dados? Sim. Veja o que isso impede","O Supabase criptografa os dados? Sim: AES-256 em repouso, TLS em trânsito, SOC 2 e ISO 27001. O que cada um cobre, e o vazamento que nenhum deles impede.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":991,"title":992,"description":993,"published":994,"category":711,"image":995,"draft":715},"\u002Fblog\u002Fsupabase-free-plan-limits","O Supabase é gratuito? Sim, com estes limites e sem backups","Sim: o plano gratuito do Supabase vai até 500 MB de banco e 5 GB de egress, sem nenhum backup. O que para em cada limite e o que muda no Pro de $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":997,"title":998,"description":999,"published":1000,"category":812,"image":1001,"draft":715},"\u002Fblog\u002Ftest-your-supabase-backup","Teste o backup do seu Supabase antes do dia em que precisar","Como testar o backup do seu Supabase: restaurar num projeto de teste, contar as linhas, entrar e procurar a linha que falta num arquivo cortado.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":1003,"title":1004,"description":1005,"published":1006,"category":812,"image":1007,"draft":715},"\u002Fblog\u002Fsupabase-backup-github-action","Backup grátis do Supabase com uma GitHub Action, e a pegadinha","Um backup do Supabase com GitHub Action é grátis e serve para muitos apps. O workflow, a connection string certa e o egress de cada execução.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":1009,"title":1010,"description":1011,"published":1012,"category":812,"image":1013,"draft":715},"\u002Fblog\u002Fdownload-your-supabase-backup","Por que você não consegue baixar seu backup do Supabase","Você não consegue baixar seu backup do Supabase num projeto atual, porque a cópia diária é um snapshot físico. Como conferir e como ter uma cópia só sua.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":1015,"title":1016,"description":1017,"published":1012,"category":711,"image":1018,"draft":715},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": o grant que falta","A partir de 30 de outubro, uma tabela nova no Supabase responde \"permission denied for table\" até receber um grant. O e-mail mostra só metade.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":1020,"title":1021,"description":1022,"published":1023,"category":711,"image":1024,"draft":715},"\u002Fblog\u002Fopen-api-endpoint-exposed","Um endpoint de API aberto é um problema? Leia o JSON","Seu scan apontou um endpoint de API aberto. Se isso importa depende do que voltou, e a maioria dos que encontramos era da própria plataforma.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":1026,"title":1027,"description":1028,"published":1029,"category":711,"image":1030,"draft":715},"\u002Fblog\u002Flovable-security-scan","Escaneamento de segurança do Lovable: o que ele não prova","Escaneamento de segurança do Lovable: o que o Quick scan e o Deep scan checam, quando cada um roda, e a única coisa que nenhum escaneamento por dentro prova.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":1032,"title":1033,"description":1034,"published":1035,"category":812,"image":1036,"draft":715},"\u002Fblog\u002Fsupabase-backup-auth-users","Por que seu dump do Supabase não tem usuários dentro","Rode supabase db dump sozinho e você recebe a forma do seu banco e nenhuma das linhas dele, sem o schema auth onde seus usuários moram.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":1038,"title":1039,"description":1040,"published":1041,"category":711,"image":1042,"draft":715},"\u002Fblog\u002Fdomain-and-certificate-expiry","Domínio expirado, site fora do ar: o que acontece agora","Seu domínio expirou e seu site está fora do ar. O relógio que começa a correr, por que o certificado é o problema menor, e como conferir os dois.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":1044,"title":1045,"description":1046,"published":1047,"category":711,"image":1048,"draft":715},"\u002Fblog\u002Fis-lovable-safe","O Lovable é seguro? O que vimos em 18.554 aplicativos Lovable","O Lovable é seguro? Passamos 18.554 aplicativos Lovable no ar por nove verificações. A plataforma foi a mais limpa de cinco. Os achados estavam nos aplicativos.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":1050,"title":1051,"description":1052,"published":1053,"category":711,"image":1054,"draft":715},"\u002Fblog\u002Fvibe-coded-app-security-checklist","O checklist de segurança do vibe coding, em nove verificações","Um checklist de segurança do vibe coding com nove itens, cada um verificável no seu app de fora por qualquer pessoa, e cada um com um teste de uma linha.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":1056,"title":1057,"description":1058,"published":1059,"category":711,"image":1060,"draft":715},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Uma chave secreta da Stripe no frontend pode mover dinheiro","Uma chave secreta da Stripe exposta no seu frontend pode reembolsar, cobrar e ler cada ficha de cliente que você tem. Sua chave pk_live_ é que deve estar aí.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":1062,"title":1063,"description":1064,"published":1065,"category":711,"image":1066,"draft":715},"\u002Fblog\u002Fvite-and-next-public-env-vars","Variáveis de ambiente do Vite expostas: o prefixo diz publique isto","Variáveis de ambiente do Vite expostas no seu app: fizeram o que o prefixo pediu. VITE_ e NEXT_PUBLIC_ significam publique isto, e a IA nunca soube o custo.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":1068,"title":1069,"description":1070,"published":1071,"category":711,"image":1072,"draft":715},"\u002Fblog\u002Fbase44-source-maps","Segurança no Base44: o que um scan aponta e o que é seu para corrigir","Segurança no Base44 em 5.438 apps escaneados: três achados em quase todos são da plataforma, o source map é o selo do Base44, e a sua parte é uma lista curta.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":1074,"title":1075,"description":1076,"published":1077,"category":711,"image":1078,"draft":715},"\u002Fblog\u002Fis-cursor-ai-safe","O Cursor AI é seguro? O editor, o código e o app que você publicou","O Cursor AI é seguro? Três perguntas em uma busca: o que o Cursor guarda, o que o código que ele escreve erra, e se o app que você publicou está aberto.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":1080,"title":1081,"description":1082,"published":1083,"category":711,"image":1084,"draft":715},"\u002Fblog\u002Fis-replit-safe","O Replit é seguro? O que vimos em 3.042 aplicativos Replit no ar","O Replit é seguro? Passamos 3.042 aplicativos Replit no ar por nove verificações externas. Os achados estavam no aplicativo publicado, não no host.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":1086,"title":1087,"description":1088,"published":1089,"category":812,"image":1090,"draft":715},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: sua cópia do banco não tem nenhum arquivo","Um Supabase storage backup é uma tarefa à parte. Os backups do banco guardam a lista dos seus arquivos e nenhum deles, então cada upload fica quebrado.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":1092,"title":1093,"description":1094,"published":1095,"category":812,"image":1096,"draft":715},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery do Supabase: preço e limites","O point-in-time recovery do Supabase rebobina seu banco para qualquer segundo da última semana. Custa $100 por mês além do Pro e cobre só o banco.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":1098,"title":1099,"description":1100,"published":1101,"category":812,"image":1102,"draft":715},"\u002Fblog\u002Fsupabase-project-paused-recover","Projeto Supabase pausado? Seus dados continuam lá","O Supabase pausou seu projeto depois de uma semana sem atividade. Nada foi apagado, Restaurar fica ao lado do nome e você tem um ano antes disso mudar.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":1104,"title":1105,"description":1106,"published":1107,"category":711,"image":1108,"draft":715},"\u002Fblog\u002Fsafest-ai-app-builder","Qual builder de apps com IA é mais seguro? 30.998 apps testados","Qual builder de apps com IA é mais seguro? Escaneamos 30.998 apps no ar do Lovable, Base44, Replit, v0 e Bolt. O builder não é o que decide sua nota.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":1110,"title":1111,"description":1112,"published":1113,"category":711,"image":1114,"draft":715},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Ative Row Level Security em toda tabela do Supabase e comprove","Ativar Row Level Security no Supabase sem política fecha a tabela por completo. Uma política sem a chave ligada não faz nada. Aqui está o SQL, e o teste.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":1116,"title":1117,"description":1118,"published":1119,"category":711,"image":1120,"draft":715},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": o que o aviso não vê","O Supabase marca \"RLS disabled in public\" como erro. Ele não diz nada sobre a política de leitura que deixa a sua tabela igualmente aberta.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":428,"title":1122,"description":1123,"published":1124,"category":711,"image":1125,"draft":715},"Como rotacionar uma chave service_role do Supabase vazada","O Supabase manda fechar o vazamento primeiro. Outros guias mandam rotacionar agora. O que vale depende de para onde a sua chave service_role vazou.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":1127,"title":1128,"description":1129,"published":1130,"category":711,"image":1131,"draft":715},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Scanners de segurança para vibe coding comparados, o nosso incluído","O melhor scanner de segurança para vibe coding depende de três perguntas que nenhuma lista de recursos responde. Oito ferramentas comparadas, com preços.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1133,"title":1134,"description":1135,"published":1136,"category":711,"image":1137,"draft":715},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: faça você mesmo as cinco verificações","Um Supabase security checker lê o seu app publicado em vez das configurações do projeto. Aqui estão as cinco verificações e como fazer cada uma sozinho.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":1139,"title":1140,"description":1141,"published":1142,"category":711,"image":1143,"draft":715},"\u002Fblog\u002Fvibe-coding-security-scanner","Scanner de segurança para vibe coding: o que ele não vê","Um scanner de segurança para vibe coding lê seu app no ar, de fora. O que isso cobre, as quatro coisas que ele não consegue ver e como ler o resultado.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1145,"title":1146,"description":1147,"published":1148,"category":711,"image":1149,"draft":715},"\u002Fblog\u002Fmissing-security-headers","Cabeçalhos de segurança faltando: quando isso importa","Cabeçalhos de segurança faltando é o achado que nosso scanner mais imprime. Contra o que eles protegem e quando são a linha menos urgente do relatório.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1151,"title":1152,"description":1153,"published":1154,"category":711,"image":1155,"draft":715},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Sua chave de API da OpenAI está exposta no frontend. Troque-a.","Uma chave de API da OpenAI exposta no frontend não pode ser presa a um domínio. Troque-a hoje, mova a chamada para o seu servidor e limite o gasto.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1157,"title":1158,"description":1159,"published":1160,"category":711,"image":1161,"draft":715},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Chave de API exposta no frontend: o que 30.998 apps entregam","Uma chave de API exposta no seu frontend costuma ser uma chave do Google Maps. Escaneamos 30.998 apps vibe-coded e contamos quais segredos vazam de verdade.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":1163,"title":1164,"description":1165,"published":1166,"category":812,"image":1167,"draft":715},"\u002Fblog\u002Fsupabase-backup-tools-compared","Ferramentas de backup do Supabase comparadas, a nossa incluída","Quatro tipos de ferramenta de backup do Supabase, o que cada uma copia de verdade e quando uma GitHub Action gratuita ganha de pagar, nós inclusive.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1169,"title":1170,"description":1171,"published":1172,"category":711,"image":1173,"draft":715},"\u002Fblog\u002Freplit-secrets-explained","Como usar secrets no Replit, e o que ainda assim é publicado","Como usar secrets no Replit: adicionar um, ler de volta e resolver as duas causas do undefined. E as chaves que a ferramenta Secrets não consegue proteger.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1175,"title":1176,"description":1177,"published":1178,"category":812,"image":1179,"draft":715},"\u002Fblog\u002Fback-up-supabase-free-tier","Backups do plano gratuito do Supabase: como fazer sem terminal","No plano gratuito do Supabase não existe backup nenhum: a cópia é você que faz. Como fazer uma pelo painel e o que a rota do CSV deixa para trás.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1181,"title":1182,"description":1183,"published":1184,"category":711,"image":1185,"draft":715},"\u002Fblog\u002Fis-supabase-secure","O Supabase é seguro? É. Seu projeto é outra pergunta","O Supabase é seguro? A plataforma é auditada, criptografada e passa por pentests. A documentação deles diz onde isso termina e começam suas configurações.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1187,"title":1188,"description":1189,"published":1190,"category":711,"image":1191,"draft":715},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Onde ficam as chaves de API do Supabase: anon, service_role e URL","A URL do projeto, a chave anon e a chave service_role ficam todas numa página do painel. Aqui está onde ela fica, e qual dos quatro valores vai no seu app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1193,"title":1194,"description":1195,"published":1196,"category":711,"image":1197,"draft":715},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy no Supabase. E agora?","\"New row violates row-level security policy\" significa que o Supabase recusou uma escrita. O conserto rápido reabre a tabela para qualquer um.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1199,"title":1200,"description":1201,"published":1202,"category":711,"image":1203,"draft":715},"\u002Fblog\u002Fcors-wildcard-security-risk","Um curinga CORS é um risco de segurança? Quase nunca.","Um curinga CORS é um risco de segurança? Em geral é o padrão do seu builder e não entrega nada que o seu servidor já não desse a qualquer um que pedisse.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1205,"title":1206,"description":1207,"published":1208,"category":812,"image":1209,"draft":715},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Branching do Supabase não é backup. Ele só anda para a frente.","Por que o branching do Supabase não é backup: um branch começa sem os seus dados e um merge só leva o esquema. Para que ele serve e o que usar no lugar.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1211,"title":1212,"description":1213,"published":1214,"category":812,"image":1215,"draft":715},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Como restaurar um backup do Supabase, e o que quebra depois","Como restaurar um backup do Supabase pelo painel ou por um arquivo de dump, o que a restauração substitui e por que o seu app pode continuar quebrado no fim.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1217,"title":1218,"description":1219,"published":1220,"category":711,"image":1221,"draft":715},"\u002Fblog\u002Fsupabase-storage-bucket-public","Seu bucket do Supabase Storage é público. Isso é um problema?","Um bucket público do Supabase Storage significa que quem tem a URL de um arquivo pode abri-lo. Não significa que alguém possa listar o que está lá dentro.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1223,"title":1224,"description":1225,"published":1226,"category":711,"image":1227,"draft":715},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Uma chave de API do Google no frontend é um problema?","Uma chave de API do Google exposta no seu frontend é a chave que nosso scanner mais encontra, e quase sempre está tudo bem. Um ajuste gratuito decide isso.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1229,"title":1230,"description":1231,"published":1232,"category":812,"image":1233,"draft":715},"\u002Fblog\u002Fai-agent-deleted-my-database","Um agente de IA apagou meus dados do Supabase. O que eu recupero?","Um agente de IA apagou dados do seu banco. O que você recupera já estava decidido antes de ele rodar, e os próximos minutos decidem o resto.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1235,"title":1236,"description":1237,"published":1238,"category":711,"image":1239,"draft":715},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Qualquer um consegue ler seu banco Supabase? Testamos 3.680 apps","Qualquer um consegue ler seu banco de dados Supabase sem fazer login? Escaneamos 30.998 apps no ar criadas com builders de IA e medimos quantas dizem que sim.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1241,"title":1242,"description":1243,"published":1238,"category":711,"image":1244,"draft":715},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source maps expostos: seu app está publicando o código original","Um source map exposto deixa qualquer um ler o código original do seu app, comentários incluídos. A verificação de 30 segundos e o que importa de verdade.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1246,"title":1247,"description":1248,"published":1249,"category":711,"image":1250,"draft":715},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: é a mesma coisa que a anon key?","O Supabase trocou anon e service_role por chaves publicáveis e secretas. Qual delas pertence ao seu app e qual nunca deve estar lá?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1252,"title":1253,"description":1254,"published":1255,"category":812,"image":1256,"draft":715},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","O Supabase faz backup do meu banco de dados? Depende do plano.","O Supabase faz backup do seu banco de dados? Todo dia nos planos pagos, e nada no gratuito. Como descobrir o que você tem e o que essa cópia não cobre.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1258,"title":1259,"description":1260,"published":1261,"category":711,"image":1262,"draft":715},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","O Supabase Row Level Security está ligado. A tabela continua pública.","Ligar o Supabase Row Level Security não protege uma tabela. Quem protege são as políticas, e a que consertou o seu app pode deixar qualquer um entrar.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1264,"title":1265,"description":1266,"published":1261,"category":812,"image":1267,"draft":715},"\u002Fblog\u002Fversion-history-is-not-a-backup","O histórico de versões não é backup. Ele não desfaz um delete.","Lovable e Bolt guardam um histórico de versões do seu código. Seu banco de dados é um serviço à parte, e voltar atrás não traz os seus dados de volta.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1269,"title":1270,"description":1271,"published":1272,"category":812,"image":1273,"draft":715},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Três formas de fazer backup de um banco Supabase, e o que falta","O painel, o pg_dump e um serviço gerenciado. O que cada um salva de verdade, o que deixa de fora sem avisar e qual sobrevive a perder a conta.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":179,"title":1275,"description":1276,"published":1272,"category":711,"image":1277,"draft":715},"Quais chaves de API são seguras no navegador e quais não são","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.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213648755]