Skip to content

Docker image missing libpq-oauth-18.so. SASL OAUTHBEARER auth to PostgreSQL 18 servers is unusable #9951

@MarkBogelund

Description

@MarkBogelund

Describe the bug

The official dpage/pgadmin4 Docker image ships libpq.so.5.18 but not libpq-oauth-18.so, the SASL OAUTHBEARER flow plugin that libpq 18 dlopens at connect time. As a result, any attempt to connect to a PostgreSQL 18 server that requires OAuth authentication (a pg_hba.conf oauth rule, RFC 7628 / RFC 8628) fails before the connection can be established. The runtime library libcurl.so.4 — which the plugin links
against — is also absent from the image.

To Reproduce

  1. Pull dpage/pgadmin4:9.15.
  2. Run any PostgreSQL 18 server with an OAuth pg_hba.conf rule, e.g. host all all 0.0.0.0/0 oauth issuer=https://idp.example/realms/foo scope="postgres" (using e.g. Percona's pg_oidc_validator + Keycloak).
  3. In pgAdmin, register a server with ConnectionParameters including oauth_issuer, oauth_client_id, oauth_client_secret, oauth_scope.
  4. Click Connect.
  5. See the error below.

Equivalent reproduction directly inside the container, without going through the UI:

docker exec pgadmin /venv/bin/python -c '
import psycopg
psycopg.connect(host="postgres", dbname="app", user="default-access",
  oauth_issuer="https://keycloak:8443/realms/local-development",
  oauth_client_id="default-access",
  oauth_client_secret="default-access-secret",
  oauth_scope="postgres")
'

Expected behavior

libpq should load libpq-oauth-18.so, run the OAuth flow against the configured issuer, and either authenticate or surface a flow-specific error (e.g. invalid token). Today libpq aborts before the flow can begin because the plugin is missing.

Error message

OperationalError: connection failed: connection to server at "...", port 5432 failed:
no OAuth flows are available (try installing the libpq-oauth package)

Verified the missing pieces by hand by manually loading the plugin:

$ docker exec pgadmin /venv/bin/python -c 'import ctypes; ctypes.CDLL("/usr/lib/libpq-oauth-18.so")'
OSError: Error loading shared library libcurl.so.4: No such file or directory
  (needed by /usr/lib/libpq-oauth-18.so)

Once both libpq-oauth-18.so and libcurl.so.4 are present, the dlopen succeeds and libpq proceeds to the device-authorization flow against Keycloak.

Screenshots

N/A — backend connection failure, no UI state to capture.

Desktop (please complete the following information):

  • OS: Linux (Docker host); Alpine 3.23 inside the container
  • pgAdmin version: 9.15
  • Mode: Server
  • Browser (if running in server mode): N/A — error is on the backend connection path, browser-agnostic
  • Package type: Container (dpage/pgadmin4:9.15, also reproducible on dpage/pgadmin4:snapshot)

Additional context

Root cause. postgres:18-alpine — the same image the existing Dockerfile already pulls libpq.so.5.18 from — ships the plugin at /usr/local/lib/libpq-oauth-18.so (built for the same Alpine/musl ABI). The current COPY --from=pg18-builder ... line copies only libpq.so.5.18, leaving the plugin behind. Two files are missing from the final image:

  1. libpq-oauth-18.so — copy it from the same pg18-builder stage.
  2. libcurl.so.4 — add curl to the runtime apk add block. The Alpine libpq package doesn't pull libcurl in transitively.

A two-line Dockerfile change makes the plugin loadable and OAuth flow start.

Scope. This bug report covers only the packaging gap that makes the plugin unloadable. libpq-oauth's only implemented flow is device-authorization (RFC 8628), which prints Visit https://… and enter the code: XXX-YYY to stderr. Surfacing that to pgAdmin's web UI so users can complete the flow interactively is a separate, larger piece of work (likely involving PQauthDataHook plus front-end changes). I'm
intentionally not asking for that here — just for the underlying plumbing to load.

Prior art.

  • Closed #9063 ("Add support for OAUTHBEARER SASL mechanism") was marked as duplicate of #8935 ("Add all new connection string parameters").
  • Add all new connection string parameters. #8935 added the oauth_* connection params to pgAdmin's UI, but the runtime plugin is still missing from the image, so the params currently have nothing to drive.

Tested against.

  • pgAdmin: dpage/pgadmin4:9.15 and :snapshot
  • libpq: 18.0.3 (Alpine 3.23 inside the pgAdmin image)
  • PostgreSQL server: postgres:18.4-trixie with pg_oidc_validator (Percona)
  • IdP: Keycloak 25.0.6

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions