Skip to content

Allow schema selection from JWT claims (like role) #4608

Description

@code-flu

Problem
Currently, PostgREST can dynamically add new schemas at runtime, but selecting which schema a request hits still requires the client to specify it via Accept-Profile or URL. This exposes schema names to clients and makes fully hidden multi-tenant routing impossible.

What I tried
I configured PostgREST to use a pre-request function:

create or replace function postgrest.set_schema_from_jwt()
returns void as $$
declare
  schema_name text := current_setting('request.jwt.claims', true)::json->>'namespace';
begin
   if schema_name is not null and schema_name <> '' then
    perform set_config('search_path', schema_name, true);
  else
    raise exception 'Invalid or corrupted JWT';
  end if;
end;
$$ language plpgsql;

And set it in the environment:

PGRST_DB_PRE_REQUEST="postgrest.set_schema_from_jwt"

However, this does not work for routing endpoints because it runs after PostgREST has already planned the query. Changing search_path at this point only affects functions or views, not which schema the endpoint resolves to.

Use case

  • Each tenant has its own schema
  • JWT contains the tenant identity or role (e.g., "namespace": "schema_fd9d")
  • Requests should automatically go to the correct schema based on the JWT, without the client needing to set headers or URLs

Proposed feature
Add a configuration option, e.g.:

db-schema-claim = "namespace"

Behavior:

  • PostgREST reads the configured JWT claim before routing
  • Uses its value as the API schema for the request (like Accept-Profile)
  • Falls back to a default schema if the claim is missing or invalid

Benefits

  • Supports fully hidden multi-tenant routing
  • No need for clients to send headers
  • Works with dynamically added schemas
  • Keeps schema cache and OpenAPI generation deterministic
  • Compatible with JWT-based access control

Security considerations

  • JWT claims are signed and verified, so schema selection is trusted
  • Permissions still follow the role grants, same as current behavior

Metadata

Metadata

Assignees

Labels

authnRelated to authenticationconfigrelated to the configuration optionsdifficulty: mediumHaskell task involving PostgreSQL IO

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions