Updated 25 October 2026
Connect database sessions to Postgres row security
A database session does not automatically preserve Supabase row security when authentication moves into an application backend. Own Auth can verify who made the request, while Postgres policies still need a trusted identity and the correct database role. Keep the existing data protection explicit during the migration rather than assuming that a new session cookie supplies the claims used by the old data API.
Supabase's authenticated data API can supply signed claims to database policies. A successful Own Auth login does not populate the uid() helper in Supabase's authentication schema. The Supabase migration guide covers exports, user mapping, and credential cutover. This article addresses the separate decision about how protected application queries receive their verified identity after that cutover.
Keep session verification in its existing owner
Read the credential from the application's chosen transport and call auth.getCurrentSession on the backend. A null result means the request cannot proceed as an authenticated user. The successful result supplies the user ID. A path parameter, request body, hidden form field, or browser storage value naming another user does not supply equivalent evidence.
Keep the authentication tables under Own Auth's ownership. Policies for application projects or documents should not require replacing the package's session lookup with a custom token query. The package remains responsible for verifying the session. The application is responsible for connecting the resulting identity to its own protected records and database access design.
Use an application database role
Inspect the role that actually executes the protected query. A policy demonstrated with a restricted role does not prove what happens when the production pool connects as the table owner. Postgres table owners normally bypass row security, and superusers or roles with BYPASSRLS bypass it as well. Enabling row security on a table is therefore only one part of the arrangement.
Use a runtime role with the minimum application privileges. Keep schema ownership and migration authority separate from normal request handling. Grant only the operations the application needs, and define policies for those operations. A select policy does not describe who may insert a record, change its owner, or delete it. Review each operation against the user action it serves.
Scope request identity to one transaction
A pool reuses database connections. Identity stored as a persistent connection setting can survive beyond the request that established it. If another request borrows that connection, its query may inherit the wrong context. A transaction local setting avoids keeping that identity after the transaction ends, provided every protected statement uses that transaction's same database client.
With node postgres, acquire a client from the pool before beginning the transaction. Execute the identity setup and protected queries on that client, then commit or roll back and release it. Do not issue the setup through one pool.query call and the protected query through another. Those calls can use different connections, so they do not establish one shared transaction.
Treat database settings as trusted backend input
A custom setting can carry a verified user ID to a policy. The setting itself is not a signed credential. The safety claim depends on who is allowed to connect with that runtime role and set the value. If an untrusted caller can execute arbitrary SQL with the same authority, the setting cannot prove that caller's identity.
For that reason, keep this design behind a trusted backend. Do not hand out its database credentials or describe the setting as a replacement for a browser facing authenticated data API. Where clients access Postgres through an existing service, preserve that service's supported identity verification mechanism instead of assuming that a backend convention applies to arbitrary client SQL.
Keep user identity separate from tenant permission
A user ID identifies the requester. It does not establish membership of the organisation named in a URL. A document policy must still express who may access that document, such as its owner or a current member of the owning organisation. Derive requested tenant IDs from validated input and evaluate membership using authoritative records.
Pay particular attention to writes that change ownership. The allowed original row and the allowed resulting row can differ. A user who may edit a document's content should not automatically be able to move it into another tenant or assign it to a different owner. State those separate outcomes in the update rule rather than relying on a frontend that hides the ownership field.
Verify with the production role and pool behavior
Check one user's read and write access, then attempt the same operations against another user's records. Run those checks with the role used by the application, not a migration account. Repeat requests on reused connections, including a rolled back transaction, and confirm that a missing identity denies access instead of inheriting a previous user.
Also verify removal of membership and ownership changes. A policy that only proves the initial happy path leaves the important lifecycle transitions unresolved. Start with the Postgres authentication guide, keep Own Auth responsible for session validity, and make the database policy responsible for the application rows it actually protects.