You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.confoauth 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
Pull dpage/pgadmin4:9.15.
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).
In pgAdmin, register a server with ConnectionParameters including oauth_issuer, oauth_client_id, oauth_client_secret, oauth_scope.
Click Connect.
See the error below.
Equivalent reproduction directly inside the container, without going through the UI:
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:
libpq-oauth-18.so — copy it from the same pg18-builder stage.
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)
Describe the bug
The official
dpage/pgadmin4Docker image shipslibpq.so.5.18but notlibpq-oauth-18.so, the SASLOAUTHBEARERflow plugin that libpq 18 dlopens at connect time. As a result, any attempt to connect to a PostgreSQL 18 server that requires OAuth authentication (apg_hba.confoauthrule, RFC 7628 / RFC 8628) fails before the connection can be established. The runtime librarylibcurl.so.4— which the plugin linksagainst — is also absent from the image.
To Reproduce
dpage/pgadmin4:9.15.pg_hba.confrule, e.g.host all all 0.0.0.0/0 oauth issuer=https://idp.example/realms/foo scope="postgres"(using e.g. Percona'spg_oidc_validator+ Keycloak).ConnectionParametersincludingoauth_issuer,oauth_client_id,oauth_client_secret,oauth_scope.Equivalent reproduction directly inside the container, without going through the UI:
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
Verified the missing pieces by hand by manually loading the plugin:
Once both
libpq-oauth-18.soandlibcurl.so.4are 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):
dpage/pgadmin4:9.15, also reproducible ondpage/pgadmin4:snapshot)Additional context
Root cause.
postgres:18-alpine— the same image the existing Dockerfile already pullslibpq.so.5.18from — ships the plugin at/usr/local/lib/libpq-oauth-18.so(built for the same Alpine/musl ABI). The currentCOPY --from=pg18-builder ...line copies onlylibpq.so.5.18, leaving the plugin behind. Two files are missing from the final image:libpq-oauth-18.so— copy it from the samepg18-builderstage.libcurl.so.4— addcurlto the runtimeapk addblock. The Alpinelibpqpackage 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-YYYto stderr. Surfacing that to pgAdmin's web UI so users can complete the flow interactively is a separate, larger piece of work (likely involvingPQauthDataHookplus front-end changes). I'mintentionally not asking for that here — just for the underlying plumbing to load.
Prior art.
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.
dpage/pgadmin4:9.15and:snapshotpostgres:18.4-trixiewithpg_oidc_validator(Percona)