📄 SKILL.md

← Vault

name: supabase-gotrue-jwt-secret-mismatch

description: Diagnóstico e correção de GoTrue self-hosted rejectando JWT com "invalid signature" — token de serviço com chave secreta desatualizada

triggers:

- GoTrue 401 invalid JWT signature

- SERVICE_ROLE_KEY JWT verification failing

- JWT secret mismatch in self-hosted Supabase


Supabase Self-Hosted: JWT Secret Mismatch no GoTrue

Sintoma

Edge functions (ou chamadas diretas) usando SERVICE_ROLE_KEY para admin via /auth/v1/admin/* retornam:

`

{"msg":"invalid JWT: unable to parse or verify signature, signature is invalid"}

`

Mas o mesmo token funciona para PostgREST (REST API).

Diagnóstico

1. Identificar a JWT_SECRET atual do container GoTrue

`bash

sshpass -p '' ssh -o StrictHostKeyChecking=no root@ \

"docker exec deploy-vps-auth-1 env | grep -E 'JWT_SECRET|GOTRUE_JWT_SECRET'"

`

2. Gerar token de teste com a chave atual

`python

python3 << 'EOF'

import jwt, time

secret = '' # ex: kETxz0JNJhJyg5UYxbd8zG6g2v9kXTYZGjY+3v7LUKI=

payload = {

'iss': 'supabase', 'ref': 'rochasales',

'role': 'supabase_admin',

'iat': int(time.time()),

'exp': int(time.time()) + 28800,

'is_super_admin': True,

'email': 'service_role@rochasales'

}

print(jwt.encode(payload, secret, algorithm='HS256'))

EOF

`

3. Testar diretamente no GoTrue (bypass Kong)

`bash

docker exec deploy-vps-auth-1 wget -O- -q 'http://127.0.0.1:9999/admin/users' \

--header="Authorization: Bearer " \

--header="apikey: "

`

Se o novo token funciona → o SERVICE_ROLE_KEY no container está desatualizado (gerado com chave secreta antiga).

Solução

Opção A: Atualizar o SERVICE_ROLE_KEY no container (substituição direta)

`bash

Gerar o novo token (veja passo 2 acima)

NOVO_TOKEN=""

Verificar nome da variável no container

sshpass -p '' ssh root@ \

"docker exec deploy-vps-auth-1 env | grep SERVICE_ROLE_KEY"

Anotar o nome exato da variável (ex: SUPABASE_SERVICE_ROLE_KEY)

Aplicar temporariamente (sobrevive reinício do container mas não do docker compose)

sshpass -p '' ssh root@ \

"docker exec deploy-vps-auth-1 env set SERVICE_ROLE_KEY=$NOVO_TOKEN"

`

Opção B: Atualizar via docker-compose secrets (permanente)

`bash

No diretório com docker-compose.yml do Supabase:

echo "" | docker secret create supabase_service_role_key -

docker-compose up -d auth

`

Opção C: Atualizar .env se tiver acesso

Se a .env do docker-compose contém GOTRUE_JWT_SECRET, atualize também SERVICE_ROLE_KEY com o novo token gerado na mesma secret.

Por que acontece

Quando o Supabase self-hosted é migrado ou recriado (reinstall, backup restore), o JWT_SECRET pode ser regenerado. O SERVICE_ROLE_KEY é um JWT fixo salvo em config/secrets — não se atualiza automaticamente. Resultado: tokens emitidos pelo serviço têm assinaturas incompatíveis com a nova chave.

Verificação pós-correção

`bash

Testar listar usuários (bypass Kong direto ao GoTrue)

docker exec deploy-vps-auth-1 wget -O- -q 'http://127.0.0.1:9999/admin/users' \

--header="Authorization: Bearer " \

--header="apikey: "

Esperado: JSON com array de usuários, status 200

`

Armadilhas