📄 SKILL.md

← Vault

name: supabase-edge-function-401-debug

description: Debug 401 Unauthorized errors in Supabase Edge Functions when JWT verification fails despite valid tokens

category: devops


Supabase Edge Function 401 Unauthorized Debug

Problem

Edge Function /functions/v1/manage-users always returns {"error":"Unauthorized"} even with valid JWT tokens. The signature verification fails silently.

Root Cause

Trailing newline (\n) in GOTRUE_JWT_SECRET environment variable in the auth container. The auth signs tokens with secret+\n, but the functions container's JWT_SECRET (without \n) tries to verify with the raw secret. Signatures never match.

Discovery Method

When JWT_SECRET appears byte-identical via hex dump but tokens still fail verification, check for trailing newlines:

`bash

docker exec sh -c 'echo $GOTRUE_JWT_SECRET | wc -c'

docker exec sh -c 'echo $JWT_SECRET | wc -c'

If auth has +1 byte, there's a trailing \n

`

Architecture on VPS

`

Kong → nginx (functions-proxy:9000) → Deno runtime (functions-1:9000)

`

The nginx just proxy-passes, no auth filtering there.

Key Discovery Steps

1. JWT token valid via Python verification → problem is on the verification side

2. Kong in DB-less mode, no auth plugins

3. Kong routes to functions-proxy (nginx), which proxies to functions-1 (Deno)

4. Deno runtime uses --main-service /home/deno/functions/main but /manage-users also works

5. Edge Function code in container at /home/deno/functions/manage-users/index.ts

6. docker logs often shows no application logs (only shutdown signals)

7. Python hmac.new() with base64url encoding can verify signatures independently

Solution

Remove the trailing \n from GOTRUE_JWT_SECRET in the auth container's environment or add it to JWT_SECRET in the functions container to match.

Prevention

When setting JWT_SECRET in docker-compose or environment files, ensure no trailing newlines. Use echo -n when setting env vars in shell scripts.