name: comercialrs-supabase-auth-debug
description: Debug OAuth login issues on Supabase Cloud + TanStack Start VPS app — SSR crashes, 401 errors, wrong user IDs
ComercialRS Supabase Auth Debugging
Contexto
Deploy Lovable/TanStack Start no VPS (documentos.rochasalesseguros.com.br) com Supabase Cloud (dauftiqcvgaydddoxqhh). OAuth via Google funcionando no browser mas login não persistia.
Problema 1: SSR crash no Node.js (502 Bad Gateway)
Sintoma: Servidor crashava ao fazer redirect OAuth para /. Nginx retornava 502. Systemd mostrava reinicializações frequentes.
Causa raiz: O AuthProvider em __root.tsx chama supabase.auth.getSession() durante SSR. Em contexto Node.js, isso pode quebrar porque localStorage não existe no servidor.
Fix: Adicionar ssr: false em TODAS as rotas que usam auth:
`tsx
export const Route = createFileRoute("/")({
ssr: false,
component: () =>
});
`
Verificação:
`bash
grep -r "createFileRoute" app/src/routes/ --include="*.tsx" | grep -v node_modules
`
Problema 2: Google OAuth cria user ID diferente do email/password
Sintoma: Login Google mostrava email correto no console, mas todas as chamadas API retornavam 401.
Causa raiz: O usuário existia no Supabase com email/password (ou outro provider) com ID A. Quando fez login Google, o Google criou um NOVO usuário com ID B. O profile e roles estavam atrelados ao ID antigo A.
Fix: Criar profile e roles para o ID do Google:
`sql
-- Encontrar o ID do usuário Google:
-- DevTools > Application > Local Storage > sb-{ref}-auth-token > decodificar JWT (base64)
-- O campo "sub" do payload é o user_id
INSERT INTO profiles (user_id, email, full_name, role)
VALUES ('{google_user_id}', 'email@gmail.com', 'Nome', 'admin');
INSERT INTO user_roles (user_id, role)
VALUES ('{google_user_id}', 'adm');
`
Problema 3: Token expira rápido no implicit flow
Sintoma: Após login, 1-2 requests funcionavam e depois 401.
Causa: O implicit flow (hash #access_token=) não fornece refresh_token de verdade. O access token expira rapidamente.
Fix: PKCE flow (?code=). O exchangeCodeForSession gerencia refresh automaticamente.
Fluxo OAuth Debug Checklist
1. Verificar ssr: false em todas as rotas auth-dependent
2. Verificar user_id: Console → JSON.parse(atob(token.split('.')[1])).sub → comparar com profile user_id no banco
3. Verificar profile existe: SELECT * FROM profiles WHERE email = 'user@email.com'
4. Verificar roles existem: SELECT * FROM user_roles WHERE user_id = 'google_id'
5. Testar em aba anônima para evitar conflito com sessões antigas
Rebuild/Deploy
`bash
cd /var/www/documentos/deploy-vps-nodejs/app
source ~/.nvm/nvm.sh && nvm use 20
npm run build
rm -rf assets && ln -sf dist/client/assets assets
systemctl restart documentos
`
Password Reset via admin-reset-user-password Edge Function
Function location: var/www/comercialrs/supabase/functions/admin-reset-user-password/index.ts
Payload:
`json
{ "user_id": "
`
Returns: {"ok": true} on success (NOT the user object).
⚠️ Critical quirk: Multiple rapid calls can silently fail — password is NOT set even though response says ok:true. ALWAYS verify immediately via REST Auth API:
`python
import urllib.request, json
anon_key = "eyJh..."
data = json.dumps({"email": "user@email.com", "password": "password"}).encode()
req = urllib.request.Request(
"https://dauftiqcvgaydddoxqhh.supabase.co/auth/v1/token?grant_type=password",
data=data, headers={"Content-Type": "application/json", "apikey": anon_key}, method="POST"
)
with urllib.request.urlopen(req, timeout=15) as resp:
result = json.loads(resp.read().decode())
print("Login OK:", result["access_token"][:30])
`
If REST API says invalid credentials but function returned ok:true: this is a timing bug. Workaround: call function ONCE, immediately verify via REST. If fails, retry with a DIFFERENT new password.
RLS Policy for Edge Functions Writing to Custom Tables
Edge Functions write to custom tables (like alert_throttle) as anon role by default (when called with anon key). The service_role key bypasses RLS inside the function but external REST calls still enforce RLS.
Minimal RLS for INSERT + SELECT by anon:
`sql
CREATE POLICY alert_throttle_all ON public.alert_throttle
FOR ALL TO anon USING (true) WITH CHECK (true);
`
Verify INSERT works (should return 201):
`python
import urllib.request, json
data = json.dumps([{"signature": "test", "event_type": "test", "..."}]).encode()
req = urllib.request.Request(
"https://dauftiqcvgaydddoxqhh.supabase.co/rest/v1/alert_throttle",
data=data,
headers={"Authorization": f"Bearer {anon_key}", "apikey": anon_key,
"Content-Type": "application/json", "Prefer": "return=minimal"},
method="POST"
)
201 = success, 4xx = RLS blocking it
`
Quick Auth Debug Checklist
1. Query auth.users — check email_confirmed_at, confirmation_token, last_sign_in_at
2. If email_confirmed_at IS NULL: UPDATE auth.users SET email_confirmed_at = now() WHERE id = '...';
3. If login still fails after reset: test via REST Auth API directly (bypasses UI)
4. Check profiles table has matching record for the user
Projeto
- - Supabase:
dauftiqcvgaydddoxqhh - - VPS: 31.97.243.106, app em
/var/www/documentos/deploy-vps-nodejs/app - - URL:
https://documentos.rochasalesseguros.com.br