[{"data":1,"prerenderedAt":1136},["ShallowReactive",2],{"blog-pt-supabase-invalid-login":3,"blog-index-pt":607},{"id":4,"title":5,"body":6,"category":565,"cover":566,"coverAlt":567,"description":568,"draft":569,"extension":570,"faq":571,"image":587,"keywords":588,"meta":595,"navigation":596,"ogTitle":597,"path":598,"published":599,"seo":600,"stem":601,"tldr":602,"updated":599,"__hash__":606},"blog_pt\u002Fblog\u002Fsupabase-invalid-login.md","\"Invalid login credentials\" no Supabase: as três causas",{"type":7,"value":8,"toc":552},"minimark",[9,13,24,27,35,40,43,64,94,97,101,104,110,116,122,131,137,141,148,161,168,174,177,255,262,266,269,272,275,288,292,295,306,332,335,339,342,345,348,357,368,378,385,390,394,397,433,436,442,445,449,452,461,475,484,504,508,539],[10,11,12],"p",{},"Alguém escreve dizendo que não consegue entrar no seu app e tem certeza de que a\nsenha está certa. Você testa o endereço da pessoa e recebe a mesma linha\nvermelha embaixo do formulário:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","Invalid login credentials\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26],{},"O Supabase responde \"Invalid login credentials\" para uma senha errada. E\nresponde com exatamente as mesmas palavras para outras duas pessoas: quem tem um\ne-mail sem conta no seu app e quem se cadastrou com o Google e nunca teve senha.\nSeu app feito no Lovable, Bolt, v0, Cursor, Claude Code ou Replit está\nfuncionando do jeito que foi construído. Ele dá uma resposta só para três\nsituações diferentes.",[10,28,29,30,34],{},"Esta é a parte que a correção óbvia erra: ",[31,32,33],"strong",{},"a mensagem vaga é proposital, e\ndeixá-la mais útil abre um buraco."," O que ajuda é descobrir qual dos três casos\nvocê tem na frente, algo que o seu próprio painel consegue dizer, enquanto o\nformulário continua dizendo tão pouco quanto agora.",[36,37,39],"h2",{"id":38},"o-que-significa-invalid-login-credentials-no-supabase","O que significa \"Invalid login credentials\" no Supabase?",[10,41,42],{},"Significa que o Supabase Auth, a parte do Supabase que faz o login das pessoas,\nrecusou um e-mail e uma senha e guarda o motivo para si.",[10,44,45,46,53,54,57,58,63],{},"A mensagem está escrita no próprio código do servidor de Auth. Na\n",[47,48,52],"a",{"href":49,"rel":50},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Fapi\u002Ftoken.go",[51],"nofollow","função que trata um login com senha",",\no mesmo erro é devolvido em três pontos: quando nenhum usuário tem aquele\ne-mail, quando o usuário não tem senha salva e quando a senha não confere. Em\ntodos eles a resposta é um HTTP 400 com o código ",[21,55,56],{},"invalid_credentials",", que a\n",[47,59,62],{"href":60,"rel":61},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fdebugging\u002Ferror-codes",[51],"referência de códigos de erro","\ndo Supabase descreve como \"Login credentials or grant type not recognized.\"",[10,65,66,67,70,71,74,75,78,79,81,82,84,85,88,89,93],{},"No seu app ele chega como um ",[21,68,69],{},"AuthApiError"," vindo de ",[21,72,73],{},"signInWithPassword",", com\n",[21,76,77],{},"error.code"," igual a ",[21,80,56],{},". A mesma referência pede para\nidentificar os erros sempre por ",[21,83,77],{}," e ",[21,86,87],{},"error.name",", e isso importa mais\nadiante, quando você decidir o que o seu formulário diz. Se os seus usuários\nestavam logados e depois foram jogados para fora, é outro erro, com\n",[47,90,92],{"href":91},"\u002Fblog\u002Fsupabase-users-logged-out","uma página só dele",".",[10,95,96],{},"Pense no seu formulário de login como o teclado ao lado da porta de um prédio.\nAlguém digita um código e uma luz responde. A verde abre a porta. A vermelha\nacende para um código errado, para um código que nunca foi dado a ninguém e para\num morador que sempre entrou pela porta lateral com um crachá e nunca teve\ncódigo.",[36,98,100],{"id":99},"as-três-pessoas-por-trás-da-mensagem","As três pessoas por trás da mensagem",[10,102,103],{},"Cada uma precisa de uma correção diferente, então vale saber qual você tem na\nfrente.",[10,105,106,109],{},[31,107,108],{},"A senha errada."," A conta existe, tem senha, e o que foi digitado não confere.\nIsso inclui uma senha trocada em outro aparelho e esquecida depois, e um\ngerenciador de senhas que preenche uma antiga.",[10,111,112,115],{},[31,113,114],{},"O endereço sem conta."," Ninguém no seu projeto se cadastrou com aquele e-mail.\nPode ser um segundo endereço (o do trabalho, quando a pessoa se cadastrou com o\npessoal) ou um erro de digitação no cadastro, que agora está salvo como o e-mail\ndela.",[10,117,118,121],{},[31,119,120],{},"A conta sem senha."," A pessoa se cadastrou com Google, GitHub ou outro botão de\nlogin, e o Supabase nunca salvou uma senha para ela. Quando ela volta e digita\numa, não há nada com que comparar. O servidor de Auth confere se existe uma\nsenha salva antes de olhar a digitada, e uma conta sem senha recebe o mesmo 400.",[10,123,124,125,130],{},"Quem se cadastrou com um magic link, o link de login enviado por e-mail, é uma\nvariação do primeiro caso. O\n",[47,126,129],{"href":127,"rel":128},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Fapi\u002Fmagic_link.go",[51],"código de magic link","\ndo Supabase cria a conta com uma senha aleatória que nunca é mostrada a ninguém,\nentão qualquer senha que a pessoa digite está errada.",[132,133],"diagram",{"alt":134,"caption":135,"src":136},"Três pessoas vão até o mesmo teclado: uma com uma chave que não serve, outra desenhada em contorno tracejado porque não existe conta para ela, e outra com um crachá no lugar da chave. Os três caminhos se encontram no teclado, a única luz acende em vermelho e sai uma única resposta idêntica.","Uma senha errada, um endereço desconhecido e uma conta sem senha chegam à mesma verificação e recebem a mesma resposta.","\u002Fblog\u002Fsupabase-invalid-login\u002Fthree-people-one-light-1600x760.png",[36,138,140],{"id":139},"como-descubro-qual-dos-três-foi","Como descubro qual dos três foi?",[10,142,143,144,147],{},"Pergunte ao seu próprio banco de dados. Cada conta do seu projeto é uma linha\nnuma tabela chamada ",[21,145,146],{},"auth.users",", e essa linha diz como a pessoa faz login.",[10,149,150,151,156,157,160],{},"O ",[47,152,155],{"href":153,"rel":154},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fusers",[51],"guia de usuários"," do Supabase\ndescreve o campo que importa: segundo o Supabase, ",[21,158,159],{},"app_metadata.providers"," é a\nlista de provedores com os quais o usuário pode fazer login. Um usuário pode ter\nvárias identidades, então a mesma pessoa pode ter senha e Google ao mesmo tempo.\nSe existe uma senha salva está na coluna que o próprio servidor confere.",[10,162,163,164,167],{},"Abra o ",[31,165,166],{},"SQL Editor"," no painel do Supabase e rode isto com o endereço que a\npessoa passou:",[14,169,172],{"className":170,"code":171,"language":19},[17],"select email,\n       raw_app_meta_data->'providers' as signs_in_with,\n       coalesce(encrypted_password, '') \u003C> '' as has_password,\n       email_confirmed_at\nfrom auth.users\nwhere lower(email) = lower('person@example.com');\n",[21,173,171],{"__ignoreMap":23},[10,175,176],{},"A consulta lê uma linha e nunca mostra uma senha, só se existe uma.",[178,179,180,193],"table",{},[181,182,183],"thead",{},[184,185,186,190],"tr",{},[187,188,189],"th",{},"O que volta",[187,191,192],{},"O que significa",[194,195,196,205,232,244],"tbody",{},[184,197,198,202],{},[199,200,201],"td",{},"Nenhuma linha",[199,203,204],{},"Nenhuma conta tem esse endereço neste projeto. Pergunte que outro endereço a pessoa pode ter usado",[184,206,207,229],{},[199,208,209,212,213,216,217,220,221,224,225,228],{},[21,210,211],{},"has_password"," é ",[21,214,215],{},"false",", e ",[21,218,219],{},"signs_in_with"," lista ",[21,222,223],{},"google",", ",[21,226,227],{},"github"," ou algo parecido",[199,230,231],{},"A pessoa se cadastrou com esse botão e nunca teve senha",[184,233,234,241],{},[199,235,236,212,238],{},[21,237,211],{},[21,239,240],{},"true",[199,242,243],{},"A senha digitada está errada, ou a pessoa se cadastrou com um magic link e nunca soube a dela",[184,245,246,252],{},[199,247,248,251],{},[21,249,250],{},"email_confirmed_at"," está vazio",[199,253,254],{},"O e-mail ainda não foi confirmado, o que vira outra mensagem quando a senha está certa",[10,256,257,258,261],{},"Se você prefere clicar a digitar, ",[31,259,260],{},"Authentication → Users"," no painel mostra as\nmesmas contas.",[36,263,265],{"id":264},"a-conta-que-nunca-teve-senha","A conta que nunca teve senha",[10,267,268],{},"Mande a pessoa de volta ao botão que ela usou, ou deixe que ela crie uma senha\npelo seu link de redefinição.",[10,270,271],{},"No teclado, esse é o morador que sempre usou a porta lateral. Não há nenhum\ncódigo cadastrado para ele, então todo código que ele tenta é recusado.",[10,273,274],{},"O primeiro conserto fica na sua página de login. Se o cadastro oferece\n\"Continuar com o Google\", a página de login precisa do mesmo botão, para que\nquem se cadastrou com ele o veja quando voltar.",[10,276,277,278,283,284,287],{},"Se a pessoa também quiser uma senha, o seu link \"Esqueceu a senha?\" já resolve.\nO\n",[47,279,282],{"href":280,"rel":281},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Fapi\u002Frecover.go",[51],"código de redefinição de senha","\ndo Supabase envia o e-mail de recuperação para qualquer conta que encontrar, sem\nconferir como ela foi criada. Um usuário do Google que segue o link e define uma\nsenha nova consegue entrar dos dois jeitos depois. Isso depende de o seu app ter\na página que define a senha nova, a que chama\n",[21,285,286],{},"supabase.auth.updateUser({ password })",". Se o link cai numa página que nunca\npede senha, a pessoa entra uma vez e continua sem senha.",[36,289,291],{"id":290},"email-not-confirmed-quer-dizer-que-a-senha-estava-certa","\"Email not confirmed\" quer dizer que a senha estava certa",[10,293,294],{},"É outra mensagem, com outro código, e só chega a quem já passou pela verificação\nda senha.",[10,296,297,298,301,302,305],{},"Na mesma função do servidor de Auth, a verificação do e-mail confirmado vem\ndepois da verificação da senha. Então ",[21,299,300],{},"Email not confirmed",", código\n",[21,303,304],{},"email_not_confirmed",", só volta para quem digitou um e-mail existente e a senha\ncorreta dele. A referência de erros do Supabase descreve isso como \"Signing in\nis not allowed for this user as the email address is not confirmed.\" No teclado\né outra luz: o código estava certo, e a porta continua fechada até a papelada da\nmudança terminar.",[10,307,308,309,312,313,318,319,322,323,327,328,93],{},"Você vê essa mensagem quando ",[31,310,311],{},"Confirm email"," está ativado no provedor Email do\nseu projeto. Segundo o\n",[47,314,317],{"href":315,"rel":316},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fgeneral-configuration",[51],"guia de configuração","\ndo Supabase, os usuários precisam então confirmar o endereço de e-mail antes de\nfazer login pela primeira vez. A correção é o e-mail em que a pessoa ainda não\nclicou: diga para ela conferir a caixa de entrada e o spam, e ofereça reenviar\ncom ",[21,320,321],{},"supabase.auth.resend({ type: 'signup', email })",". Se esses e-mails não\nchegam de jeito nenhum,\n",[47,324,326],{"href":325},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","o limite de envio de e-mails"," é a\nprimeira coisa a descartar. Se eles chegam e o link responde \"Email link is\ninvalid or has expired\",\n",[47,329,331],{"href":330},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","provavelmente alguma coisa o abriu antes da pessoa",[10,333,334],{},"Como essa mensagem só aparece depois de uma senha correta, pedir à pessoa que\nconfira a caixa de entrada não dá a um estranho nada que ele já não tivesse.",[36,336,338],{"id":337},"por-que-a-mensagem-continua-vaga","Por que a mensagem continua vaga",[10,340,341],{},"Porque a versão útil contaria a estranhos quem são os seus usuários.",[10,343,344],{},"Imagine o teclado respondendo \"ninguém mora no 4B\". Qualquer pessoa passando\npoderia percorrer a lista de apartamentos e saber quais estão ocupados.",[10,346,347],{},"O seu formulário funciona do mesmo jeito. Se ele dissesse \"Nenhuma conta com esse\ne-mail\", qualquer pessoa com uma lista de endereços poderia digitar um por um e\nsaber quais pertencem aos seus usuários. Um vazamento de algum outro site deixa\numa lista assim para trás, às vezes com as senhas que as pessoas usavam lá. Quem\nsabe quais endereços são seus usuários sabe de quem vale a pena testar senhas\nantigas no seu app, e quem provavelmente vai abrir um e-mail que parece vir de\nvocê.",[10,349,350,351,356],{},"O Supabase aplica a mesma regra em todo lugar onde se digita um endereço. O\n",[47,352,355],{"href":353,"rel":354},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Fapi\u002Fsignup.go",[51],"código de cadastro","\ndele, quando recebe o pedido de criar uma conta para um e-mail já cadastrado e\nconfirmado, pode devolver um usuário inventado com um ID aleatório, por meio de\numa função cujo comentário diz que ela existe para impedir que vaze se um\nusuário está cadastrado ou não. A redefinição de senha responde a um endereço\ndesconhecido com o mesmo sucesso vazio que dá a um conhecido.",[10,358,359,360,363,364,367],{},"O lado do cadastro tem uma chave que você controla. Esse usuário inventado é o\nque volta quando a confirmação é exigida tanto para cadastros por e-mail quanto\npor telefone. Se qualquer uma das duas estiver desligada (a do telefone conta\nmesmo que o seu app nunca use login por telefone), um endereço cadastrado recebe\n",[21,361,362],{},"User already registered",", código ",[21,365,366],{},"user_already_exists",", e o seu formulário de\ncadastro vira, sozinho, um verificador de listas.",[10,369,370,371,374,375,377],{},"A mensagem útil também precisa vir de algum lugar. O Supabase não conta ao seu\napp se um e-mail tem conta, então, para mostrar \"Nenhuma conta com esse e-mail\",\no seu app tem que descobrir sozinho. Isso significa uma consulta que funcione\npara um visitante sem login: uma leitura da sua tabela ",[21,372,373],{},"profiles"," que só dá\ncerto se qualquer pessoa puder ler os e-mails dela, ou uma função do banco de\ndados que procura em ",[21,376,146],{}," para quem perguntar. De um jeito ou de outro,\na lista dos seus usuários fica legível de fora.",[10,379,380,381,93],{},"A primeira delas dá para ver de fora, e é assim que a nossa verificação gratuita\nprocura por ela. Ela pergunta a cada tabela que o seu app cita quantas linhas um\nvisitante sem login conseguiria obter, lê só a contagem e leva cerca de 20\nsegundos, sem conta: ",[47,382,384],{"href":383},"\u002Fsecurity-scanner","verifique seu app",[132,386],{"alt":387,"caption":388,"src":389},"Uma pilha de endereços de e-mail passa por dois formulários de login. O de cima diz quando a conta não existe, e a pilha sai dividida em dois montes, um marcado com visto e outro riscado, com o monte marcado destacado em âmbar. O de baixo dá a cada endereço a mesma resposta, e a pilha sai como um único monte uniforme.","Um formulário que diz quando a conta não existe separa qualquer lista de endereços entre os seus usuários e todo o resto. Uma resposta só para todos deixa a lista como estava.","\u002Fblog\u002Fsupabase-invalid-login\u002Fthe-list-checker-1600x720.png",[36,391,393],{"id":392},"o-que-colocar-na-sua-página-de-login","O que colocar na sua página de login",[10,395,396],{},"Mantenha a mensagem vaga e coloque todas as formas de voltar a entrar na mesma\npágina.",[398,399,400,407,413,419],"ul",{},[401,402,403,406],"li",{},[31,404,405],{},"Uma mensagem só para os três casos",", em palavras simples, com os outros\ncaminhos ao lado: \"O e-mail e a senha não conferem. Se você se cadastrou com\no Google, use o botão abaixo.\" Ela ajuda o usuário do Google e não conta a um\nestranho nada que a sua página de cadastro já não diga.",[401,408,409,412],{},[31,410,411],{},"Todos os métodos da sua página de cadastro."," O botão do Google, o magic\nlink e o campo de senha, todos também na página de login.",[401,414,415,418],{},[31,416,417],{},"Um link \"Esqueceu a senha?\" para uma página que defina uma."," O Supabase\nresponde do mesmo jeito a qualquer endereço ali, então é seguro mostrar, e é\nassim que uma pessoa sem senha consegue uma.",[401,420,421,426,427,429,430,432],{},[31,422,423,424,93],{},"Decisões pelo ",[21,425,77],{}," Mostre a sua mensagem vaga para\n",[21,428,56],{},", e \"confira sua caixa de entrada\" com um botão de\nreenvio para ",[21,431,304],{},". A referência de erros do Supabase pede\npara identificar os erros pelo código em vez do texto da mensagem, e avisa\nque os códigos de status HTTP podem mudar sem aviso.",[10,434,435],{},"Em código, são dois caminhos:",[14,437,440],{"className":438,"code":439,"language":19},[17],"const { error } = await supabase.auth.signInWithPassword({ email, password })\nif (error?.code === 'email_not_confirmed') showCheckYourInbox(email)\nelse if (error) showSignInHelp()\n",[21,441,439],{"__ignoreMap":23},[10,443,444],{},"Se um builder escreve a sua página de login, você pode colar esses quatro pontos\ncomo instrução, inclusive o que diz o que a página deve guardar para si.",[36,446,448],{"id":447},"para-a-sua-página-de-login-continuar-como-você-deixou","Para a sua página de login continuar como você deixou",[10,450,451],{},"Duas coisas ainda podem dar errado depois de hoje: um prompt posterior reescreve\na página para ficar \"mais útil\", e uma mudança em outro lugar perde as contas em\nque a página faz login.",[10,453,454],{},[31,455,456,460],{},[47,457,459],{"href":458},"\u002Fwebsite-monitoring","Reeve Monitor"," continua verificando de fora:",[398,462,463,466,469,472],{},[401,464,465],{},"as nove verificações a cada hora, em até três apps, incluindo quantas linhas um visitante sem login consegue contar nas tabelas que o seu app cita",[401,467,468],{},"um e-mail no dia em que uma nova varredura avaliar o seu app pior que a anterior",[401,470,471],{},"se o app está no ar, a cada 60 segundos",[401,473,474],{},"um relatório mensal, em linguagem simples, do que ele viu",[10,476,477],{},[31,478,479,483],{},[47,480,482],{"href":481},"\u002Fsupabase-backups","Reeve Care"," guarda uma cópia do seu banco de dados\nSupabase, contas incluídas:",[398,485,486,489,492,495,498,501],{},[401,487,488],{},"uma cópia criptografada em uma programação, no armazenamento próprio da Reeve na UE, fora da sua conta do Supabase",[401,490,491],{},"o schema auth onde vivem as contas dos seus usuários, para que elas voltem com todo o resto",[401,493,494],{},"cada cópia verificada antes de contar, contando as linhas de cada tabela",[401,496,497],{},"seus arquivos enviados também, assim que você conectar uma credencial do Storage",[401,499,500],{},"uma restauração com um clique, com uma cópia de segurança do estado atual feita antes",[401,502,503],{},"tudo o que o Monitor faz",[36,505,507],{"id":506},"o-que-fazer-agora","O que fazer agora",[509,510,511],"key-takeaways",{},[398,512,513,519,522,525,528,536],{},[401,514,515,516,518],{},"Rode a consulta em ",[21,517,146],{}," com o endereço que a pessoa passou e veja qual dos três casos é.",[401,520,521],{},"Nenhuma linha: pergunte com que outro endereço ela pode ter se cadastrado.",[401,523,524],{},"Sem senha: indique o botão do Google ou do GitHub que ela usou, ou o seu link de redefinição.",[401,526,527],{},"Com senha e ainda recusada: mande o link de redefinição.",[401,529,530,531,533,534,93],{},"Mostre uma mensagem vaga para ",[21,532,56],{},", e \"confira sua caixa de entrada\" só para ",[21,535,304],{},[401,537,538],{},"Nunca adicione uma verificação que diga a um visitante se um e-mail tem conta.",[10,540,541,542,546,547,551],{},"Se o problema começa um passo antes e as contas novas nem chegam a ser criadas,\n",[47,543,545],{"href":544},"\u002Fblog\u002Fdatabase-error-saving-new-user","Database error saving new user"," cobre esse\nlado do formulário. O ",[47,548,550],{"href":549},"\u002Fchecklist","checklist de segurança de 10 minutos"," cobre o\nque costuma ficar aberto num app recém-lançado.",{"title":23,"searchDepth":553,"depth":553,"links":554},3,[555,557,558,559,560,561,562,563,564],{"id":38,"depth":556,"text":39},2,{"id":99,"depth":556,"text":100},{"id":139,"depth":556,"text":140},{"id":264,"depth":556,"text":265},{"id":290,"depth":556,"text":291},{"id":337,"depth":556,"text":338},{"id":392,"depth":556,"text":393},{"id":447,"depth":556,"text":448},{"id":506,"depth":556,"text":507},"Noções de segurança","\u002Fblog\u002Fsupabase-invalid-login\u002Fcover-1200x630.png","Um teclado ao lado de uma porta com sua única luz acesa em vermelho e, na frente dele, um crachá para o qual o teclado não tem leitor.","O Supabase diz \"Invalid login credentials\" para senha errada, e-mail desconhecido e conta Google. Como saber qual é, e por que é vago.",false,"md",[572,575,578,581,584],{"q":573,"a":574},"Por que o Supabase diz \"Invalid login credentials\" se a senha está certa?","Porque a senha pode estar certa para uma conta que não existe, ou a conta pode nem ter senha. Confira se o e-mail é o mesmo usado no cadastro, e se a pessoa se cadastrou com o Google ou outro botão de login, o que deixa a conta sem senha. Uma consulta em auth.users no SQL Editor mostra qual é o caso.",{"q":576,"a":577},"\"Invalid login credentials\" quer dizer que a conta não existe?","Às vezes. O Supabase devolve a mesma mensagem, com o mesmo código, invalid_credentials, quando nenhuma conta tem aquele e-mail, quando a conta não tem senha e quando a senha está errada. A mensagem sozinha não diz qual, e ela foi feita assim.",{"q":579,"a":580},"Por que quem se cadastrou com o Google não consegue entrar com senha?","Porque a conta foi criada sem senha. O Supabase confere se existe uma senha salva antes de comparar a que foi digitada, e uma conta sem senha recebe \"Invalid login credentials\". A pessoa pode continuar usando o botão do Google ou usar o link de redefinição de senha do seu app para criar uma: o Supabase envia esse e-mail para qualquer conta que encontrar, não importa como ela foi criada.",{"q":582,"a":583},"Meu formulário de login deveria dizer que o e-mail não está cadastrado?","Não. Essa mensagem conta a qualquer pessoa que digite um endereço se ele pertence a um dos seus usuários, e quem tem uma lista de endereços vazados pode conferir todos. Seu app também precisaria de uma consulta que respondesse essa pergunta para estranhos, e isso é um segundo buraco. Mantenha a mensagem vaga e mostre as outras formas de entrar.",{"q":585,"a":586},"Qual a diferença entre \"Invalid login credentials\" e \"Email not confirmed\"?","O Supabase só devolve \"Email not confirmed\" depois de conferir a senha e ver que ela está correta. Então a pessoa certa digitou a senha certa, e a conta está esperando que ela clique no link do e-mail de confirmação. É seguro dizer a ela que confira a caixa de entrada e oferecer o reenvio do e-mail.","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",[589,590,591,592,56,593,594],"invalid login credentials supabase","invalid login credentials","supabase login não funciona","email not confirmed supabase","supabase user enumeration","supabase usuário google sem senha",{},true,"\"Invalid login credentials\" no Supabase","\u002Fblog\u002Fsupabase-invalid-login","2026-10-28",{"title":5,"description":568},"blog\u002Fsupabase-invalid-login",[603,604,605],"O Supabase responde \"Invalid login credentials\" a três pessoas diferentes: quem digitou a senha errada, quem tem um e-mail sem conta e quem se cadastrou com o Google e nunca teve senha.","Ele faz isso de propósito. Um formulário de login que dissesse qual dos três casos foi contaria a qualquer pessoa com uma lista de e-mails quais pertencem aos seus usuários.","Você mesmo pode distinguir os três com uma consulta em auth.users. Sua página de login deve manter a mensagem vaga e oferecer todas as formas pelas quais a conta pode ter sido criada.","r5fjWSbc2iZcuSjCBXRfn6jZOoJFY5ch9bBt5c2ip2Q",[608,614,620,626,632,638,644,650,656,661,667,674,680,681,687,693,699,705,711,717,723,728,733,739,745,751,757,762,768,774,780,786,792,798,804,810,816,822,828,834,840,846,852,858,864,870,875,881,887,893,899,905,911,917,923,929,935,941,947,953,959,965,971,977,983,989,995,1001,1007,1013,1019,1025,1031,1037,1043,1049,1055,1061,1067,1073,1079,1085,1091,1097,1102,1108,1114,1120,1125,1131],{"path":609,"title":610,"description":611,"published":612,"category":565,"image":613,"draft":569},"\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":615,"title":616,"description":617,"published":618,"category":565,"image":619,"draft":569},"\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":621,"title":622,"description":623,"published":624,"category":565,"image":625,"draft":569},"\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":627,"title":628,"description":629,"published":630,"category":565,"image":631,"draft":569},"\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":633,"title":634,"description":635,"published":636,"category":565,"image":637,"draft":569},"\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":639,"title":640,"description":641,"published":642,"category":565,"image":643,"draft":569},"\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":645,"title":646,"description":647,"published":648,"category":565,"image":649,"draft":569},"\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":651,"title":652,"description":653,"published":654,"category":565,"image":655,"draft":569},"\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":330,"title":657,"description":658,"published":659,"category":565,"image":660,"draft":569},"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":662,"title":663,"description":664,"published":665,"category":565,"image":666,"draft":569},"\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":668,"title":669,"description":670,"published":671,"category":672,"image":673,"draft":569},"\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":675,"title":676,"description":677,"published":678,"category":565,"image":679,"draft":569},"\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":598,"title":5,"description":568,"published":599,"category":565,"image":587,"draft":569},{"path":682,"title":683,"description":684,"published":685,"category":565,"image":686,"draft":569},"\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":688,"title":689,"description":690,"published":691,"category":565,"image":692,"draft":569},"\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":694,"title":695,"description":696,"published":697,"category":565,"image":698,"draft":569},"\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":700,"title":701,"description":702,"published":703,"category":565,"image":704,"draft":569},"\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":706,"title":707,"description":708,"published":709,"category":565,"image":710,"draft":569},"\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":712,"title":713,"description":714,"published":715,"category":565,"image":716,"draft":569},"\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":718,"title":719,"description":720,"published":721,"category":565,"image":722,"draft":569},"\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":325,"title":724,"description":725,"published":726,"category":565,"image":727,"draft":569},"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":91,"title":729,"description":730,"published":731,"category":565,"image":732,"draft":569},"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":734,"title":735,"description":736,"published":737,"category":565,"image":738,"draft":569},"\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":740,"title":741,"description":742,"published":743,"category":565,"image":744,"draft":569},"\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":746,"title":747,"description":748,"published":749,"category":565,"image":750,"draft":569},"\u002Fblog\u002Fsupabase-invalid-jwt","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":752,"title":753,"description":754,"published":755,"category":565,"image":756,"draft":569},"\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":544,"title":758,"description":759,"published":760,"category":565,"image":761,"draft":569},"\"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":763,"title":764,"description":765,"published":766,"category":565,"image":767,"draft":569},"\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":769,"title":770,"description":771,"published":772,"category":565,"image":773,"draft":569},"\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":775,"title":776,"description":777,"published":778,"category":565,"image":779,"draft":569},"\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":781,"title":782,"description":783,"published":784,"category":565,"image":785,"draft":569},"\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":787,"title":788,"description":789,"published":790,"category":565,"image":791,"draft":569},"\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":793,"title":794,"description":795,"published":796,"category":565,"image":797,"draft":569},"\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":799,"title":800,"description":801,"published":802,"category":565,"image":803,"draft":569},"\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":805,"title":806,"description":807,"published":808,"category":565,"image":809,"draft":569},"\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":811,"title":812,"description":813,"published":814,"category":565,"image":815,"draft":569},"\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":817,"title":818,"description":819,"published":820,"category":565,"image":821,"draft":569},"\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":823,"title":824,"description":825,"published":826,"category":565,"image":827,"draft":569},"\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":829,"title":830,"description":831,"published":832,"category":565,"image":833,"draft":569},"\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":835,"title":836,"description":837,"published":838,"category":565,"image":839,"draft":569},"\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":841,"title":842,"description":843,"published":844,"category":565,"image":845,"draft":569},"\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":847,"title":848,"description":849,"published":850,"category":565,"image":851,"draft":569},"\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":853,"title":854,"description":855,"published":856,"category":672,"image":857,"draft":569},"\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":859,"title":860,"description":861,"published":862,"category":672,"image":863,"draft":569},"\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":865,"title":866,"description":867,"published":868,"category":672,"image":869,"draft":569},"\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":871,"title":872,"description":873,"published":868,"category":565,"image":874,"draft":569},"\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":876,"title":877,"description":878,"published":879,"category":565,"image":880,"draft":569},"\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":882,"title":883,"description":884,"published":885,"category":565,"image":886,"draft":569},"\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":888,"title":889,"description":890,"published":891,"category":672,"image":892,"draft":569},"\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":894,"title":895,"description":896,"published":897,"category":565,"image":898,"draft":569},"\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":900,"title":901,"description":902,"published":903,"category":565,"image":904,"draft":569},"\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":906,"title":907,"description":908,"published":909,"category":565,"image":910,"draft":569},"\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":912,"title":913,"description":914,"published":915,"category":565,"image":916,"draft":569},"\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":918,"title":919,"description":920,"published":921,"category":565,"image":922,"draft":569},"\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":924,"title":925,"description":926,"published":927,"category":565,"image":928,"draft":569},"\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":930,"title":931,"description":932,"published":933,"category":565,"image":934,"draft":569},"\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":936,"title":937,"description":938,"published":939,"category":565,"image":940,"draft":569},"\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":942,"title":943,"description":944,"published":945,"category":672,"image":946,"draft":569},"\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":948,"title":949,"description":950,"published":951,"category":672,"image":952,"draft":569},"\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":954,"title":955,"description":956,"published":957,"category":672,"image":958,"draft":569},"\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":960,"title":961,"description":962,"published":963,"category":565,"image":964,"draft":569},"\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":966,"title":967,"description":968,"published":969,"category":565,"image":970,"draft":569},"\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":972,"title":973,"description":974,"published":975,"category":565,"image":976,"draft":569},"\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":978,"title":979,"description":980,"published":981,"category":565,"image":982,"draft":569},"\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":984,"title":985,"description":986,"published":987,"category":565,"image":988,"draft":569},"\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":990,"title":991,"description":992,"published":993,"category":565,"image":994,"draft":569},"\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":996,"title":997,"description":998,"published":999,"category":565,"image":1000,"draft":569},"\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":1002,"title":1003,"description":1004,"published":1005,"category":565,"image":1006,"draft":569},"\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":1008,"title":1009,"description":1010,"published":1011,"category":565,"image":1012,"draft":569},"\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":1014,"title":1015,"description":1016,"published":1017,"category":565,"image":1018,"draft":569},"\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":1020,"title":1021,"description":1022,"published":1023,"category":672,"image":1024,"draft":569},"\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":1026,"title":1027,"description":1028,"published":1029,"category":565,"image":1030,"draft":569},"\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":1032,"title":1033,"description":1034,"published":1035,"category":672,"image":1036,"draft":569},"\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":1038,"title":1039,"description":1040,"published":1041,"category":565,"image":1042,"draft":569},"\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":1044,"title":1045,"description":1046,"published":1047,"category":565,"image":1048,"draft":569},"\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":1050,"title":1051,"description":1052,"published":1053,"category":565,"image":1054,"draft":569},"\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":1056,"title":1057,"description":1058,"published":1059,"category":565,"image":1060,"draft":569},"\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":1062,"title":1063,"description":1064,"published":1065,"category":672,"image":1066,"draft":569},"\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":1068,"title":1069,"description":1070,"published":1071,"category":672,"image":1072,"draft":569},"\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":1074,"title":1075,"description":1076,"published":1077,"category":565,"image":1078,"draft":569},"\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":1080,"title":1081,"description":1082,"published":1083,"category":565,"image":1084,"draft":569},"\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":1086,"title":1087,"description":1088,"published":1089,"category":672,"image":1090,"draft":569},"\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":1092,"title":1093,"description":1094,"published":1095,"category":565,"image":1096,"draft":569},"\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":1098,"title":1099,"description":1100,"published":1095,"category":565,"image":1101,"draft":569},"\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":1103,"title":1104,"description":1105,"published":1106,"category":565,"image":1107,"draft":569},"\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":1109,"title":1110,"description":1111,"published":1112,"category":672,"image":1113,"draft":569},"\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":1115,"title":1116,"description":1117,"published":1118,"category":565,"image":1119,"draft":569},"\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":1121,"title":1122,"description":1123,"published":1118,"category":672,"image":1124,"draft":569},"\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":1126,"title":1127,"description":1128,"published":1129,"category":672,"image":1130,"draft":569},"\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":1132,"title":1133,"description":1134,"published":1129,"category":565,"image":1135,"draft":569},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","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",1794213649056]