Authenticate PostgreSQL connections with signed OAuth 2.0 JWT access tokens from an explicitly trusted issuer. Tokens are validated offline: signing keys are discovered through OIDC, the token and the required database scopes are verified, and a stable identity is returned for PostgreSQL role mapping. Optional delegated role claims are also supported.
This repository provides two independent modules built on one shared validation core (see Architecture):
| Module | PostgreSQL | Status |
|---|---|---|
pg_oauth_validator: native OAuth validator |
18 (stable), 19 (preview) | prerelease |
pg_oauth_pam: PAM token authentication, see the PAM guide |
15 to 19 | prerelease |
Either module works without the other. Build a separate module for each PostgreSQL major version. The project is prerelease software; passing tests alone does not establish production readiness.
The default accepts at+jwt and application/at+jwt access tokens. OIDC ID
tokens and opaque tokens are not database credentials. A missing typ requires
an explicit compatibility setting and issuer-specific
evidence that ID/session tokens cannot satisfy the audience and scope policy.
This runnable example starts PostgreSQL 18 with the validator and a local Keycloak realm. You need Docker with Compose; no local PostgreSQL installation or provider account is required. From the repository root:
-
Start the services. The first build may take a few minutes.
docker compose up --build -d
-
Connect with the bundled PostgreSQL 18
psqlclient and run a query:docker compose run --rm psql -c 'SELECT current_user, system_user;' -
psqlprints a device code and waits for authorization. In your browser, openhttps://localhost:8443/realms/pg-oauth/device?user_code=CODE, replacingCODEwith the printed code. Sign in as alice with password demo-alice-password, then approve Connect to the demo PostgreSQL database. The locally generated HTTPS certificate may require you to trust the demo CA; the Keycloak quickstart guide shows how. -
Return to the terminal. The query should show
app_readerascurrent_userandoauth:00000000-0000-0000-0000-000000000001assystem_user. Rundocker compose run --rm psqlfor an interactive session; each new connection starts a new device authorization.
Stop the services with docker compose down. To also delete the disposable
database and generated certificates, run docker compose down --volumes. The
Keycloak quickstart guide explains the sample configuration
and how to use compose.external.yml with a single
ignored YAML profile for your own issuer, including a locally verified
WorkOS AuthKit example. This stack uses
published demo credentials and is intended for local evaluation.
Install the module for your PostgreSQL major version.
Configure the explicit resource audience in postgresql.conf:
oauth_validator_libraries = 'pg_oauth_validator'
pg_oauth_validator.audiences = 'https://postgres.example.internal/'Suppose your issuer issues access tokens with sub=principal-123, that audience,
and the scope connect:postgres. Map the external identity to a database role:
# pg_hba.conf
hostssl appdb app_reader 10.0.0.0/8 oauth \
issuer="https://idp.example/" scope="connect:postgres" \
validator=pg_oauth_validator map=oauthmap
# pg_ident.conf: map-name authenticated-identity PostgreSQL-role
oauthmap principal-123 app_readerCreate the role if it does not already exist:
CREATE ROLE app_reader LOGIN;Reload PostgreSQL after configuration changes. A client requests app_reader;
the validator authenticates principal-123, and PostgreSQL checks the usermap.
current_user is app_reader; system_user is oauth:principal-123.
Use an OAuth-capable client configured for your issuer, with sslmode=verify-full
and the appropriate PostgreSQL CA trust.
Without map=, the identity must exactly equal the requested role. For custom
identity claims or delegated roles, see the
configuration guide.
PostgreSQL 19 additionally accepts validator.policy=default; PostgreSQL 18
must omit it.
Before rollout, test accepted and rejected tokens, restrict HBA databases, roles and networks, and retain a protected non-OAuth administrative recovery path. Configuration, token, network and internal failures deny authentication. See operations for provider outages, redaction, reloads, upgrades and rollback.
| Need | Read |
|---|---|
| Settings and role mapping | Configuration |
| Installation, rollout and recovery | Operations |
| PAM token authentication for PostgreSQL 15-19 (prerelease) | PAM guide |
| Demo and external issuer setup | Tutorial |
| Tested issuers and limitations | Provider compatibility |
| Product and security contract | Features |
| Implementation, source layout and design rationale | Architecture, ADRs |
| Build and test commands | Development |
| Packaging and publication | Release checklist, experimental RPMs |
Each topic has one maintained reference above. ADRs record decisions; dated release and security records capture evidence at the time of review and are not rolling claims about the current tree. Older development narratives remain available in Git history.
PostgreSQL License. See third-party notices for incorporated and linked components.