Alpha. Contributes ctx.postgres — an RLS-scoped pg client, the safe
version of "authenticate, then query as the user". This is the
direct-connection counterpart to withSupabaseClient, and its service-role
companion is withPostgresAdminClient
(@supabase/server/middleware/postgres-admin).
Every query runs in its own short transaction that injects the caller's
claims and drops to their role, exactly like PostgREST:
Everything is transaction-local, so nothing leaks onto the pooled connection.
Only authenticated and anon are assumed. A token naming any other role —
including service_role — is refused with a 500 and
code: 'UNSUPPORTED_ROLE', never silently downgraded to anon: running the
query as the wrong identity would return zero rows and leave nothing to
debug. Bypassing RLS is a separate, explicit opt-in: compose
withPostgresAdminClient.
Custom roles. Supabase supports custom Postgres roles via the role
claim, and RLS still applies to them. They are not supported here yet, so
such a token is refused rather than downgraded.
Reads the caller's claims from ctx.jwtClaims, which withSupabase
populates (JWKS-verified) — so after withSupabase in a pipeline it composes
directly:
Alpha. Contributes
ctx.postgres— an RLS-scopedpgclient, the safe version of "authenticate, then query as the user". This is the direct-connection counterpart towithSupabaseClient, and its service-role companion iswithPostgresAdminClient(@supabase/server/middleware/postgres-admin).Every query runs in its own short transaction that injects the caller's claims and drops to their role, exactly like PostgREST:
Everything is transaction-local, so nothing leaks onto the pooled connection.
Only
authenticatedandanonare assumed. A token naming any other role — includingservice_role— is refused with a 500 andcode: 'UNSUPPORTED_ROLE', never silently downgraded toanon: running the query as the wrong identity would return zero rows and leave nothing to debug. Bypassing RLS is a separate, explicit opt-in: composewithPostgresAdminClient.Reads the caller's claims from
ctx.jwtClaims, whichwithSupabasepopulates (JWKS-verified) — so afterwithSupabasein a pipeline it composes directly:Standalone (no
withSupabase), pair it withwithClaimssoctx.jwtClaimsis present before it runs.