name: supabase-cloud-auth-manual-setup-fix
description: Fix "Database error querying schema" on Supabase Cloud when auth schema was created manually (without migrations) — RLS blocking GoTrue, missing policies, missing grants
category: devops
Supabase Cloud — Auth Schema Criado Manualmente: Fix "Database error querying schema"
O Problema
Ao criar tabelas de auth (auth.users, etc.) manualmente via Management API (sem usar migrations nativas do Supabase), o GoTrue (backend de autenticação) falha com:
`
{"code":500,"error_code":"unexpected_failure","msg":"Database error querying schema","error_id":"...-GRU"}
`
mesmo quando o utilizador existe em auth.users com email_confirmed_at preenchido.
Diagnóstico
O erro Database error querying schema indica que o GoTrue consegue conectar à base de dados mas não consegue ler a schema auth. Causas comuns:
1. RLS ativo em auth.users sem policies — o authenticator role não tem policies para ler
2. Falta GRANT USAGE ON SCHEMA auth — o authenticator não tem permissão na schema
3. Falta GRANT SELECT ON auth.users TO authenticator — o role não consegue ler a tabela
Passos de Diagnóstico
`bash
1. Verificar se RLS está ativo na auth.users
curl -s -X POST "https://api.supabase.com/v1/projects/{REF}/database/query" \
-H "Authorization: Bearer {SERVICE_ROLE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query": "SELECT relname, relrowsecurity FROM pg_class WHERE relname = '\''users'\'' AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = '\''auth'\'');"}'
2. Verificar policies em auth.users
curl -s -X POST "https://api.supabase.com/v1/projects/{REF}/database/query" \
-H "Authorization: Bearer {SERVICE_ROLE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query": "SELECT polname, polcmd FROM pg_policy WHERE polrelid = '\''auth.users'\''::regclass;"}'
3. Verificar grants na schema auth
curl -s -X POST "https://api.supabase.com/v1/projects/{REF}/database/query" \
-H "Authorization: Bearer {SERVICE_ROLE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query": "SELECT grantee, privilege_type FROM information_schema.schema_privileges WHERE table_schema = '\''auth'\'';"}'
4. Testar se SET ROLE funciona (se falhar com "permission denied" = problema de grants)
curl -s -X POST "https://api.supabase.com/v1/projects/{REF}/database/query" \
-H "Authorization: Bearer {SERVICE_ROLE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query": "SET ROLE authenticator; SELECT id, email FROM auth.users LIMIT 1;"}'
`
Fix Completo (Executar pela ordem)
Passo 1: GRANT USAGE na schema auth
`sql
GRANT USAGE ON SCHEMA auth TO authenticator, anon, authenticated, service_role, postgres;
`
Passo 2: GRANT SELECT em auth.users para todos os roles
`sql
GRANT SELECT ON auth.users TO authenticator, anon, authenticated, service_role, postgres;
`
Passo 3: Criar policies RLS em auth.users
`sql
-- Para o authenticator (GoTrue usa este role internamente)
CREATE POLICY "authenticator_select" ON auth.users TO authenticator USING (true);
-- Para SELECT simples via PostgREST
CREATE POLICY "anon_select" ON auth.users TO anon USING (true);
CREATE POLICY "authenticated_select" ON auth.users TO authenticated USING (true);
CREATE POLICY "service_role_all" ON auth.users TO service_role USING (true) WITH CHECK (true);
`
Passo 4: Adicionar policies noutras tabelas auth (se existirem)
`sql
-- Se existirem as tabelas abaixo com RLS ativo, adicionar policies
CREATE POLICY "authenticator_all_identities" ON auth.identities TO authenticator USING (true) WITH CHECK (true);
CREATE POLICY "authenticator_all_sessions" ON auth.sessions TO authenticator USING (true) WITH CHECK (true);
CREATE POLICY "authenticator_all_refresh_tokens" ON auth.refresh_tokens TO authenticator USING (true) WITH CHECK (true);
`
Passo 5: Verificar colunas essenciais em auth.users
O utilizador precisa destes campos preenchidos para login funcionar:
`sql
-- Atualizar se necessário
UPDATE auth.users SET
email_confirmed_at = COALESCE(email_confirmed_at, now()),
confirmed_at = COALESCE(confirmed_at, now()),
raw_app_meta_data = COALESCE(raw_app_meta_data, '{"provider":"email","providers":["email"]}'::jsonb)
WHERE id = 'USER_UUID';
`
Testar o Login
`bash
curl -s -X POST "https://{REF}.supabase.co/auth/v1/token?grant_type=password" \
-H "Content-Type: application/json" \
-H "apikey: {ANON_KEY}" \
-d '{"email": "user@example.com", "password": "password123"}'
`
Se retornar {"access_token": "...", "token_type": "bearer", ...} → OK ✅
Se retornar erro 500 com Database error querying schema → policies/grants ainda em falta.
Alternativa Mais Simples
Se o problema persistir, a forma mais fiável é criar o utilizador pelo Supabase Dashboard:
1. Ir a Supabase Dashboard
2. Clicar em "Add User" → "Create a new user"
3. Preencher email e password
4. Clicar em "Create user"
O Dashboard usa a API interna do Supabase que configura tudo corretamente.
Problema Avançado: Auth Schema Criado Completamente à Mão
Se criaste TODAS as tabelas auth.* manualmente (não apenas adicionaste policies a um schema já existente do Supabase), o GoTrue pode ter problemas mais profundos:
Sintomas
- - Todas as policies e grants estão corretos (
SET ROLE authenticatorfunciona) - -
auth.userstem o utilizador comemail_confirmed_atpreenchido - -
auth.instancestem o registo da instância - - Mas login retorna sempre
500: Database error querying schema - - Funções internas de validação do GoTrue
- - Views internas que o GoTrue consulta
- - Configurações internas (
auth.instances,auth.schema_migrations) - - Usar o Supabase Dashboard para criar o utilizador — o Dashboard usa a API interna que configura tudo corretamente
- - Abrir ticket de suporte ao Supabase pedindo para "repair auth schema"
- - Criar novo projeto Supabase e usar a mesma approach (Deploy > Database > Auth funcionando corretamente)
- - Não usar
ALTER TABLE auth.users DISABLE ROW LEVEL SECURITY— retornamust be owner of table usersporque a tabela pertence ao superusersupabase_admin - - O management API token (
sbp_...) não é o mesmo que oservice_roleJWT — o management token serve para DDL via/v1/projects/{ref}/database/query - - O JWT do service_role (
eyJ...service_role...) serve para chamadas PostgREST com privilégios elevados, mas NÃO resolve problemas de RLS no auth schema - - O erro "Invalid API key" pode significar que o token está mal formatado ou o projeto não existe nesse endpoint
- - Testar primeiro com
service_roleJWT (não o management token) para distinguir se o problema é RLS ou autenticação mesmo
Causa Raiz
O GoTrue (servidor de auth do Supabase) guarda cache interno da schema e expects certain internal functions/views that are created by Supabase's own migration system. Quando a schema auth é criada completamente à mão, podem faltar:
Diagnóstico Extra
`bash
Verificar se auth.instances tem registos (pode estar vazio)
curl -s -X POST "https://api.supabase.com/v1/projects/{REF}/database/query" \
-H "Authorization: Bearer {SERVICE_ROLE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query": "SELECT * FROM auth.instances;"}'
Verificar migrations (se existir tabela)
curl -s -X POST "https://api.supabase.com/v1/projects/{REF}/database/query" \
-H "Authorization: Bearer {SERVICE_ROLE_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"query": "SELECT * FROM auth.schema_migrations ORDER BY version LIMIT 3;"}'
`
Soluções (pela ordem de tentativa)
1. Inserir em auth.instances se estiver vazio:
`sql
INSERT INTO auth.instances (id, uuid, raw_base_config, created_at)
VALUES ('00000000-0000-0000-0000-000000000000', '{PROJECT_REF}', NULL, now())
ON CONFLICT (id) DO NOTHING;
`
2. Gerar hash bcrypt correto para a password (se souber a password em plaintext):
`sql
-- Obter salt primeiro
SELECT gen_salt('bf');
-- Gerar hash (substituir SALT pelo resultado do comando acima)
SELECT crypt('PASSWORD_AQUI', 'SALT_AQUI');
-- Atualizar password
UPDATE auth.users SET encrypted_password = 'HASH_GERADO', updated_at = now()
WHERE email = 'user@example.com';
`
3. Se nada funcionar — é um problema de infraestrutura interna do Supabase Cloud:
O GoTrue no Supabase Cloud é um serviço gerido. Quando a schema auth foi criada completamente à mão (sem passar pelas migrations internas do Supabase), o GoTrue pode ter conflitos de cache ou configurações internas em falta que não podem ser corrigidas via Management API.
Soluções possíveis:
Quando Criar Users via Dashboard é a Única Opção
Se após aplicar todos os passos acima o login continuar a falhar com Database error querying schema, significa que o GoTrue não consegue operar corretamente com a schema auth criada manualmente. Nesse caso:
1. Criar o utilizador pelo Dashboard (mesmo que já exista na tabela — o Dashboard reconfigura os internals)
2. Ou usar o Supabase Auth viaedge functions em vez do auth nativo