Transaction-mode pooler: are SET LOCAL GUCs inside an explicit transaction guaranteed isolated between clients (RLS claims)? #47946
-
|
Setup
BEGIN;
SELECT set_config('request.jwt.claims', '{"sub":"…","role":"…"}', true); -- true = SET LOCAL semantics
-- application queries, evaluated under RLS
COMMIT;Policies are written fail-closed: if the GUC is absent, Questions
Everything works in practice (integration tests against the real database pass, including bypass attempts without claims), but for a security-relevant mechanism we'd rather rely on documented guarantees than on observed behavior. Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
|
Your design is sound, and the guarantee you're looking for is actually stronger than pooler behavior — it comes from Postgres itself. 1. Connection ownership during a transaction: yes. In transaction mode the transaction is the unit of multiplexing — a server connection is assigned to one client at 2. But you don't even need to trust the pooler for 3. Is this the recommended pattern? Yes — it's the same mechanism Supabase's own stack uses: PostgREST injects
So: explicit transaction + |
Beta Was this translation helpful? Give feedback.
Your design is sound, and the guarantee you're looking for is actually stronger than pooler behavior — it comes from Postgres itself.
1. Connection ownership during a transaction: yes. In transaction mode the transaction is the unit of multiplexing — a server connection is assigned to one client at
BEGINand isn't handed to anyone else until that transaction ends withCOMMIT/ROLLBACK. Interleaving two clients' statements inside one open transaction would break transaction semantics entirely; no transaction-mode pooler does that.2. But you don't even need to trust the pooler for
SET LOCAL.set_config(..., true)/SET LOCALis scoped to the transaction by the Postgres server: the value is …