Skip to content

Add support for OAuth 2.0 with PostgreSQL 18#693

Open
jeltz wants to merge 3 commits intoged:masterfrom
jeltz:oauth
Open

Add support for OAuth 2.0 with PostgreSQL 18#693
jeltz wants to merge 3 commits intoged:masterfrom
jeltz:oauth

Conversation

@jeltz
Copy link
Contributor

@jeltz jeltz commented Feb 6, 2026

Hi, I have hacked on this patch for some time now and feel like now is a good time to get some external input so I do not waste too much time on things the project would not like. The patch is not yet in a state where it is ready to be merged, but I think it is ready for input on architecture and design decisions. I also have several open questions.

I do not expect you to have answers to all the questions below, I mostly include them so I do not forget them myself.

Background

PostgreSQL 18 added support for OAuth 2.0 in the server, libpq and the psql client. See documentation at [1] and [2] for some further information.

So since libpq has added support for it I also think we should expose that support in the pg gem.

Current state of the patch

The patch should work and be stable but is missing polish and and some features, and CI is not entirely happy yet. See the new test cases for more details on how it is used. But here is a simple example: As you can see the current interface is pretty rough and intentionally close to the API exposed by libpq. Returning true for example means that we do not fall through to the built-in default handler.

PG.set_auth_data_hook do |data|
  case data
  when PG::OAuthBearerRequest
    if rand(2) == 1
      data.token = "secret"
    end
    true
  end
end

The first of the three patches just fixes the code so it is no longer broken with the builtin OAuth hooks, the second implements the actual feature and the third just tries to fix the CI a bit.

Since PostgreSQL does not ship with any OAuth validator module which can be used by driver authors I wrote my own quick dummy one which worked very well until I had to make it compile on the full CI matrix. 😅

Things left to do

  • Fix broken CI due to our OAuth validator failing to build
  • Improve tests in general
  • Write RDoc comments for new classes and functions
  • Improve code comments
  • Implement support for async callback?
  • Silence output spam from libpq with PGOAUTHDEBUG when running the tests?

Open questions

About interface/implementation

  • Is this quite direct translation of the C interface a good idea?
  • Should we expose that in libpq people can return -1 to signal error? E.g. by letting people return true|false|nil?
  • Is it safe to just propagate Ruby exceptions up?
  • Is the idea of using Ractor local storage to handle the callback sound?

About naming

  • Should PG.set_auth_data_hook actually be PG::Connection.set_auth_data_hook?
  • Should the new C code be in pg.c?
  • Should the new tests be moved elsewhere? Right now I just put them in connection_spec,rb.

And the test validator is surprisingly complex to build in the CI environment.

  • Should we copy stuff from the PG headers to reduce the number of dependencies needed to build it?
  • Should we build it as its own Github job and then copy it into the build images?
  • Should we create a separate Github project for it so it can be shared with authors of drivers for other languages?
  • Or maybe even use binaries from some existing validator like pg_oidc_validator?

Trying it out

To try it out for real you need the install a validator module, and here I am only familiar with our own: pg_oic_validator which comes with a Docker Compose file for setting it all up. I know there are others like keycloak-oauth-validator but I do not know how easy or tricky they are to set up.

jeltz added 3 commits February 6, 2026 19:08
Since the buitt-in OAuth hooks in libpq can return timerfd and not jsut
a socket when you ask for the current file descriptor we are waiting on
we need to make sure to use the right Ruby class to wrap the file
descriptor, if it is not a valid socket we should use IO.
Async is not supported yet
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant