[{"data":1,"prerenderedAt":1130},["ShallowReactive",2],{"blog-pt-supabase-invalid-jwt":3,"blog-index-pt":604},{"id":4,"title":5,"body":6,"category":562,"cover":563,"coverAlt":564,"description":565,"draft":566,"extension":567,"faq":568,"image":584,"keywords":585,"meta":593,"navigation":594,"ogTitle":5,"path":595,"published":596,"seo":597,"stem":598,"tldr":599,"updated":596,"__hash__":603},"blog_pt\u002Fblog\u002Fsupabase-invalid-jwt.md","Supabase invalid JWT: qual chave parou de funcionar?",{"type":7,"value":8,"toc":549},"minimark",[9,13,24,27,39,44,47,50,53,56,62,66,73,87,167,172,179,200,207,211,221,233,236,262,267,270,282,293,297,300,312,328,332,335,367,371,374,396,399,406,410,413,429,432,440,443,447,453,463,477,487,504,508,537],[10,11,12],"p",{},"Ontem seu aplicativo funcionava. Hoje de manhã toda requisição volta com 401,\nnada mudou no seu código, e a resposta fala de um JWT, uma coisa que você nunca\ndigitou em lugar nenhum.",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","{\n  \"code\": \"PGRST301\",\n  \"message\": \"JWT cryptographic operation failed\"\n}\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26],{},"Um erro Supabase invalid JWT é aquele que aparece depois que você fez a coisa\ncerta. Você trocou uma chave porque um guia mandou, ou migrou seu projeto para as\nchaves novas, e o aplicativo ficou mudo.",[10,28,29,30,34,35,38],{},"E é aqui que guia após guia erra: ",[31,32,33],"strong",{},"a chave de que esta mensagem fala muitas\nvezes não é a que você acabou de trocar."," Pesquise o erro e vão mandar você\nconferir sua chave ",[21,36,37],{},"anon",". Num projeto que migrou para as chaves publishable e\nsecret, a chave de API não é um token assinado de jeito nenhum, então o que\nfalhou na verificação era outra coisa na requisição.",[40,41,43],"h2",{"id":42},"o-que-significa-um-erro-supabase-invalid-jwt","O que significa um erro Supabase invalid JWT?",[10,45,46],{},"Alguma coisa na sua requisição era um token assinado, e a assinatura não bateu.",[10,48,49],{},"Uma senha é uma palavra que alguém procura numa lista. Um JWT não é isso. É uma\ncarta fechada com lacre: a pessoa na porta não procura você em lugar nenhum, ela\nsegura um sinete e confere se o lacre da sua carta foi feito com ele. Se foi,\nvocê passa, e ninguém lê lista nenhuma.",[10,51,52],{},"Uma carta lacrada com o sinete errado é recusada mesmo com cada palavra certa lá\ndentro. E no momento em que a porta troca de sinete, nenhuma carta que já está a\ncaminho abre mais, sem que ninguém tenha encostado nas cartas.",[10,54,55],{},"Sua requisição é a carta. Seu projeto do Supabase segura o sinete. Um 401 aqui\nquer dizer que os dois não combinaram.",[57,58],"diagram",{"alt":59,"caption":60,"src":61},"Duas pistas levando cada uma uma carta lacrada ao mesmo sinete, gravado com uma marca de três raios. Em cima o lacre da carta traz a mesma marca, a carta passa, a tabela ao fundo mostra três linhas acesas e a resposta é 200. Embaixo o lacre traz um ponto dentro de um quadrado, uma barra âmbar detém a carta, a tabela ao fundo é um contorno pontilhado vazio e a resposta é 401.","Nada é procurado numa lista. O lacre do token é comparado com o sinete que seu projeto guarda, e uma carta cujo lacre veio de outra coisa é recusada diga o que disser por dentro.","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fhow-the-check-works-1600x660.png",[40,63,65],{"id":64},"a-mensagem-mudou-no-postgrest-13-e-o-código-não","A mensagem mudou no PostgREST 13 e o código não",[10,67,68,69,72],{},"Teste por ",[21,70,71],{},"PGRST301",". A frase ao lado depende da versão do PostgREST que seu\nprojeto roda, e as mais novas dão uma lista curta delas.",[10,74,75,76,78,79,82,83,86],{},"A referência de erros do PostgREST descreve ",[21,77,71],{}," como um JWT recebido que\nnão pôde ser decodificado ou que é inválido, em HTTP 401, tanto na versão 13\nquanto na 14. Essa frase é a descrição da tabela de documentação. Não é o que\naterrissa no seu campo ",[21,80,81],{},"message",". Lendo o ",[21,84,85],{},"Error.hs"," no branch main do PostgREST,\nesse campo traz uma destas:",[88,89,90,103],"table",{},[91,92,93],"thead",{},[94,95,96,100],"tr",{},[97,98,99],"th",{},"O que a mensagem diz",[97,101,102],{},"O que isso diz a você",[104,105,106,117,127,137,147,157],"tbody",{},[94,107,108,114],{},[109,110,111],"td",{},[21,112,113],{},"Empty JWT is sent in Authorization header",[109,115,116],{},"O cabeçalho foi enviado e veio vazio.",[94,118,119,124],{},[109,120,121],{},[21,122,123],{},"Expected 3 parts in JWT; got 1",[109,125,126],{},"O que chegou não é um JWT. Um JWT são três blocos separados por pontos.",[94,128,129,134],{},[109,130,131],{},[21,132,133],{},"No suitable key or wrong key type",[109,135,136],{},"O servidor não tem nenhuma chave capaz de verificar um token desse tipo.",[94,138,139,144],{},[109,140,141],{},[21,142,143],{},"Wrong or unsupported encoding algorithm",[109,145,146],{},"O token nomeia um algoritmo de assinatura que o servidor não usa.",[94,148,149,154],{},[109,150,151],{},[21,152,153],{},"JWT cryptographic operation failed",[109,155,156],{},"O token está bem formado e a assinatura não bate.",[94,158,159,164],{},[109,160,161],{},[21,162,163],{},"Unsupported token type",[109,165,166],{},"O token tem um formato que o PostgREST não lê.",[10,168,169,171],{},[21,170,153],{}," é o que quer dizer chave velha. O token foi\nmontado certo e assinado por algo que o projeto não guarda mais, que é\nexatamente o que uma rotação deixa para trás.",[10,173,174,175,178],{},"Projetos antigos veem coisa bem diferente, e daí vem a cadeia que aparece em todo\ncanto nos resultados de busca. Antes da versão 13, o PostgREST imprimia o que a\nbiblioteca de JWT tinha dito, exatamente como ela disse. É daí que sai\n",[21,176,177],{},"JWSError JWSInvalidSignature",": é um valor de biblioteca impresso na tela, não\numa frase que alguém escreveu para você. O changelog do PostgREST para a 13.0.0\ndescreve a mudança como mensagens de erro diagnósticas no lugar de internos\nexpostos.",[180,181,183],"callout",{"type":182},"warn",[10,184,185,188,189,192,193,195,196,199],{},[31,186,187],{},"Se o seu código compara o texto da mensagem, compare o código no lugar."," Uma\nchecagem que mede ",[21,190,191],{},"error.message"," contra ",[21,194,177],{}," funciona\nhoje e para de funcionar no dia em que seu projeto passar para um PostgREST mais\nnovo, sem nenhum deploy seu no meio. O Supabase diz o mesmo na documentação de\nerros dele: use ",[21,197,198],{},"error.code"," e não compare mensagens de erro como texto.",[10,201,202,203,206],{},"Vale conhecer um código vizinho enquanto você está por aqui. ",[21,204,205],{},"PGRST303",", também\n401, é o que você recebe quando a assinatura foi verificada e o conteúdo do token\nfoi recusado: expirado, ainda não válido, ou com a audiência errada. Se for esse\no seu código, pare de olhar as chaves e vá olhar o relógio e a sessão.",[40,208,210],{"id":209},"qual-chave-é-a-de-api-ou-o-token-do-seu-usuário","Qual chave é: a de API ou o token do seu usuário?",[10,212,213,214,216,217,220],{},"Depende de se o seu projeto ainda usa ",[21,215,37],{}," e ",[21,218,219],{},"service_role",".",[10,222,223,224,216,226,228,229,232],{},"A documentação do Supabase sobre chaves de API é explícita quanto à diferença. As\nchaves antigas ",[21,225,37],{},[21,227,219],{}," são JWT de longa duração, e é por isso que\ncomeçam com ",[21,230,231],{},"eyJ",". As chaves publishable e secret mais novas são cadeias curtas e\nnão são JWT de jeito nenhum.",[10,234,235],{},"Esse único fato parte o erro em dois:",[237,238,239,250],"ul",{},[240,241,242,249],"li",{},[31,243,244,245,216,247,220],{},"Seu projeto ainda usa ",[21,246,37],{},[21,248,219],{}," A chave de API da sua\nrequisição é ela mesma um token assinado, então uma chave de outro projeto, uma\nchave de antes da rotação ou uma colagem cortada falham na verificação de\nassinatura exatamente como falharia uma sessão ruim. Qualquer um dos dois\ntokens da requisição pode ser o que falhou.",[240,251,252,261],{},[31,253,254,255,216,258,220],{},"Seu projeto migrou para ",[21,256,257],{},"sb_publishable_",[21,259,260],{},"sb_secret_"," A chave de API\ndeixou de ser um token, então não há assinatura nela para nada rejeitar. O que\nresta verificar é o token de acesso do seu usuário logado, que o Supabase Auth\nemite separado da chave de API.",[57,263],{"alt":264,"caption":265,"src":266},"Duas fileiras, cada uma terminando num sinete. Na fileira de cima, uma carta lacrada com a etiqueta anon e uma segunda carta lacrada ao lado de uma pessoa vão as duas até o sinete. Na fileira de baixo, um cartão liso com a etiqueta sb_publishable_ não tem lacre nem linha, e só a carta lacrada ao lado da pessoa vai até o sinete.","Num projeto antigo chegam duas cartas lacradas e qualquer uma das duas pode ser a recusada. Depois da migração para as chaves novas, a chave de API não carrega mais lacre, e a sessão do seu usuário logado é a única coisa que ainda tem assinatura.","\u002Fblog\u002Fsupabase-invalid-jwt\u002Ftwo-things-called-your-key-1600x820.png",[10,268,269],{},"Na prática, a primeira pergunta não é qual chave está errada. É se havia alguém\nlogado quando a requisição falhou. Se uma página sem login funciona e uma com\nlogin não, você está olhando sessões. Se tudo falha, inclusive uma página que não\npede nada pessoal, você está olhando a chave de API, e seu projeto é dos antigos.",[10,271,272,273,276,277,220],{},"Se forem sessões e seu log do Auth também disser ",[21,274,275],{},"Invalid Refresh Token",", seus\nusuários estão sendo desconectados porque\n",[278,279,281],"a",{"href":280},"\u002Fblog\u002Fsupabase-users-logged-out","a sessão por trás do token deles terminou",[10,283,284,285,288,289,220],{},"Se a resposta veio do Supabase Auth e diz ",[21,286,287],{},"invalid claim: missing sub claim",", o\ntoken passou na verificação da assinatura e não nomeava ninguém. É uma chave\nenviada onde deveria ir o token de uma pessoa, e\n",[278,290,292],{"href":291},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","essa mensagem tem um post próprio",[40,294,296],{"id":295},"invalid-jwt-não-é-no-api-key-found-in-request","Invalid JWT não é \"No API key found in request\"",[10,298,299],{},"São duas mensagens diferentes com duas causas diferentes, e as correções não têm\nnada em comum.",[10,301,302,303,307,308,311],{},"Um invalid JWT quer dizer que um token chegou e a assinatura não bateu. ",[278,304,306],{"href":305},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API\nkey found in request\""," quer dizer que nenhum\ncabeçalho ",[21,309,310],{},"apikey"," chegou, então a requisição foi recusada no gateway antes de\nqualquer coisa ser perguntada ao seu banco.",[10,313,314,315,317,318,321,322,324,325,327],{},"A própria resposta resolve qual dos dois é. Uma chave faltando é recusada pelo\ngateway na frente do seu projeto, então o corpo traz um ",[21,316,81],{}," e um ",[21,319,320],{},"hint"," e\nnenhum ",[21,323,21],{},". Um invalid JWT foi longe o bastante para ser lido pelo PostgREST,\ne por isso volta com ",[21,326,71],{}," escrito nele.",[40,329,331],{"id":330},"onde-a-chave-antiga-ainda-está-por-ordem","Onde a chave antiga ainda está, por ordem",[10,333,334],{},"Quatro lugares, e vale conferir nesta ordem porque é mais ou menos a frequência\ncom que cada um é a resposta.",[336,337,338,344,355,361],"ol",{},[240,339,340,343],{},[31,341,342],{},"As configurações de projeto da sua ferramenta."," Lovable, Bolt, v0 e Replit\nguardam cada um o próprio conjunto de variáveis de ambiente, e se você\nconstruiu com Cursor ou Claude Code o mesmo conjunto fica onde você faz o\ndeploy. É a cópia que quase todo mundo atualiza, e a única que quase todo\nmundo atualiza.",[240,345,346,349,350,354],{},[31,347,348],{},"Uma chave escrita direto no código."," Ela viaja dentro do JavaScript que\nseus visitantes baixam, então mudá-la no painel não muda nada até o arquivo\nser editado e o site reconstruído. ",[278,351,353],{"href":352},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Onde fica essa página e o que cada valor\nnela faz",", se você ainda não abriu.",[240,356,357,360],{},[31,358,359],{},"Secrets de Edge Function."," Uma função guarda o próprio conjunto, separado\ndo do seu frontend, e continua usando a chave antiga depois que todo o resto\njá mudou. O Supabase também avisa que uma função com a opção Verify JWT ligada\npode quebrar ao rotacionar uma chave de assinatura.",[240,362,363,366],{},[31,364,365],{},"Um deploy que ninguém reconstruiu."," A chave ficou embutida na última\nconstrução, então a cópia no ar continua mandando ela até algo disparar uma\nnova. Seu painel mostra a chave nova esse tempo todo, e é isso que torna este\ncaso difícil de ver: o lugar onde você vai conferir é o único que já está\ncerto.",[40,368,370],{"id":369},"qual-chave-seu-aplicativo-em-produção-manda-de-verdade","Qual chave seu aplicativo em produção manda de verdade",[10,372,373],{},"Abra o site publicado em vez da prévia e leia o que a página manda.",[10,375,376,377,379,380,382,383,385,386,390,391,395],{},"Uma chave antiga do Supabase é uma cadeia longa começando com ",[21,378,231],{},". As mais\nnovas se anunciam nos primeiros caracteres: ",[21,381,257],{}," pertence ao seu\naplicativo e ",[21,384,260],{}," nunca. Se você encontrar a segunda numa página que um\nvisitante consegue carregar, pare este artigo e\n",[278,387,389],{"href":388},"\u002Fblog\u002Frotate-supabase-service-role-key","troque ela"," antes de qualquer outra\ncoisa. Qual das duas você tem, e\n",[278,392,394],{"href":393},"\u002Fblog\u002Fsupabase-new-api-keys","o que mudou quando o Supabase renomeou as duas",",\nsão coisas a resolver antes de começar a substituir valores.",[10,397,398],{},"Para ver o que seu projeto emite agora: todas as chaves ficam num lugar só no\npainel, em Settings e depois API Keys, as antigas inclusive.",[10,400,401,402,220],{},"Se você prefere não ler um bundle minificado, nosso escaneamento gratuito lê seu\naplicativo em produção como um estranho leria e aponta as chaves visíveis de\nfora. Leva uns 20 segundos e não precisa de conta:\n",[278,403,405],{"href":404},"\u002Fsecurity-scanner","escanear seu aplicativo",[40,407,409],{"id":408},"rotacionar-uma-chave-de-assinatura-sem-deslogar-todo-mundo","Rotacionar uma chave de assinatura sem deslogar todo mundo",[10,411,412],{},"Qual dos dois caminhos de rotação você segue decide se seus usuários percebem.",[10,414,415,416,419,420,216,422,424,425,428],{},"A documentação do Supabase sobre chaves de assinatura põe os dois lado a lado.\nRotacionar o ",[31,417,418],{},"secret JWT antigo"," desloga na hora todos os usuários ativos, e\n",[21,421,37],{},[21,423,219],{}," precisam ser rotacionadas ao mesmo tempo. As ",[31,426,427],{},"JWT\nsigning keys"," mais novas funcionam de outro jeito: uma chave nova começa como\nstandby, a rotação a torna a atual, e a que ela substitui passa a ser a anterior.\nEnquanto for assim, assinaturas das duas chaves continuam sendo aceitas, e as\ncartas lacradas semana passada ainda abrem. Revogar a chave antiga é o passo\nseparado que encerra isso.",[10,430,431],{},"Dois avisos nessa mesma documentação são os que pegam as pessoas:",[237,433,434,437],{},[240,435,436],{},"Um componente que verifica tokens por conta própria contra o secret JWT antigo,\ncom uma biblioteca como jose ou jsonwebtoken, quebra na rotação. Ele segura o\nsinete velho e ninguém disse para ele trocar.",[240,438,439],{},"Uma Edge Function com Verify JWT ligada pode quebrar pelo mesmo motivo.",[10,441,442],{},"Criar chaves publishable e secret também não revoga suas chaves antigas. Elas\ncontinuam funcionando até você desativá-las, o que a documentação marca como um\npasso à parte. Então um aplicativo que migrou só metade das cópias segue\nfuncionando por semanas, e o dia em que alguém desativa o par antigo é o dia em\nque a outra metade começa a responder 401.",[40,444,446],{"id":445},"ficar-de-olho-num-aplicativo-que-começou-a-responder-401","Ficar de olho num aplicativo que começou a responder 401",[10,448,449,452],{},[31,450,451],{},"Um aplicativo que devolve 401 em toda requisição continua no ar, continua\nservindo uma página e continua respondendo a qualquer checagem de saúde."," Nada\nfica vermelho no seu painel. Você descobre quando alguém te escreve.",[10,454,455],{},[31,456,457,458,462],{},"O ",[278,459,461],{"href":460},"\u002Fwebsite-monitoring","Reeve Monitor"," descobre primeiro:",[237,464,465,468,471,474],{},[240,466,467],{},"as nove verificações a cada hora, em até três aplicativos",[240,469,470],{},"um e-mail no dia em que um novo escaneamento dá uma nota pior que a anterior",[240,472,473],{},"se o aplicativo responde, a cada 60 segundos",[240,475,476],{},"um relatório mensal do que ele viu",[10,478,479],{},[31,480,481,482,486],{},"Uma chave que você teve de trocar com pressa costuma ser uma chave que estava\nonde não devia, e daqui você não enxerga o que foi lido ou alterado com ela\nenquanto ela esteve fora. O ",[278,483,485],{"href":484},"\u002Fsupabase-backups","Reeve Care"," guarda uma cópia do\nseu banco de dados Supabase de antes disso.",[237,488,489,492,495,498,501],{},[240,490,491],{},"uma cópia criptografada conforme um calendário, guardada no armazenamento do próprio Reeve na UE, fora da sua conta Supabase",[240,493,494],{},"cada cópia verificada antes de contar, contando as linhas de cada tabela",[240,496,497],{},"uma restauração em um clique que salva o estado atual antes de substituí-lo",[240,499,500],{},"seus arquivos enviados também, assim que você conectar um acesso de Storage",[240,502,503],{},"tudo o que o Monitor faz",[40,505,507],{"id":506},"o-que-fazer-hoje","O que fazer hoje",[509,510,511],"key-takeaways",{},[237,512,513,525,528,531,534],{},[240,514,515,516,518,519,521,522,524],{},"Leia o campo ",[21,517,21],{},", não a frase. ",[21,520,71],{}," é uma assinatura que não bateu, ",[21,523,205],{}," é um token cujo conteúdo foi recusado, como um expirado.",[240,526,527],{},"Descubra qual token falhou antes de trocar qualquer chave. Se as páginas sem login funcionam e as com login não, é uma sessão e não sua chave de API.",[240,529,530],{},"Confira os quatro lugares onde a chave antiga se esconde: as configurações da ferramenta, o próprio código, os secrets de Edge Function e um deploy que ninguém reconstruiu.",[240,532,533],{},"Faça a rotação de uma sentada. Cada cópia deixada para trás é um aplicativo funcionando pela metade, e o site no ar continua mandando a chave antiga até ser reconstruído.",[240,535,536],{},"Nas chaves de assinatura novas, revogar é o passo que de fato encerra as assinaturas antigas. Rotacionar sozinho deixa elas aceitas.",[10,538,539,540,543,544,548],{},"Comece perguntando se uma página sem login ainda carrega, porque essa única\nresposta decide qual metade deste artigo é a sua. Se aparecer uma chave secreta\nexposta, ",[278,541,542],{"href":388},"trocá-la"," cobre a ordem em que\nagir, e\n",[278,545,547],{"href":546},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","quais chaves algum dia foram seguras de\npublicar"," conta por que as duas\nficaram tão parecidas.",{"title":23,"searchDepth":550,"depth":550,"links":551},3,[552,554,555,556,557,558,559,560,561],{"id":42,"depth":553,"text":43},2,{"id":64,"depth":553,"text":65},{"id":209,"depth":553,"text":210},{"id":295,"depth":553,"text":296},{"id":330,"depth":553,"text":331},{"id":369,"depth":553,"text":370},{"id":408,"depth":553,"text":409},{"id":445,"depth":553,"text":446},{"id":506,"depth":553,"text":507},"Noções de segurança","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcover-1200x630.png","Uma carta lacrada diante de um sinete cuja gravação já não combina com o lacre, e outras cartas atrás de uma barra âmbar.","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.",false,"md",[569,572,575,578,581],{"q":570,"a":571},"O que significa PGRST301?","PGRST301 é o PostgREST respondendo HTTP 401 porque não conseguiu verificar um token assinado que seguia na sua requisição. O PostgREST é o servidor que transforma suas tabelas do Supabase na API HTTP com que seu aplicativo conversa. A referência de erros dele descreve o código como um JWT recebido que não pôde ser decodificado ou que é inválido, e a partir da versão 13 o campo message traz uma frase mais específica sobre qual parte da verificação falhou.",{"q":573,"a":574},"Por que recebo 401 depois de trocar minha chave do Supabase?","Porque alguma cópia da chave antiga continua sendo enviada. Os lugares de sempre são as configurações de projeto da sua ferramenta, uma chave escrita direto no código, um secret de Edge Function e um deploy que foi construído antes da troca e nunca mais reconstruído. Um token assinado por uma chave que o servidor não aceita mais não passa na verificação, e isso chega até você como 401 em toda requisição em vez de como um aviso sobre a chave.",{"q":576,"a":577},"Qual a diferença para No API key found in request?","São duas mensagens diferentes com causas diferentes. No API key found in request significa que a requisição chegou sem nenhum cabeçalho apikey e foi recusada no gateway antes de o banco ser consultado. Um invalid JWT significa que o token estava lá e a assinatura não bateu. O primeiro é uma carta sem endereço, o segundo é uma carta com o lacre errado.",{"q":579,"a":580},"Preciso atualizar minhas Edge Functions também?","Sim, e é a cópia que mais se esquece, porque uma Edge Function guarda os próprios secrets, separados dos que seu frontend usa. O Supabase também avisa que uma função com a opção Verify JWT ligada pode quebrar ao rotacionar uma chave de assinatura, e que qualquer componente que verifique tokens por conta própria contra o secret JWT antigo vai quebrar pelo mesmo motivo.",{"q":582,"a":583},"Como vejo qual chave meu aplicativo em produção realmente envia?","Abra o site publicado, não a prévia, e veja o que a página envia de fato. Uma chave antiga do Supabase é uma cadeia longa começando com eyJ, e as mais novas começam com sb_publishable_ ou sb_secret_. Nosso escaneamento gratuito lê um aplicativo em produção como um estranho leria e aponta as chaves visíveis de fora, o que também mostra se uma antiga ainda está sendo enviada.","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",[586,587,588,589,590,591,592],"supabase invalid jwt","pgrst301","bad_jwt supabase","supabase 401 depois de trocar a chave","jwsinvalidsignature supabase","chave antiga do supabase parou de funcionar","provided jwt could not be decoded",{},true,"\u002Fblog\u002Fsupabase-invalid-jwt","2026-10-16",{"title":5,"description":565},"blog\u002Fsupabase-invalid-jwt",[600,601,602],"Um erro Supabase invalid JWT chega como PGRST301 com HTTP 401, e significa que a assinatura do token que seguiu na sua requisição não pôde ser verificada. Nada foi procurado numa lista e recusado.","As chaves publishable e secret são cadeias curtas sem assinatura, então num projeto que já migrou para elas este erro fala do seu usuário logado e nunca da chave de API.","O PostgREST 13 trocou uma frase vaga por uma lista curta de frases concretas. Leia a mensagem que você recebeu de fato: cada uma descarta uma causa diferente.","R3a88L8sEZtaB9SGGdDX9lA_zsV7Argr7hmnlH_Ze_c",[605,611,617,623,629,635,640,646,652,658,664,671,677,683,689,695,701,707,713,719,725,731,736,742,748,749,755,761,767,773,779,785,791,797,802,808,814,820,826,832,838,844,850,856,862,868,873,879,885,891,897,903,909,915,921,927,933,939,945,951,957,963,969,975,980,986,992,998,1004,1010,1016,1022,1028,1034,1040,1045,1051,1057,1063,1069,1075,1081,1087,1093,1098,1103,1109,1115,1120,1126],{"path":606,"title":607,"description":608,"published":609,"category":562,"image":610,"draft":566},"\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":612,"title":613,"description":614,"published":615,"category":562,"image":616,"draft":566},"\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":618,"title":619,"description":620,"published":621,"category":562,"image":622,"draft":566},"\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":624,"title":625,"description":626,"published":627,"category":562,"image":628,"draft":566},"\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":630,"title":631,"description":632,"published":633,"category":562,"image":634,"draft":566},"\u002Fblog\u002Fauth-session-missing","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":291,"title":636,"description":637,"published":638,"category":562,"image":639,"draft":566},"Supabase \"invalid claim: missing sub claim\": ninguém está logado","\"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.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":641,"title":642,"description":643,"published":644,"category":562,"image":645,"draft":566},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"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":647,"title":648,"description":649,"published":650,"category":562,"image":651,"draft":566},"\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":653,"title":654,"description":655,"published":656,"category":562,"image":657,"draft":566},"\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":659,"title":660,"description":661,"published":662,"category":562,"image":663,"draft":566},"\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":665,"title":666,"description":667,"published":668,"category":669,"image":670,"draft":566},"\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":672,"title":673,"description":674,"published":675,"category":562,"image":676,"draft":566},"\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":678,"title":679,"description":680,"published":681,"category":562,"image":682,"draft":566},"\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":684,"title":685,"description":686,"published":687,"category":562,"image":688,"draft":566},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"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":690,"title":691,"description":692,"published":693,"category":562,"image":694,"draft":566},"\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":696,"title":697,"description":698,"published":699,"category":562,"image":700,"draft":566},"\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":702,"title":703,"description":704,"published":705,"category":562,"image":706,"draft":566},"\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":708,"title":709,"description":710,"published":711,"category":562,"image":712,"draft":566},"\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":714,"title":715,"description":716,"published":717,"category":562,"image":718,"draft":566},"\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":720,"title":721,"description":722,"published":723,"category":562,"image":724,"draft":566},"\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":726,"title":727,"description":728,"published":729,"category":562,"image":730,"draft":566},"\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":280,"title":732,"description":733,"published":734,"category":562,"image":735,"draft":566},"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":737,"title":738,"description":739,"published":740,"category":562,"image":741,"draft":566},"\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":743,"title":744,"description":745,"published":746,"category":562,"image":747,"draft":566},"\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":595,"title":5,"description":565,"published":596,"category":562,"image":584,"draft":566},{"path":750,"title":751,"description":752,"published":753,"category":562,"image":754,"draft":566},"\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":756,"title":757,"description":758,"published":759,"category":562,"image":760,"draft":566},"\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":762,"title":763,"description":764,"published":765,"category":562,"image":766,"draft":566},"\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":768,"title":769,"description":770,"published":771,"category":562,"image":772,"draft":566},"\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":774,"title":775,"description":776,"published":777,"category":562,"image":778,"draft":566},"\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":780,"title":781,"description":782,"published":783,"category":562,"image":784,"draft":566},"\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":786,"title":787,"description":788,"published":789,"category":562,"image":790,"draft":566},"\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":792,"title":793,"description":794,"published":795,"category":562,"image":796,"draft":566},"\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":305,"title":798,"description":799,"published":800,"category":562,"image":801,"draft":566},"\"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":803,"title":804,"description":805,"published":806,"category":562,"image":807,"draft":566},"\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":809,"title":810,"description":811,"published":812,"category":562,"image":813,"draft":566},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","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":815,"title":816,"description":817,"published":818,"category":562,"image":819,"draft":566},"\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":821,"title":822,"description":823,"published":824,"category":562,"image":825,"draft":566},"\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":827,"title":828,"description":829,"published":830,"category":562,"image":831,"draft":566},"\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":833,"title":834,"description":835,"published":836,"category":562,"image":837,"draft":566},"\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":839,"title":840,"description":841,"published":842,"category":562,"image":843,"draft":566},"\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":845,"title":846,"description":847,"published":848,"category":562,"image":849,"draft":566},"\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":851,"title":852,"description":853,"published":854,"category":669,"image":855,"draft":566},"\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":857,"title":858,"description":859,"published":860,"category":669,"image":861,"draft":566},"\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":863,"title":864,"description":865,"published":866,"category":669,"image":867,"draft":566},"\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":869,"title":870,"description":871,"published":866,"category":562,"image":872,"draft":566},"\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":874,"title":875,"description":876,"published":877,"category":562,"image":878,"draft":566},"\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":880,"title":881,"description":882,"published":883,"category":562,"image":884,"draft":566},"\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":886,"title":887,"description":888,"published":889,"category":669,"image":890,"draft":566},"\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":892,"title":893,"description":894,"published":895,"category":562,"image":896,"draft":566},"\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":898,"title":899,"description":900,"published":901,"category":562,"image":902,"draft":566},"\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":904,"title":905,"description":906,"published":907,"category":562,"image":908,"draft":566},"\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":910,"title":911,"description":912,"published":913,"category":562,"image":914,"draft":566},"\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":916,"title":917,"description":918,"published":919,"category":562,"image":920,"draft":566},"\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":922,"title":923,"description":924,"published":925,"category":562,"image":926,"draft":566},"\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":928,"title":929,"description":930,"published":931,"category":562,"image":932,"draft":566},"\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":934,"title":935,"description":936,"published":937,"category":562,"image":938,"draft":566},"\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":940,"title":941,"description":942,"published":943,"category":669,"image":944,"draft":566},"\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":946,"title":947,"description":948,"published":949,"category":669,"image":950,"draft":566},"\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":952,"title":953,"description":954,"published":955,"category":669,"image":956,"draft":566},"\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":958,"title":959,"description":960,"published":961,"category":562,"image":962,"draft":566},"\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":964,"title":965,"description":966,"published":967,"category":562,"image":968,"draft":566},"\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":970,"title":971,"description":972,"published":973,"category":562,"image":974,"draft":566},"\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":388,"title":976,"description":977,"published":978,"category":562,"image":979,"draft":566},"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":981,"title":982,"description":983,"published":984,"category":562,"image":985,"draft":566},"\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":987,"title":988,"description":989,"published":990,"category":562,"image":991,"draft":566},"\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":993,"title":994,"description":995,"published":996,"category":562,"image":997,"draft":566},"\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":999,"title":1000,"description":1001,"published":1002,"category":562,"image":1003,"draft":566},"\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":1005,"title":1006,"description":1007,"published":1008,"category":562,"image":1009,"draft":566},"\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":1011,"title":1012,"description":1013,"published":1014,"category":562,"image":1015,"draft":566},"\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":1017,"title":1018,"description":1019,"published":1020,"category":669,"image":1021,"draft":566},"\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":1023,"title":1024,"description":1025,"published":1026,"category":562,"image":1027,"draft":566},"\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":1029,"title":1030,"description":1031,"published":1032,"category":669,"image":1033,"draft":566},"\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":1035,"title":1036,"description":1037,"published":1038,"category":562,"image":1039,"draft":566},"\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":352,"title":1041,"description":1042,"published":1043,"category":562,"image":1044,"draft":566},"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":1046,"title":1047,"description":1048,"published":1049,"category":562,"image":1050,"draft":566},"\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":1052,"title":1053,"description":1054,"published":1055,"category":562,"image":1056,"draft":566},"\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":1058,"title":1059,"description":1060,"published":1061,"category":669,"image":1062,"draft":566},"\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":1064,"title":1065,"description":1066,"published":1067,"category":669,"image":1068,"draft":566},"\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":1070,"title":1071,"description":1072,"published":1073,"category":562,"image":1074,"draft":566},"\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":1076,"title":1077,"description":1078,"published":1079,"category":562,"image":1080,"draft":566},"\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":1082,"title":1083,"description":1084,"published":1085,"category":669,"image":1086,"draft":566},"\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":1088,"title":1089,"description":1090,"published":1091,"category":562,"image":1092,"draft":566},"\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":1094,"title":1095,"description":1096,"published":1091,"category":562,"image":1097,"draft":566},"\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":393,"title":1099,"description":1100,"published":1101,"category":562,"image":1102,"draft":566},"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":1104,"title":1105,"description":1106,"published":1107,"category":669,"image":1108,"draft":566},"\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":1110,"title":1111,"description":1112,"published":1113,"category":562,"image":1114,"draft":566},"\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":1116,"title":1117,"description":1118,"published":1113,"category":669,"image":1119,"draft":566},"\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":1121,"title":1122,"description":1123,"published":1124,"category":669,"image":1125,"draft":566},"\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":546,"title":1127,"description":1128,"published":1124,"category":562,"image":1129,"draft":566},"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",1794213649237]