Playbook — n8n Cloud Supabase credential revoked after a Supabase key rotation

Trigger: A workflow on n8n Cloud (https://app.n8n.cloud / API https://p24.app.n8n.cloud) that reads/writes Supabase starts failing with HTTP 401 — e.g. Legacy API keys are disabled or Unregistered API key — at the first Supabase node. First seen on issue #1987: credential kapibara_supabase (XZylX4DaTinlilTL) kept the disabled legacy JWT after Supabase disabled legacy keys on 2026-06-21, breaking the ecotrans - docs 4 fibu 2025 document pipeline.

This is the Cloud counterpart of n8n-supabase-credential-rotation.md. That playbook fixes self-hosted bms-4 n8n via docker exec … n8n import:credentials. None of it applies to n8n Cloud — there is no Docker, no shell, and (critically) no API path to update a credential. Use this playbook for anything under app.n8n.cloud.

Why the Cloud case is different — the n8n Cloud Public API cannot update credentials

Verified against https://p24.app.n8n.cloud/api/v1 (#1987):

CallResultMeaning
GET /credentials405 Method Not AllowedCredentials cannot be listed or read via API
GET /credentials/{id}not exposedCannot read a credential’s embedded value
PATCH /credentials/{id}405 Method Not AllowedCannot update a credential in place
POST /credentialsallowedCreate a new credential (gets a new id)
DELETE /credentials/{id}allowedDelete a credential
GET /workflows, GET /workflows/{id}allowedWorkflow JSON does expose each node’s credential {id,name} reference (not the secret)

Consequence: there is no safe automated way for a code-worker to set the new key on the existing credential. The only programmatic alternative — DELETE then POST a replacement — mints a new credential id, which then has to be re-pointed in every workflow node that referenced the old id, on a live production instance. Because GET /credentials is 405 you cannot even enumerate the consumers reliably. Do not attempt delete+recreate autonomously. Fix via the UI (human or Playwright agent), as below.

The affected credential and workflow (#1987)

ItemValue
Credential namekapibara_supabase
Credential idXZylX4DaTinlilTL
Credential typesupabaseApi → key lives in the Service Role Secret field (serviceRole)
Workflowecotrans - docs 4 fibu 2025 - creating and uploading docs to google drive folders office / month (vuZ1bgFHeiLr6JXp, active)
Failing nodesupabaseLogs (n8n-nodes-base.supabase) — first Supabase write; run dies after 1 file
ScheduleTue + Fri 21:00 CEST (19:00 UTC); both prior runs returned 401

Where the new key lives

The new-format Supabase service key is already in SOPS — no need to mint one:

# Existence/format check only — never print the value
sops -d --input-type dotenv --output-type dotenv secrets/monitoring.env.sops \
  | grep -q '^SUPABASE_SERVICE_KEY=sb_secret_' && echo "new sb_secret_ key present" || echo "check SOPS"

secrets/monitoring.env.sops → SUPABASE_SERVICE_KEY holds the sb_secret_* service-role key for project mwkqmgadqnkkihjdeqsi (https://mwkqmgadqnkkihjdeqsi.supabase.co). (For the self-hosted n8n the equivalent lives in secrets/n8n-bms4.env.sops → SUPABASE_SERVICE_ROLE_KEY.)

Fix — via the n8n Cloud UI (manual; ~5 min)

The n8n Cloud login (radieu@gmail.com + account password) is in secrets/monitoring.env.sops — reference the key name only, never print the value.

  1. Read the new key silently from SOPS (do not echo it):
    NEWKEY=$(sops -d --input-type dotenv --output-type dotenv secrets/monitoring.env.sops \
      | grep -m1 '^SUPABASE_SERVICE_KEY=' | cut -d= -f2- | tr -d '"')
    # paste $NEWKEY into the UI field below, then: unset NEWKEY
  2. Log in to https://app.n8n.cloud (radieu@gmail.com).
  3. Credentials → open kapibara_supabase (XZylX4DaTinlilTL).
  4. Replace the Service Role Secret with the sb_secret_* value → Save.
    • Optionally use the credential’s Test / Reconnect button to confirm it authenticates.
  5. Audit the rest: in Credentials, open every other Supabase-type credential (and any httpHeaderAuth credential whose value is a Supabase key) and replace any legacy eyJ... value with the SOPS key the same way. The API cannot enumerate these, so this audit must be done in the UI.
  6. Re-run the backlog: open ecotrans - docs 4 fibu 2025 (vuZ1bgFHeiLr6JXp) → Execute Workflow (or retry the failed executions). ~2 missed runs × ~600 files ≈ ~1200 files pending.

Fix — via a Playwright agent (unattended alternative)

Same shape as n8n-cloud-api-key-rotation.md Option A: spawn a Playwright agent that logs in with the SOPS-held account password, opens credential XZylX4DaTinlilTL, pastes the sb_secret_* value from secrets/monitoring.env.sops → SUPABASE_SERVICE_KEY into the Service Role Secret field, saves, then triggers vuZ1bgFHeiLr6JXp. The agent must never print any secret value.

Verify

# Workflow JSON still references the same credential id (name/id unchanged after a UI value edit)
APIKEY=$(sops -d --input-type dotenv --output-type dotenv secrets/monitoring.env.sops \
  | grep -m1 '^N8N_CLOUD_API_KEY=' | cut -d= -f2- | tr -d '"')
curl -s "https://p24.app.n8n.cloud/api/v1/workflows/vuZ1bgFHeiLr6JXp" \
  -H "X-N8N-API-KEY: $APIKEY" \
  | jq -r '.nodes[] | select(.type=="n8n-nodes-base.supabase") | .credentials.supabaseApi'
unset APIKEY
# In the n8n UI: the latest execution of vuZ1bgFHeiLr6JXp is "success" and processes all files
# (not just 1), and supabaseLogs no longer returns 401.

Prevention

  • secrets-sync.yml distributes SOPS → on-server .env files, but does not touch n8n credentials on either self-hosted or Cloud n8n. Cloud has no equivalent of scripts/sync-n8n-supabase-creds.py because the API cannot write credential values (405). After any Supabase key rotation, the Cloud credentials must be updated manually in the UI — add this to the rotation checklist in supabase-service-key-rotation.md.
  • There is no automated alert for an expired n8n Cloud credential; the n8n-cloud-exporter reports execution status, so a workflow stuck on 401 shows as repeated failed executions in Grafana.