Re: [oauth] Stabilize the libpq-oauth ABI (and allow alternative implementations?)
Zsolt Parragi <zsolt.parragi@percona.com>
From: Zsolt Parragi <zsolt.parragi@percona.com>
To: Jacob Champion <jacob.champion@enterprisedb.com>
Cc: Chao Li <li.evan.chao@gmail.com>, PostgreSQL Hackers <pgsql-hackers@postgresql.org>
Date: 2026-01-17T09:37:43Z
Lists: pgsql-hackers
Hello! The patches look good, I don't have comments for them directly. I also tried out a simple client-server plugin pair with them, both built as external plugins, and it works. I have some practical findings based on that: 1. If I provide an incorrect library path to psql, it suggests that I should install the libpq-oauth package. It would be better to tell the user that PGOAUTHMODULE is invalid in this case. For example: PGOAUTHMODULE=/not/existing/path/to/oauth42_flow.so bin/psql "oauth_issuer=... oauth_client_id=..." psql: error: connection to server at "127.0.0.1", port 5432 failed: no OAuth flows are available (try installing the libpq-oauth package) 2. Even if I use a custom library (which doesn't default to the usual get the discovery json - do a device flow - etc flow), it tries to construct/validate the well known discovery url. Why does it do that, if it doesn't try to use the URL directly? The only validation done inside libpq is now to validate that the URL matches the server URL. The server doesn't do this validation at all, it accepts any string I provide and starts up. If we want this URL validation, shouldn't it happen in the server, and in the client side oauth plugin? (Not doing it on the server but enforcing it on the client seems like a strange choice, as typos/misconfigurations will need server restarts) 3. Is it really still OAuth, and not a generic pluggable SASLBEARER authentication? Yes, I still have to provide the "oauth_issuer" and "oauth_client_id" parameters, but I don't have to do anything with it. I can implement any client side authentication I want in a libpq plugin, as long as I am able to verify it on the server side by sending a single token using SASL. That token doesn't have to be an OAuth token, because I can change both the creation and validation part. So why don't you call this SASLBEARER, with the default provided implementation being OAuthBearer, that seems to be a better fitting name for it? (this was already the case for custom applications with PQsetAuthDataHook, and because of that I already wanted to ask this question, but now I can also misuse it in psql/other command line tools/existing applications/...) 4. Have you thought about parameter passing, if my custom plugin needs extra configuration? Especially related to the above question, but even in the scope of OIDC. For example there's my next 5th question. Or if used by a webpage and it has to pass a callback URL to the provider. 5. I was about to submit a separate patch we got some requests about: a way to supply an OAuth token directly to psql (PGOAUTHTOKEN=... bin/psql ...), by implementing PQsetAuthDataHook in psql/other command line tools. (Multiple users asked for this) I realized that I could possibly implement that using this new plugin API, and keep it outside of the core, but from a user experience perspective simply using an environment variable without custom plugins could be better. What direction would you prefer with that? (and this is related to the previous question with again the additional parameter - the custom user provided token) 6. Still about PQsetAuthDataHook, this seems to have a limited use case: if I am in the control of the application, writing it, PQsetAuthDataHook seems to be a better choice. These plugins are useful if I have to modify an existing generic application, to use a different authentication method, and that seems to be useful, especially if I treat it as a generic SASLBEARER API. But this also goes back to the security questions I raised in another thread: could an application say that it doesn't want to use plugins? Could it be configured in another way, other than environment variables? (if an application has a config file for example, it seems to be more practical to make this plugin part of that config file, instead of relying on a completely different environment variable)
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
libpq: Allow developers to reimplement libpq-oauth
- 09532b4040ed 19 (unreleased) landed
-
libpq: Poison the v2 part of a v1 Bearer request
- 0af4d402cb90 19 (unreleased) landed
-
libpq-oauth: Never link against libpq's encoding functions
- dba35604485f 19 (unreleased) landed
-
libpq-oauth: Use the PGoauthBearerRequestV2 API
- 6225403f2783 19 (unreleased) landed
-
libpq: Introduce PQAUTHDATA_OAUTH_BEARER_TOKEN_V2
- e982331b5208 19 (unreleased) landed
-
libpq: Add PQgetThreadLock() to mirror PQregisterThreadLock()
- b8d76858353e 19 (unreleased) landed
-
oauth: Report cleanup errors as warnings on stderr
- f8c0b91a6063 19 (unreleased) landed
-
oauth_validator: Avoid races in log_check()
- c3df85756ceb 18.2 landed
- ab8af1db4303 19 (unreleased) landed
-
libpq-oauth: use correct c_args in meson.build
- 023a3c786b81 18.2 landed
- 781ca72139d6 19 (unreleased) landed
-
libpq-fe.h: Don't claim SOCKTYPE in the global namespace
- cc824482a3c0 18.2 landed
- 8b217c96ea2d 19 (unreleased) landed