Supabase backup without sharing the database password
A backup integration needs two different kinds of access: Management API permission to prepare the job, and a Postgres login for pg_dump. Those credentials do not have the same privilege boundary.
ReviveDB avoids collecting the long-lived production database password. Instead it uses Supabase OAuth to create a separate, temporary Postgres login immediately before each backup.
Why OAuth alone is not a Postgres login
A complete logical backup uses pg_dump. It connects to Postgres directly, so a Supabase OAuth token is not itself a database credential. The OAuth integration guide documents the available project-management scopes separately from direct database access.
Supabase also has Temporary Access, often called JIT. It lets a Supabase user connect to Postgres with a personal or dashboard token. In our OAuth-app test, the JIT authorization endpoint returned:
HTTP 406: "Failed to get user's JIT access for project"We reproduced that response again on 5 August 2026. Other documented OAuth routes do work, so this is a specific JIT limitation rather than a general OAuth or documentation failure.
The route that works
The Management API does allow an OAuth app with database write permission to run a SQL query. We use that route to create a purpose-built Postgres login immediately before a backup.
The permission boundary matters: database:write belongs to the encrypted OAuth management grant. The temporary login used by pg_dump is a different credential and is read-only.
- It receives a random password and is used for one backup run.
- It can read every schema through pg_read_all_data.
- It uses BYPASSRLS so protected rows are included rather than silently omitted.
- It cannot write application data, create roles or databases, replicate, or act as superuser.
- It is limited to five database connections and expires after six hours.
- The backup worker drops it when the job finishes, including after a failed run.
BYPASSRLS is broad read access. It has to be: without it, pg_dump can succeed while leaving out rows protected by row-level security. The role can read the full database while the backup runs, but it cannot change it.
How we tested it
We first checked access to every discovered table and to auth.users. We then ran a real pg_dump through the normal backup pipeline. The dump included Auth data and rows behind RLS.
After the backup completed, we checked Postgres directly rather than relying on a cleanup log:
SELECT rolname, rolcanlogin, rolvaliduntil
FROM pg_roles
WHERE rolname LIKE 'revivedb_b_%'
ORDER BY rolname;The query returned zero rows. PostgreSQL also enforces the six-hour expiry, so a missed cleanup request does not leave working access behind indefinitely.
What this changes
The integration never receives, stores or resets the project's production database password. The temporary login exists only for the backup and has fewer privileges than the main postgres role.
This does not make the whole integration read-only. The OAuth grant includes database:write because Supabase classifies creating and removing the login as management writes. The improvement is a read-only, short-lived backup session instead of sharing a permanent production database credential.
The workaround also depends on Supabase accepting role creation through its SQL endpoint. We verify that before saving a connection. If role creation, table access or pg_dump fails, setup fails instead of producing a partial backup.
The narrower API we would prefer
Supabase also exposes a temporary CLI login endpoint. A read-only login from that route worked after retrying the same credential while Supavisor refreshed it. It is not suitable for concurrent backup workers, however: repeated requests returned the same username with a new password, and the second request invalidated the first credential.
The ideal endpoint would issue a unique, job-scoped read-only login using only database:read. Until that exists, integrations must either ask users to provision a credential manually or protect a broader OAuth grant while enforcing a read-only backup session themselves.
Using this in ReviveDB
ReviveDB now uses this temporary-role flow for supported Supabase projects. Connecting a project no longer requires its database password. Each database backup is then restored in isolated Postgres before its recovery point is marked verified. See the Supabase backup page for the full access model.