Preview PostgreSQL 18’s OAuth2 Authentication (1) - Explore How it Works

September 15, 2025

PostgreSQL 18 (RC1 was released on 09/05/2025) introduces a native OAuth2 authentication method based on the SASL OAUTHBEARER mechanism. Instead of passwords, clients present bearer tokens issued by an identity provider (IdP). PostgreSQL validates those tokens through a pluggable validator module, then maps the authenticated identity to a database role before allowing access. This brings Postgres in line with modern SSO practices while keeping role/privilege management under your control.

This blog series contains 3 articles: 

  • Part-1: (this article) Explore how PostgreSQL 18 OAuth2 authentication works
  • Part-2: Write a custom validator with Rust
  • Part-3: Teach a PostgreSQL proto 3 client library to speak OAUTHBEARER

What you need (deployment prerequisites)

To enable OAuth2 authentication end-to-end, prepare the following:

  • An IdP (OAuth2/OIDC) — practically required for token issuance, though the server ultimately trusts whatever your validator accepts.
  • A PostgreSQL v3-protocol client — today, psql (via libpq) is confirmed and supports an integrated device authorization flow.   
  • PostgreSQL 18, built with --with-openssl --with-libcurl, configured with pg_hba.conf and (optionally) pg_ident.conf.
  • A server-side validator module to verify tokens and return an authorization decision.
     

How it works

The handshake consists of an SASL exchange where the server advertises OAUTHBEARER. The client either presents a token immediately or requests discovery info to run an OAuth flow (e.g., device code) and then retries with the token. The server validates the token via the configured validator and finalizes authentication.  

PostgreSQL-18 OAUTHBEARER SASL Flow

Key points from this flow:

  • Server advertises OAUTHBEARER when pg_hba.conf selects oauth.
  • Client may send a bearer token immediately, or send an empty auth="" to fetch discovery info and then obtain a token (libpq implements Device Authorization).
  • The token-acquisition method is protocol-independent; SASL only transports the result.    
     

Server configuration

1) pg_hba.conf (new oauth method)

A typical rule looks like this:

# TYPE  DATABASE  USER     ADDRESS    METHOD  OPTIONS...
host    all       tester   ::1/128    oauth   scope="openid profile" issuer=https://my-system.my-domain/auth validator=my_system_validator map="my_oauth_map"
  • method=oauth enables the feature for matching connections.
  • issuer and scope express what the server expects the token to contain.
  • validator names the validator to use (see below).
  • map activates classic pg_ident.conf mapping (user ↔ role).    

The pg_ident.conf looks like 

# MAPNAME       SYSTEM-USERNAME         PG-USERNAME
my_oauth_map    abcdef_my_user_id       tester

2) postgresql.conf (load validators)

# - Authentication -
oauth_validator_libraries = 'my_system_validator'
# comma-separated list of trusted validator modules

Validators listed here become available to HBA rules.    

3) Identity mapping modes

You can keep mapping in pg_ident.conf, like the above example

  • pg_ident.conf mapping (default): the validator must return authn_id that exactly matches the requested user or the pg_ident-mapped role, otherwise login fails.
  • Delegated mapping: set delegate_ident_mapping=1 on the HBA rule. PostgreSQL will ignore authn_id and admit the requested user if the validator returns authorized=true. Use this only if the validator strictly binds token identity to the requested role.  
PostgreSQL 18 custom validator internal logic

Client behavior

psql/libpq requires two connection parameters and fails fast if they’re missing:

  • oauth_issuer
  • oauth_client_id

libpq can run the Device Authorization flow in terminal environments by printing a verification_uri and user_code, then polling until the token is issued.   

Other clients/drivers (e.g., jackc/pgx, launchbadge/sqlx) can adopt one of two patterns:

  • Full SASL OAUTHBEARER: react to the server’s discovery/scope hint, run an OAuth flow, then continue the SASL exchange.
  • Token-first: obtain a token out-of-band and send it in the initial SASL message.

GUI tools often prefer (1). SDKs/libraries in services often prefer (2).  

Validator module

A validator is the trust anchor between Postgres and the IdP. Its job is to:

  • Verify the token (issuer, signature/keys if JWT, or introspection if opaque; scopes; lifetime).
  • Return { authorized: true/false, authn_id: "username" }.
  • Enforce identity-to-role binding when delegated mapping is enabled.     

Design note: offline JWT checks minimize latency; online introspection simplifies revocation but must complete within authentication_timeout. Read this doc for more official explanations.

Token format

SASL OAUTHBEARER does not require JWT. Any bearer token with characters in the allowed set is acceptable at the protocol level; your validator determines how to verify it.

Roles and privileges

OAuth2 support changes the authentication only. Role lifecycle (creation, grants, revocation) stays with your usual DBA processes or automation. 


Putting it Together

  • Provision roles in Postgres (the identities you intend to map to).
  • Choose an IdP and decide JWT (offline) vs. introspection (online).
  • Implement a validator and list it in oauth_validator_libraries.
  • Add an OAuth HBA rule with issuer, scope, and either map or delegate_ident_mapping=1.
  • Update clients: for psql, set oauth_issuer and oauth_client_id; confirm the device flow works where needed.  

How does psql work with PostgreSQL 18?

Here is a typical psql command to connect to a PostgreSQL 18 server with the OAuth2 authentication method:

psql "postgres://tester@my_pg.my-domain:5432/upm?oauth_issuer=https://my-system.my-domain/auth&oauth_client_id=my-app-client-id"

What happens underneath can be explained by the following diagram, which highlights the two opportunities a client has to authenticate: send a token upfront or fetch discovery info, run device flow, and then continue.

PostgreSQL 18 OAuth2 psql device code flow

libpq’s device flow prompts (verification_uri, user_code) are documented in the official libpq OAuth section.
 

Further reading

Share this