[{"data":1,"prerenderedAt":1270},["ShallowReactive",2],{"blog-pt-supabase-users-logged-out":3,"blog-index-pt":741},{"id":4,"title":5,"body":6,"category":700,"cover":701,"coverAlt":702,"description":703,"draft":704,"extension":705,"faq":706,"image":722,"keywords":723,"meta":730,"navigation":731,"ogTitle":5,"path":732,"published":733,"seo":734,"stem":735,"tldr":736,"updated":733,"__hash__":740},"blog_pt\u002Fblog\u002Fsupabase-users-logged-out.md","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 causas",{"type":7,"value":8,"toc":685},"minimark",[9,13,24,27,35,40,43,62,84,110,114,117,126,217,225,229,232,238,260,266,270,291,294,297,303,306,311,315,327,340,358,363,369,373,376,398,414,417,421,427,430,434,452,455,513,520,526,529,533,536,562,571,577,581,584,593,611,620,640,644,679],[10,11,12],"p",{},"Seus usuários escrevem para dizer que foram desconectados. Um estava no meio de\num formulário, e outra tem certeza de que não apertou nada. Quando você testa o\napp, ele funciona. Aí você abre seus logs e encontra a mesma linha, de novo e de\nnovo:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","AuthApiError: Invalid Refresh Token: Refresh Token Not Found\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26],{},"Supabase \"Invalid Refresh Token: Refresh Token Not Found\" é o Supabase Auth, a\nparte do Supabase que faz as pessoas entrarem, dizendo que não tem registro do\ntoken que seu app enviou para manter uma sessão aberta. Sem nada para renovar,\nseu app desconecta o usuário.",[10,28,29,30,34],{},"Esta é a parte que é fácil entender ao contrário: ",[31,32,33],"strong",{},"esse erro é o último passo,\ne a causa veio antes."," Quando o Supabase não encontra mais o token, a sessão a\nque ele pertencia já terminou. Quem a encerrou foi um logout, um token enviado\nduas vezes ou um limite que alguém definiu. Fazer o access token durar mais, ou\ndesligar a verificação que encerra uma sessão, deixa a linha mais rara nos seus\nlogs e deixa a causa exatamente onde estava.",[36,37,39],"h2",{"id":38},"o-que-significa-invalid-refresh-token-refresh-token-not-found","O que significa \"Invalid Refresh Token: Refresh Token Not Found\"?",[10,41,42],{},"Significa que o Supabase Auth recebeu um refresh token do qual não tem registro,\ne por isso se recusou a renovar a sessão.",[10,44,45,46,49,50,53,54,61],{},"Todo usuário conectado tem dois tokens. O ",[31,47,48],{},"access token"," funciona como uma\npulseira: prova quem ele é por um tempo, uma hora se você não mudou a\nconfiguração, e seu app a mostra em cada requisição. O ",[31,51,52],{},"refresh token"," é um\nbilhete. Antes que a pulseira expire, seu app leva o bilhete ao balcão, que é o\nSupabase Auth, e o troca por uma pulseira nova e um bilhete novo. O\n",[55,56,60],"a",{"href":57,"rel":58},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fsessions",[59],"nofollow","guia de sessões"," do Supabase\ndiz que refresh tokens \"never expire but can only be used once\".",[10,63,64,67,68,71,72,77,78,83],{},[21,65,66],{},"Refresh Token Not Found"," é o balcão procurando um bilhete e não encontrando\nnada. O servidor responde com HTTP 400 e o código ",[21,69,70],{},"refresh_token_not_found",", que\na\n",[55,73,76],{"href":74,"rel":75},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fdebugging\u002Ferror-codes",[59],"lista de códigos de erro do Auth","\ndo Supabase descreve como \"Session containing the refresh token not found.\" Se a\npulseira também expirou,\n",[55,79,82],{"href":80,"rel":81},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsupabase-js\u002Fblob\u002Fmaster\u002Fpackages\u002Fcore\u002Fauth-js\u002Fsrc\u002FGoTrueClient.ts",[59],"o cliente JavaScript do Supabase","\nremove a sessão do navegador e avisa seu app de que o usuário saiu. É nesse\nmomento que seu usuário dá de cara com a página de login.",[10,85,86,87,91,92,95,96,100,101,104,105,109],{},"Nenhum dos dois tokens é uma das chaves de API do seu projeto, que são outra\nquestão:\n",[55,88,90],{"href":89},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","quais delas pertencem ao seu app",".\nSe a sua mensagem diz ",[21,93,94],{},"Invalid JWT",", foi a pulseira que foi recusada, e não o\nbilhete, e\n",[55,97,99],{"href":98},"\u002Fblog\u002Fsupabase-invalid-jwt","esse erro tem uma página própria",".\nSe depois a pessoa não consegue entrar de novo e o formulário de login diz\n",[21,102,103],{},"Invalid login credentials",",\n",[55,106,108],{"href":107},"\u002Fblog\u002Fsupabase-invalid-login","essa mensagem cobre três pessoas diferentes",".",[36,111,113],{"id":112},"por-que-meus-usuários-do-supabase-são-desconectados","Por que meus usuários do Supabase são desconectados?",[10,115,116],{},"Porque a sessão por trás do bilhete deles terminou, e a pulseira que eles ainda\nusam os manteve conectados até expirar. Esse atraso, de até uma hora com a\nconfiguração padrão, é o que faz as desconexões parecerem aleatórias: o usuário\né jogado para fora um tempo depois de a sessão terminar.",[10,118,119,120,125],{},"O Supabase Auth tem quatro jeitos de dizer que um bilhete não vale, e cada um\naponta para uma causa diferente. Estas são as mensagens exatas do\n",[55,121,124],{"href":122,"rel":123},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Ftokens\u002Fservice.go",[59],"código do próprio servidor do Supabase Auth",":",[127,128,129,145],"table",{},[130,131,132],"thead",{},[133,134,135,139,142],"tr",{},[136,137,138],"th",{},"A mensagem no seu log",[136,140,141],{},"O código",[136,143,144],{},"O que aconteceu",[146,147,148,163,178,202],"tbody",{},[133,149,150,156,160],{},[151,152,153],"td",{},[21,154,155],{},"Invalid Refresh Token: Refresh Token Not Found",[151,157,158],{},[21,159,70],{},[151,161,162],{},"O balcão não tem registro deste bilhete. Um logout encerrou a sessão dele, ou ele foi trocado há tanto tempo que o registro sumiu.",[133,164,165,170,175],{},[151,166,167],{},[21,168,169],{},"Invalid Refresh Token: Already Used",[151,171,172],{},[21,173,174],{},"refresh_token_already_used",[151,176,177],{},"O bilhete foi trocado há mais de dez segundos e voltou. O Supabase encerra a sessão inteira quando isso acontece.",[133,179,180,194,199],{},[151,181,182,185,186,189,190,193],{},[21,183,184],{},"Invalid Refresh Token: Session Expired",", às vezes com ",[21,187,188],{},"(Inactivity)"," ou ",[21,191,192],{},"(Revoked by Newer Login)"," depois",[151,195,196],{},[21,197,198],{},"session_expired",[151,200,201],{},"Um limite de sessão nas suas configurações do Auth a encerrou.",[133,203,204,209,214],{},[151,205,206],{},[21,207,208],{},"Invalid Refresh Token: No Valid Session Found",[151,210,211],{},[21,212,213],{},"session_not_found",[151,215,216],{},"A sessão a que o bilhete pertencia não existe mais.",[10,218,219,220,224],{},"Por trás dessas mensagens estão três causas, segundo a própria documentação do\nSupabase e os relatos nos seus issue trackers, e cada uma tem sua correção. Se\nninguém consegue entrar, ou o app inteiro está em branco, é outro problema, e\n",[55,221,223],{"href":222},"\u002Fblog\u002Fis-supabase-down-or-your-app","o Supabase caiu, ou é o seu app?"," é por\nonde começar.",[36,226,228],{"id":227},"um-refresh-token-funciona-uma-vez","Um refresh token funciona uma vez",[10,230,231],{},"Toda vez que seu app renova uma sessão, ele entrega o bilhete e o balcão rasga o\nantigo. O Supabase chama isso de rotação de refresh tokens. O bilhete antigo\ncontinua funcionando por mais dez segundos, o que o guia de sessões chama de\nreuse interval, para que um servidor e um navegador renovando quase no mesmo\nmomento não derrubem um ao outro. Um cliente que trocou o bilhete e perdeu a\nresposta numa conexão ruim também está coberto: ele recebe o bilhete atual de\nvolta.",[10,233,234,235,109],{},"Fora desses dois casos, um bilhete antigo que volta conta como sinal de alerta,\nporque um token que aparece duas vezes é o que um token roubado parece. O guia\ndiz que a sessão inteira então \"is regarded as terminated and all refresh tokens\nbelonging to it are marked as revoked\". A resposta dessa vez é ",[21,236,237],{},"Already Used",[10,239,240,241,243,244,247,248,253,254,256,257,259],{},"Mais um passo transforma ",[21,242,237],{}," em ",[21,245,246],{},"Not Found",". O servidor do Supabase\nAuth\n",[55,249,252],{"href":250,"rel":251},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Fmodels\u002Fcleanup.go",[59],"apaga os registros dos bilhetes rasgados","\n24 horas depois de serem revogados. Então o bilhete vencido que hoje recebe\n",[21,255,237],{}," amanhã recebe ",[21,258,66],{},", porque o balcão não tem\nmais o registro para comparar.",[261,262],"diagram",{"alt":263,"caption":264,"src":265},"Uma linha do tempo de um bilhete. Primeiro ele é trocado no balcão por uma pulseira nova e um bilhete novo, e o antigo é rasgado. Mostrado de novo em até 10 segundos, ainda é aceito. Mais tarde no mesmo dia, é recusado como já usado. Depois de 24 horas, o livro do balcão tem uma linha vazia onde estava o registro dele.","Um bilhete em quatro momentos. Em até dez segundos ainda funciona. Depois é recusado como já usado, e quando o registro dele é apagado um dia depois, o balcão não o encontra mais.","\u002Fblog\u002Fsupabase-users-logged-out\u002Fone-ticket-four-moments-1600x700.png",[36,267,269],{"id":268},"causa-1-alguém-saiu-neste-dispositivo-ou-em-outro","Causa 1: alguém saiu, neste dispositivo ou em outro",[10,271,272,273,276,277,280,281,286,287,290],{},"Um logout apaga a sessão do lado do balcão, e cada bilhete dela vira um que o\nbalcão não encontra. No cliente JavaScript do Supabase, ",[21,274,275],{},"signOut()"," sem nada\ndentro dos parênteses encerra ",[31,278,279],{},"todas"," as sessões daquele usuário, em todos os\ndispositivos. O ",[55,282,285],{"href":283,"rel":284},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fsignout",[59],"guia de logout","\ndo Supabase diz isso com todas as letras: com esse padrão, as outras sessões\nfalham com ",[21,288,289],{},"AuthApiError: Invalid Refresh Token: Refresh Token Not Found"," na\npróxima vez que tentam se renovar, \"even though no one signed out on that\ndevice.\"",[10,292,293],{},"Então um usuário que sai no celular também é desconectado no notebook, até uma\nhora depois, quando a pulseira do notebook expira e o bilhete dele volta como\ndesconhecido. Do ponto de vista dele, seu app o jogou para fora sem motivo.",[10,295,296],{},"Se cada dispositivo deve continuar conectado por conta própria, a chamada de\nlogout precisa encerrar só a sessão de onde ela partiu:",[14,298,301],{"className":299,"code":300,"language":19},[17],"await supabase.auth.signOut({ scope: 'local' })\n",[21,302,300],{"__ignoreMap":23},[10,304,305],{},"Peça ao seu builder para usar essa forma em todo lugar onde seu app desconecta\nas pessoas. O outro jeito comum de encerrar uma sessão é uma troca de senha, que\no guia de sessões do Supabase lista entre as coisas que encerram uma.",[261,307],{"alt":308,"caption":309,"src":310},"Dois painéis. No da esquerda, um celular sai com signOut() e os bilhetes do celular, de um notebook e de um tablet ficam todos rasgados. No da direita, o celular sai com scope local, e só o bilhete do celular é rasgado, enquanto o notebook e o tablet ficam com os deles.","Sem scope, um único logout encerra a sessão em todos os dispositivos. Com scope local, encerra só a do dispositivo na sua mão.","\u002Fblog\u002Fsupabase-users-logged-out\u002Fone-sign-out-every-device-1600x720.png",[36,312,314],{"id":313},"causa-2-o-bilhete-novo-nunca-chegou-ao-navegador","Causa 2: o bilhete novo nunca chegou ao navegador",[10,316,317,318,321,322,324,325,109],{},"Se seu app gera as páginas num servidor, como faz um app Next.js, esse servidor\ntambém renova sessões. Ele lê o bilhete de um cookie, troca no balcão e precisa\ndevolver o bilhete novo ao navegador num cabeçalho ",[21,319,320],{},"Set-Cookie"," da sua resposta.\nQuando esse cookie não chega, o navegador fica com o bilhete antigo, e a próxima\nrequisição apresenta um bilhete que o servidor já trocou. Em até dez segundos,\nisso passa. Depois disso é ",[21,323,237],{}," e a sessão termina, e um dia depois o\nmesmo bilhete é ",[21,326,246],{},[10,328,329,330,335,336,339],{},"O\n",[55,331,334],{"href":332,"rel":333},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fserver-side\u002Fcreating-a-client",[59],"guia do Supabase para criar um cliente de servidor","\naponta o erro que causa isso num app Next.js. O código que renova a sessão, que o\nNext.js 16 chama de Proxy e as versões anteriores de middleware, precisa\ndevolver a resposta em que os cookies novos foram escritos: \"An earlier response\ndoesn't carry the refreshed cookies, so the user is signed out on the next\nrequest.\" O mesmo guia avisa que no Next.js 15 e anteriores um arquivo chamado\n",[21,337,338],{},"proxy.ts"," nunca é executado, \"so sessions never refresh and users get signed\nout\". Um assistente trabalhando com a documentação mais nova pode escrever\nexatamente esse arquivo num app mais antigo.",[10,341,342,343,351,352,357],{},"O guia do Supabase também diz por que esse caso é difícil de achar: \"it looks\nlike users being signed out at random rather than an error in your code.\" Os\nrelatos soam igual. Um desenvolvedor escreveu no\n",[55,344,347,348],{"href":345,"rel":346},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fssr\u002Fissues\u002F68",[59],"issue tracker do ",[21,349,350],{},"@supabase\u002Fssr","\n\"I'm inadvertently logged out of my web application every day\", e o engenheiro\ndo Supabase que respondeu apontou o jeito como o middleware repassava a\nresposta. O\n",[55,353,356],{"href":354,"rel":355},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsupabase-swift\u002Fissues\u002F486",[59],"relato de um app de iOS","\ndescreve a desconexão chegando \"2-3 days after logging in\", e foi fechado depois\nque atualizações na biblioteca Swift do Supabase reduziram os relatos.",[261,359],{"alt":360,"caption":361,"src":362},"Um navegador manda seu bilhete a um servidor. O servidor o troca no balcão e recebe um novo. A resposta que levaria o bilhete novo ao navegador se interrompe antes de chegar, então o navegador manda o bilhete antigo de novo, e o balcão o recusa como já usado.","O servidor renovou a sessão, e o bilhete novo nunca voltou. O navegador ainda segura o que já foi trocado.","\u002Fblog\u002Fsupabase-users-logged-out\u002Fnew-ticket-lost-1600x640.png",[10,364,365,366,368],{},"Para conferir, abra as ferramentas de desenvolvedor do navegador numa página que\nrenovou a sessão e olhe a resposta na aba Network. Ela deve trazer um\n",[21,367,320],{}," com o token novo, e a requisição seguinte deve mandar esse token de\nvolta.",[36,370,372],{"id":371},"causa-3-um-limite-de-sessão-nas-suas-configurações-do-auth","Causa 3: um limite de sessão nas suas configurações do Auth",[10,374,375],{},"A partir do plano Pro, o Supabase pode encerrar sessões de propósito, pela\npágina Sessions das configurações do Auth do seu projeto. São três limites, e o\nguia de sessões descreve cada um:",[377,378,379,386,392],"ul",{},[380,381,382,385],"li",{},[31,383,384],{},"Sessões com tempo limitado"," terminam depois de um tempo fixo, por mais ativo\nque o usuário esteja.",[380,387,388,391],{},[31,389,390],{},"Um tempo limite de inatividade"," encerra uma sessão que não é renovada há um\ntempo.",[380,393,394,397],{},[31,395,396],{},"Uma sessão por usuário"," mantém só o login mais recente, então entrar pelo\ncelular encerra a sessão no notebook.",[10,399,400,401,404,405,407,408,410,411,413],{},"Esses dizem isso na própria mensagem, ",[21,402,403],{},"Session Expired",", com ",[21,406,188],{}," ou\n",[21,409,192],{}," depois, no segundo e no terceiro. O guia acrescenta\nque sessões encerradas são apagadas 24 horas depois, então um bilhete de uma\ndelas que volta depois desse prazo recebe ",[21,412,246],{}," no lugar.",[10,415,416],{},"Se você configurou um desses, as desconexões são a configuração fazendo o seu\ntrabalho. Se não era a intenção, ou se um template ou um assistente ligou isso\npor você, a página mostra qual limite está ativo.",[36,418,420],{"id":419},"o-caso-inofensivo","O caso inofensivo",[10,422,423,424,426],{},"Um bilhete de uma sessão que já terminou, voltando de uma aba antiga ou de um\nnavegador que ninguém abria havia semanas, também recebe\n",[21,425,66],{},". A pessoa por trás já tinha sido desconectada. O\nnavegador dela perguntou uma vez, o Supabase disse não, e ela vê sua página de\nlogin, que é o que teria visto de qualquer jeito.",[10,428,429],{},"No log, aparece assim: uma linha para um usuário, muitas vezes logo depois de\nesse usuário sair em algum lugar, e depois nada mais dele. Linhas assim são o\nerro fazendo o seu trabalho. As que valem investigar são as mesmas pessoas de\nnovo e de novo, ou um monte de pessoas diferentes no mesmo dia.",[36,431,433],{"id":432},"como-ler-seus-logs-do-auth-para-isso","Como ler seus logs do Auth para isso",[10,435,436,437,440,441,444,445,447,448,451],{},"Abra ",[31,438,439],{},"Logs"," no painel do Supabase, escolha o tipo de log ",[31,442,443],{},"Auth"," e procure\n",[21,446,52],{}," nas mensagens de evento. Selecione uma linha para ver os\ndetalhes, incluindo o ID do usuário, e o filtro ",[31,449,450],{},"User"," então reduz a lista a\nessa pessoa. Até onde os logs voltam depende do seu plano, então leia enquanto\nas reclamações são recentes.",[10,453,454],{},"Depois leia o que se repete:",[127,456,457,467],{},[130,458,459],{},[133,460,461,464],{},[136,462,463],{},"O que você vê no log do Auth",[136,465,466],{},"Para onde aponta",[146,468,469,480,490,503],{},[133,470,471,477],{},[151,472,473,474,476],{},"Um ",[21,475,66],{}," para um usuário, e nada depois",[151,478,479],{},"Uma aba antiga ou um navegador que voltou. Inofensivo.",[133,481,482,487],{},[151,483,484,486],{},[21,485,66],{}," para um usuário logo depois de ele sair em outro lugar",[151,488,489],{},"Causa 1, um logout que encerrou todos os dispositivos",[133,491,492,500],{},[151,493,494,496,497,499],{},[21,495,237],{},", e um dia depois ",[21,498,66],{},", para os mesmos usuários, de novo e de novo",[151,501,502],{},"Causa 2, bilhetes novos que não chegam ao navegador",[133,504,505,510],{},[151,506,507,509],{},[21,508,403],{},", com um motivo entre parênteses",[151,511,512],{},"Causa 3, um limite de sessão",[10,514,515,516,519],{},"Você também pode perguntar ao banco de dados com que frequência as pessoas\nentram. Cada login acrescenta uma linha em ",[21,517,518],{},"auth.sessions",", e um logout a apaga.\nCole isto no SQL Editor:",[14,521,524],{"className":522,"code":523,"language":19},[17],"select user_id, count(*) as sessions, max(created_at) as latest\nfrom auth.sessions\nwhere created_at > now() - interval '14 days'\ngroup by user_id\norder by sessions desc\nlimit 20;\n",[21,525,523],{"__ignoreMap":23},[10,527,528],{},"Um usuário com muito mais sessões do que dispositivos entrou de novo e de novo\nsem nunca sair, que é o que faz alguém que seu app joga para fora o tempo todo.",[36,530,532],{"id":531},"o-que-não-mudar-enquanto-você-corrige","O que não mudar enquanto você corrige",[10,534,535],{},"Suas regras de Row Level Security, a detecção de reutilização e a duração do\naccess token. As três parecem uma correção e deixam a causa onde está, e afrouxar\na primeira pode abrir seus dados para estranhos.",[10,537,538,541,542,545,546,551,553,554,557,558,109],{},[31,539,540],{},"Deixe suas regras de Row Level Security em paz."," Row Level Security é o\nconjunto de regras que decide quais linhas cada visitante recebe. Enquanto os\nusuários estão sendo jogados para fora, toda tela cuja regra lê ",[21,543,544],{},"auth.uid()"," fica\nvazia para eles, porque segundo a\n",[55,547,550],{"href":548,"rel":549},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fdatabase\u002Fpostgres\u002Frow-level-security",[59],"documentação do Supabase",[21,552,544],{}," retorna ",[21,555,556],{},"null"," quando a sessão expirou. A correção tentadora é\nafrouxar essa regra até a tela encher de novo, e aí ela enche também para\nestranhos. Se alguém já fez isso, nossa verificação gratuita pergunta a cada\ntabela que seu app nomeia quantas linhas um visitante sem login receberia, lê o\nnúmero sem baixar uma única linha e leva cerca de 20 segundos, sem conta:\n",[55,559,561],{"href":560},"\u002Fsecurity-scanner","verifique seu app",[10,563,564,567,568,570],{},[31,565,566],{},"Deixe a detecção de reutilização ligada."," O Supabase permite desligá-la, nas\nconfigurações avançadas da página Sessions, e chama isso de \"generally not\nrecommended\". Com ela desligada, a causa 2 para de produzir ",[21,569,237],{},", e o\nbilhete novo continua sem chegar ao navegador.",[10,572,573,576],{},[31,574,575],{},"Mantenha o access token em uma hora."," Uma pulseira mais longa adia a\ndesconexão e deixa a causa onde está. O guia do Supabase diz que definir mais de\numa hora é \"generally discouraged for security reasons\".",[36,578,580],{"id":579},"mantendo-os-logins-funcionando-depois-da-correção","Mantendo os logins funcionando depois da correção",[10,582,583],{},"Duas coisas ainda podem dar errado quando as desconexões param: uma mudança\nposterior as traz de volta, e uma regra afrouxada no caminho deixa uma tabela\naberta para estranhos.",[10,585,586],{},[31,587,588,592],{},[55,589,591],{"href":590},"\u002Fwebsite-monitoring","Reeve Monitor"," continua verificando de fora:",[377,594,595,598,601,608],{},[380,596,597],{},"se seu app está no ar, verificado a cada minuto, para que uma onda de mensagens de \"fui desconectado\" não seja confundida com uma queda",[380,599,600],{},"a verificação de segurança completa a cada hora, em até três apps",[380,602,603,604,607],{},"uma mensagem quando um resultado ",[31,605,606],{},"muda",", para que uma regra afrouxada durante uma correção não espere você olhar",[380,609,610],{},"um relatório mensal, em linguagem simples, do que ele viu",[10,612,613],{},[31,614,615,619],{},[55,616,618],{"href":617},"\u002Fsupabase-backups","Reeve Care"," guarda uma cópia do seu banco de dados Supabase:",[377,621,622,625,628,631,634,637],{},[380,623,624],{},"uma cópia criptografada em uma programação, no armazenamento próprio da Reeve na UE, fora da sua conta do Supabase",[380,626,627],{},"o schema auth onde vivem as contas dos seus usuários, para que elas voltem com todo o resto",[380,629,630],{},"cada cópia verificada antes de contar, contando as linhas de cada tabela",[380,632,633],{},"seus arquivos enviados também, assim que você conectar uma credencial do Storage",[380,635,636],{},"uma restauração com um clique, com uma cópia de segurança do estado atual feita antes",[380,638,639],{},"tudo o que o Monitor faz",[36,641,643],{"id":642},"o-que-fazer-agora","O que fazer agora",[645,646,647],"key-takeaways",{},[377,648,649,655,661,667,670,673],{},[380,650,651,652,654],{},"Procure ",[21,653,52],{}," nos seus logs do Auth e veja qual mensagem se repete, e com quem.",[380,656,657,658,109],{},"Se um logout em um dispositivo encerra os outros, troque para ",[21,659,660],{},"signOut({ scope: 'local' })",[380,662,663,664,666],{},"Se seu app gera páginas num servidor, garanta que a resposta que renovou uma sessão é a que chega ao navegador, e procure o ",[21,665,320],{}," dela na aba Network.",[380,668,669],{},"Veja na página Sessions das configurações do Auth se há um tempo limite, um limite de inatividade ou uma sessão por usuário que ninguém quis ligar.",[380,671,672],{},"Deixe Row Level Security, a detecção de reutilização e a duração do access token como estão enquanto corrige.",[380,674,675,676,678],{},"Trate um ",[21,677,246],{}," por usuário como ruído, e os mesmos usuários todo dia como um bug.",[10,680,681,682,684],{},"Comece pelo log do Auth, porque a mensagem que se repete diz qual das três causas\nvocê tem. Depois, quando as pessoas continuarem conectadas,\n",[55,683,561],{"href":560}," para conferir que nada foi afrouxado no\ncaminho.",{"title":23,"searchDepth":686,"depth":686,"links":687},3,[688,690,691,692,693,694,695,696,697,698,699],{"id":38,"depth":689,"text":39},2,{"id":112,"depth":689,"text":113},{"id":227,"depth":689,"text":228},{"id":268,"depth":689,"text":269},{"id":313,"depth":689,"text":314},{"id":371,"depth":689,"text":372},{"id":419,"depth":689,"text":420},{"id":432,"depth":689,"text":433},{"id":531,"depth":689,"text":532},{"id":579,"depth":689,"text":580},{"id":642,"depth":689,"text":643},"Noções de segurança","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcover-1200x630.png","Um bilhete rasgado em dois, a metade esquerda acesa e a direita apagada e caindo, diante de uma fileira de bilhetes inteiros.","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" desconecta seus usuários. Três causas, e como o log do Auth separa cada uma.",false,"md",[707,710,713,716,719],{"q":708,"a":709},"Por que meus usuários do Supabase são desconectados do nada?","Porque a sessão por trás do refresh token deles terminou, e o access token que eles ainda têm os mantém conectados por até uma hora, então a desconexão chega depois da causa. Os motivos mais comuns são um logout em outro dispositivo, um token renovado que nunca chegou ao navegador e um limite de sessão nas suas configurações do Auth. O log do Auth mostra qual é.",{"q":711,"a":712},"O que é um refresh token?","É a metade duradoura de uma sessão do Supabase. O access token prova quem é o usuário por uma hora por padrão, e antes que ele expire seu app troca o refresh token por um par novo. Cada refresh token funciona uma vez, e o antigo para de funcionar dez segundos depois da troca.",{"q":714,"a":715},"\"Refresh Token Not Found\" é sinal de um ataque?","Sozinho, não. Significa que o Supabase Auth recusou um token do qual não tem registro, que é a resposta certa. A proteção contra um token roubado é a detecção de reutilização, que encerra uma sessão quando um token antigo volta, e o Supabase recomenda deixá-la ligada.",{"q":717,"a":718},"Por que isso só acontece em produção?","Porque a maioria das causas precisa de tempo ou de um segundo dispositivo. Um token vencido é recusado como já usado no primeiro dia e como não encontrado quando o registro dele é apagado um dia depois, e uma sessão que você abre enquanto constrói raramente dura tanto. Usuários de verdade também entram por vários dispositivos, e é aí que aparece um logout que encerra todas as sessões.",{"q":720,"a":721},"Quanto tempo dura uma sessão do Supabase?","Por padrão, até o usuário sair. O access token dura uma hora se você não mudar, e o refresh token nunca expira, mas só funciona uma vez. A partir do plano Pro, você pode limitar as sessões por tempo total, por inatividade ou a uma por usuário, na página Sessions das suas configurações do Auth.","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",[724,725,70,726,727,728,729],"invalid refresh token refresh token not found","supabase invalid refresh token","supabase usuários desconectados","supabase refresh token already used","supabase session expired","supabase ssr erro refresh token",{},true,"\u002Fblog\u002Fsupabase-users-logged-out","2026-10-19",{"title":5,"description":703},"blog\u002Fsupabase-users-logged-out",[737,738,739],"Supabase \"Invalid Refresh Token: Refresh Token Not Found\" significa que o Supabase Auth não tem registro do refresh token que seu app enviou, então a sessão não pode ser renovada e o usuário é desconectado.","Três coisas apagam esse registro: um logout (que no JavaScript encerra todos os dispositivos por padrão), um token já usado que chega uma segunda vez e um limite de sessão nas suas configurações do Auth.","Parte disso é uma linha inofensiva de uma aba antiga. Outra parte desconecta todos os seus usuários todo dia. O log do Auth diz qual é, e cada causa tem sua própria correção.","yl9xj8Ov07XXo0Sd-AScM_aKObYM9oCMWlQWM4QWqok",[742,748,754,760,766,772,778,784,790,796,802,809,815,820,826,832,838,844,850,856,862,868,869,875,881,886,892,898,904,910,916,922,928,934,940,946,952,958,964,970,975,981,987,993,999,1005,1010,1016,1022,1028,1034,1040,1046,1052,1058,1064,1070,1076,1082,1088,1094,1100,1106,1112,1118,1124,1130,1136,1142,1148,1154,1160,1166,1172,1178,1184,1190,1196,1202,1208,1214,1220,1226,1232,1237,1243,1249,1255,1260,1266],{"path":743,"title":744,"description":745,"published":746,"category":700,"image":747,"draft":704},"\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":749,"title":750,"description":751,"published":752,"category":700,"image":753,"draft":704},"\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":755,"title":756,"description":757,"published":758,"category":700,"image":759,"draft":704},"\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":761,"title":762,"description":763,"published":764,"category":700,"image":765,"draft":704},"\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":767,"title":768,"description":769,"published":770,"category":700,"image":771,"draft":704},"\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":773,"title":774,"description":775,"published":776,"category":700,"image":777,"draft":704},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","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":779,"title":780,"description":781,"published":782,"category":700,"image":783,"draft":704},"\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":785,"title":786,"description":787,"published":788,"category":700,"image":789,"draft":704},"\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":791,"title":792,"description":793,"published":794,"category":700,"image":795,"draft":704},"\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":797,"title":798,"description":799,"published":800,"category":700,"image":801,"draft":704},"\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":803,"title":804,"description":805,"published":806,"category":807,"image":808,"draft":704},"\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":810,"title":811,"description":812,"published":813,"category":700,"image":814,"draft":704},"\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":107,"title":816,"description":817,"published":818,"category":700,"image":819,"draft":704},"\"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":821,"title":822,"description":823,"published":824,"category":700,"image":825,"draft":704},"\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":827,"title":828,"description":829,"published":830,"category":700,"image":831,"draft":704},"\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":833,"title":834,"description":835,"published":836,"category":700,"image":837,"draft":704},"\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":839,"title":840,"description":841,"published":842,"category":700,"image":843,"draft":704},"\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":845,"title":846,"description":847,"published":848,"category":700,"image":849,"draft":704},"\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":851,"title":852,"description":853,"published":854,"category":700,"image":855,"draft":704},"\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":857,"title":858,"description":859,"published":860,"category":700,"image":861,"draft":704},"\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":863,"title":864,"description":865,"published":866,"category":700,"image":867,"draft":704},"\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":732,"title":5,"description":703,"published":733,"category":700,"image":722,"draft":704},{"path":870,"title":871,"description":872,"published":873,"category":700,"image":874,"draft":704},"\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":876,"title":877,"description":878,"published":879,"category":700,"image":880,"draft":704},"\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":98,"title":882,"description":883,"published":884,"category":700,"image":885,"draft":704},"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":887,"title":888,"description":889,"published":890,"category":700,"image":891,"draft":704},"\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":893,"title":894,"description":895,"published":896,"category":700,"image":897,"draft":704},"\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":899,"title":900,"description":901,"published":902,"category":700,"image":903,"draft":704},"\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":905,"title":906,"description":907,"published":908,"category":700,"image":909,"draft":704},"\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":911,"title":912,"description":913,"published":914,"category":700,"image":915,"draft":704},"\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":917,"title":918,"description":919,"published":920,"category":700,"image":921,"draft":704},"\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":923,"title":924,"description":925,"published":926,"category":700,"image":927,"draft":704},"\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":929,"title":930,"description":931,"published":932,"category":700,"image":933,"draft":704},"\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":935,"title":936,"description":937,"published":938,"category":700,"image":939,"draft":704},"\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":941,"title":942,"description":943,"published":944,"category":700,"image":945,"draft":704},"\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":947,"title":948,"description":949,"published":950,"category":700,"image":951,"draft":704},"\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":953,"title":954,"description":955,"published":956,"category":700,"image":957,"draft":704},"\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":959,"title":960,"description":961,"published":962,"category":700,"image":963,"draft":704},"\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":965,"title":966,"description":967,"published":968,"category":700,"image":969,"draft":704},"\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":222,"title":971,"description":972,"published":973,"category":700,"image":974,"draft":704},"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":976,"title":977,"description":978,"published":979,"category":700,"image":980,"draft":704},"\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":982,"title":983,"description":984,"published":985,"category":700,"image":986,"draft":704},"\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":988,"title":989,"description":990,"published":991,"category":807,"image":992,"draft":704},"\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":994,"title":995,"description":996,"published":997,"category":807,"image":998,"draft":704},"\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":1000,"title":1001,"description":1002,"published":1003,"category":807,"image":1004,"draft":704},"\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":1006,"title":1007,"description":1008,"published":1003,"category":700,"image":1009,"draft":704},"\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":1011,"title":1012,"description":1013,"published":1014,"category":700,"image":1015,"draft":704},"\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":1017,"title":1018,"description":1019,"published":1020,"category":700,"image":1021,"draft":704},"\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":1023,"title":1024,"description":1025,"published":1026,"category":807,"image":1027,"draft":704},"\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":1029,"title":1030,"description":1031,"published":1032,"category":700,"image":1033,"draft":704},"\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":1035,"title":1036,"description":1037,"published":1038,"category":700,"image":1039,"draft":704},"\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":1041,"title":1042,"description":1043,"published":1044,"category":700,"image":1045,"draft":704},"\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":1047,"title":1048,"description":1049,"published":1050,"category":700,"image":1051,"draft":704},"\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":1053,"title":1054,"description":1055,"published":1056,"category":700,"image":1057,"draft":704},"\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":1059,"title":1060,"description":1061,"published":1062,"category":700,"image":1063,"draft":704},"\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":1065,"title":1066,"description":1067,"published":1068,"category":700,"image":1069,"draft":704},"\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":1071,"title":1072,"description":1073,"published":1074,"category":700,"image":1075,"draft":704},"\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":1077,"title":1078,"description":1079,"published":1080,"category":807,"image":1081,"draft":704},"\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":1083,"title":1084,"description":1085,"published":1086,"category":807,"image":1087,"draft":704},"\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":1089,"title":1090,"description":1091,"published":1092,"category":807,"image":1093,"draft":704},"\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":1095,"title":1096,"description":1097,"published":1098,"category":700,"image":1099,"draft":704},"\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":1101,"title":1102,"description":1103,"published":1104,"category":700,"image":1105,"draft":704},"\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":1107,"title":1108,"description":1109,"published":1110,"category":700,"image":1111,"draft":704},"\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":1113,"title":1114,"description":1115,"published":1116,"category":700,"image":1117,"draft":704},"\u002Fblog\u002Frotate-supabase-service-role-key","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":1119,"title":1120,"description":1121,"published":1122,"category":700,"image":1123,"draft":704},"\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":1125,"title":1126,"description":1127,"published":1128,"category":700,"image":1129,"draft":704},"\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":1131,"title":1132,"description":1133,"published":1134,"category":700,"image":1135,"draft":704},"\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":1137,"title":1138,"description":1139,"published":1140,"category":700,"image":1141,"draft":704},"\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":1143,"title":1144,"description":1145,"published":1146,"category":700,"image":1147,"draft":704},"\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":1149,"title":1150,"description":1151,"published":1152,"category":700,"image":1153,"draft":704},"\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":1155,"title":1156,"description":1157,"published":1158,"category":807,"image":1159,"draft":704},"\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":1161,"title":1162,"description":1163,"published":1164,"category":700,"image":1165,"draft":704},"\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":1167,"title":1168,"description":1169,"published":1170,"category":807,"image":1171,"draft":704},"\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":1173,"title":1174,"description":1175,"published":1176,"category":700,"image":1177,"draft":704},"\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":1179,"title":1180,"description":1181,"published":1182,"category":700,"image":1183,"draft":704},"\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":1185,"title":1186,"description":1187,"published":1188,"category":700,"image":1189,"draft":704},"\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":1191,"title":1192,"description":1193,"published":1194,"category":700,"image":1195,"draft":704},"\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":1197,"title":1198,"description":1199,"published":1200,"category":807,"image":1201,"draft":704},"\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":1203,"title":1204,"description":1205,"published":1206,"category":807,"image":1207,"draft":704},"\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":1209,"title":1210,"description":1211,"published":1212,"category":700,"image":1213,"draft":704},"\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":1215,"title":1216,"description":1217,"published":1218,"category":700,"image":1219,"draft":704},"\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":1221,"title":1222,"description":1223,"published":1224,"category":807,"image":1225,"draft":704},"\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":1227,"title":1228,"description":1229,"published":1230,"category":700,"image":1231,"draft":704},"\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":1233,"title":1234,"description":1235,"published":1230,"category":700,"image":1236,"draft":704},"\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":1238,"title":1239,"description":1240,"published":1241,"category":700,"image":1242,"draft":704},"\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":1244,"title":1245,"description":1246,"published":1247,"category":807,"image":1248,"draft":704},"\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":1250,"title":1251,"description":1252,"published":1253,"category":700,"image":1254,"draft":704},"\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":1256,"title":1257,"description":1258,"published":1253,"category":807,"image":1259,"draft":704},"\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":1261,"title":1262,"description":1263,"published":1264,"category":807,"image":1265,"draft":704},"\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":89,"title":1267,"description":1268,"published":1264,"category":700,"image":1269,"draft":704},"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",1794213649194]