Custom oauth validator options

Started by Zsolt Parragiabout 1 month ago15 messages
#1Zsolt Parragi
zsolt.parragi@percona.com

Hello hackers,

The current OAuth code allows validators to add custom validation
logic, but does not allow them to introduce custom
authentication-related parameters in the place where they belong:
pg_hba.conf. As a workaround, both pg_oidc_validator and
postgres-keycloak-oauth-validator (and likely others; these are simply
the two I know of) rely on GUC variables instead.

I see two issues with this:

1. Configuration for OAuth validation ends up split across two
locations: issuer/scope and a few other parameters are defined in
pg_hba.conf, while custom parameters must be set in postgresql.conf.

2. We have received multiple questions asking how to configure
multiple OIDC servers with different parameter sets. I am not sure how
common it is to use multiple OAuth providers with a single PostgreSQL
instance, but the question is certainly reasonable.

Given this, I would like to ask what you think about making
pg_hba.conf extensible. At present, option parsing is hardcoded in
parse_hba_auth_opt, and any unknown parameter triggers an error at the
end of the function.

I can see a few possible approaches:

a. Add an OAuth-specific hook that allows injecting additional
option-parsing logic into this function, as part of the existing
OAuthValidatorCallbacks. This could be scoped to the validator used on
the specific HBA line, even if multiple validators are loaded.
b. Allow the existing startup callback to supply a list of additional
valid configuration names, with the validation callback responsible
for parsing and validating them.
c. Add a more generic hook usable by any extension. I do not currently
have concrete use cases outside OAuth, but perhaps others do.

I would be interested in your thoughts on whether an improvement in
this area would be useful.

I also have two related questions, which might be addressed as part of
the above or independently:

1. HBA options are parsed sequentially. If validator-specific options
are tied to a particular validator, this implies that validator=...
must appear before its parameters when multiple validators are loaded,
since we cannot otherwise determine which validator is used. Is this
acceptable behavior, or should options be allowed in any order?

2. If a validator introduces many options, an HBA line could become
very long and hard to read. Would it make sense to allow loading the
parameters for a given line from a separate file? This might already
be useful today: for example, if a long issuer URL is repeated across
several HBA lines, it could instead be defined once in an external
file and referenced multiple times.

#2Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Zsolt Parragi (#1)
Re: Custom oauth validator options

Sorry for missing this thread!

On Tue, Dec 2, 2025 at 5:06 AM Zsolt Parragi <zsolt.parragi@percona.com> wrote:

1. Configuration for OAuth validation ends up split across two
locations: issuer/scope and a few other parameters are defined in
pg_hba.conf, while custom parameters must be set in postgresql.conf.

Yeah. (This has come up before a couple of times that I know of, in
the context of pg_hba and pg_ident splitting important configuration
between them [1]/messages/by-id/0e0c038ab962c3f6dab00934fe5ae1ae115f44c0.camel@vmware.com, and in the context of SNI's proposed pg_hosts config
[2]: /messages/by-id/CAOYmi+=ZjGJLw8tCkzY88acd=ir1r8eAxO-+5wXm9gtCUV97Sg@mail.gmail.com

2. We have received multiple questions asking how to configure
multiple OIDC servers with different parameter sets. I am not sure how
common it is to use multiple OAuth providers with a single PostgreSQL
instance, but the question is certainly reasonable.

What kinds of parameters? Having a motivating use case would be
helpful; HBA isn't always as flexible as people assume and I want to
make sure that we can end with a usable feature.

Given this, I would like to ask what you think about making
pg_hba.conf extensible.

Your proposals (and the concerns they raise) seem reasonable enough at
first glance. (I still want a motivating use case, though.)

Honestly, I'd *prefer* that any solution not be OAuth-specific. I
might throw two alternatives onto the pile:

d. Have HBA plug into the GUC system itself

A hypothetical PGC_HBA context would seem to fit nicely between
PGC_SIGHUP and PGC_SU_BACKEND.

e. Subsume HBA, ident, (hosts,) etc. under postgresql.conf

This is my personal white whale. I think pg_hba+ident is no longer fit
for purpose. It makes nonexistent use cases easy and common use cases
unnecessarily difficult. Most people ignore half the columns. New
users are surprised that you can't choose between authentication
options. You have to correlate a bunch of different files with
differing syntaxes to figure out what is going on. Etc, etc.

This is why I bypassed pg_ident for validators, so that they could be
free to do useful stuff while the core caught up. But I didn't intend
to keep them separate forever.

(I'm only halfway serious with (e) -- I don't really intend to drive
your thread straight into a wall. But when I read proposals a-c, I get
the sinking feeling that this *should* be solved in a more radical
way, if we could only agree on a direction...)

Thanks,
--Jacob

[1]: /messages/by-id/0e0c038ab962c3f6dab00934fe5ae1ae115f44c0.camel@vmware.com
[2]: /messages/by-id/CAOYmi+=ZjGJLw8tCkzY88acd=ir1r8eAxO-+5wXm9gtCUV97Sg@mail.gmail.com

#3VASUKI M
vasukianand0119@gmail.com
In reply to: Zsolt Parragi (#1)
Re: Custom oauth validator options

Hi All,

The core issue,as you said,is that OAuth validators can add custom
validation logic,but they can't define their own authentication-related
parameters in pg_hba.conf,where they naturally belong.Because of
that,validator-specific config ends up pushed into postgresql.conf via
GUCs,which feels a bit awkward and scattered.

That leads to the same points you mentioned:

1]OAuth configuration gets split between pg_hba.conf and
postgres.conf,which is confusing to reason about.
2]using multiple OIDC/OAuth providers with different parameter sets on a
single Postgresql instance is hard(or effectively impossible),even though
it's a pretty reasonable use case.

Given the constraints of the current HBA model(and similar issues that
recently came up with SNI),I agree that anything involving generic
extensibility or nested configuration would be a big hammer and likely too
complex.

I also have two related questions, which might be addressed as part of

the above or independently:

1. HBA options are parsed sequentially. If validator-specific options
are tied to a particular validator, this implies that validator=...
must appear before its parameters when multiple validators are loaded,
since we cannot otherwise determine which validator is used. Is this
acceptable behavior, or should options be allowed in any order?

2. If a validator introduces many options, an HBA line could become
very long and hard to read. Would it make sense to allow loading the
parameters for a given line from a separate file? This might already
be useful today: for example, if a long issuer URL is repeated across
several HBA lines, it could instead be defined once in an external
file and referenced multiple times.

So the direction I'm most aligned with is option (b): letting OAuth
validator advertise a limited list of additional valid option names for
pg_hba.conf,while keeping parsing,ordering rules,and validation firmly in
core.That seems like the least spicy option-incremental,OAuth-scoped,and
not a redesign of HBA parsing.

Reg. ordering:requiring validator= to appear before validator-specific
options feels acceptable to me if this is pursued,since it keeps parsing
simple and avoids ambiguity.
Reg very long HBA lines: totally agree this is a real readability issue,but
allowing per-line includes or external file feels like a seperate(and much
bigger)topic,probably best tackled independently.

Overall, +1 that this limitation is real and worth discussing.I’ll plan to
send a patch shortly exploring option (b).

Regards,

Vasuki M
CDAC,Chennai.

#4Zsolt Parragi
zsolt.parragi@percona.com
In reply to: Jacob Champion (#2)
Re: Custom oauth validator options

What kinds of parameters? Having a motivating use case would be
helpful; HBA isn't always as flexible as people assume and I want to
make sure that we can end with a usable feature.

One issue we have is that some providers don't allow users to select
what goes into the subject claim, but do allow users to define custom
claims. Additionally, the subject claim is sometimes a random
generated id, which gets generated on the first login to the client,
and that makes it practically unusable for pg. It would require:

* user trying to login to pg
* getting rejected
* figuring out what's the subject
* adding it to pg ident / some other config
* user can finally login

Instead we decided to let everyone configure which claim they want to
use for user mapping. But because of that, this is a GUC, and they can
only configure it once pre server.

The postgres-keycloak-oauth-validator is in an even worse situation,
they decided to use a long list of GUC parameters[1]https://github.com/cloudnative-pg/postgres-keycloak-oauth-validator/blob/5fceacf53c3d86fbbe18dab0341311855a89fe6a/src/kc_validator.c#L741. The main reason
is that they use an introspection endpoint for validation instead of
the JWT, so they need multiple parameters for that. Some of these GUCs
seem redundant to me, but some of them are definitely required.

They also have parameters for the client id and debugging - those are
things we are also considering adding to our validator.

(I'm only halfway serious with (e) -- I don't really intend to drive
your thread straight into a wall. But when I read proposals a-c, I get
the sinking feeling that this *should* be solved in a more radical
way, if we could only agree on a direction...)

I tried to propose simple things that are relatively easy to
implement, and wouldn't change too much at once, so there's a
realistic change for this making into PG19. I'm not against having a
bigger goal, and continuing making it even better after that.

A hypothetical PGC_HBA context would seem to fit nicely between
PGC_SIGHUP and PGC_SU_BACKEND.

How would you configure that since the hba lines don't have IDs?
Should we add a "guc_name" parameter to HBA for this or something like
that? I like this idea, it would be fun to implement and see how it
works, I'm just wondering how users could use it.

[1]: https://github.com/cloudnative-pg/postgres-keycloak-oauth-validator/blob/5fceacf53c3d86fbbe18dab0341311855a89fe6a/src/kc_validator.c#L741

#5Zsolt Parragi
zsolt.parragi@percona.com
In reply to: VASUKI M (#3)
Re: Custom oauth validator options

Overall, +1 that this limitation is real and worth discussing.I’ll plan to send a patch shortly exploring option (b).

Personally I would go with either (a) or (c), and I was planning to
clean up / improve / share my (c) patch as a second attempt for this
thread, if it didn't receive any replies. I can still do that, so that
we have multiple test implementations. (b) seemed a not as nice design
to me, but maybe you find a better way to implement it than I did.

Also now I really like the idea of the PGC_HBA, if there's a way for
users to configure it without depending on line numbers or other
easy-to-change details.

#6Jacob Champion
jacob.champion@enterprisedb.com
In reply to: VASUKI M (#3)
Re: Custom oauth validator options

On Tue, Dec 16, 2025 at 10:30 PM VASUKI M <vasukianand0119@gmail.com> wrote:

Overall, +1 that this limitation is real and worth discussing.I’ll plan to send a patch shortly exploring option (b).

Thanks!

Reg very long HBA lines: totally agree this is a real readability issue,but allowing per-line includes or external file feels like a seperate(and much bigger)topic,probably best tackled independently.

I forgot to mention in my reply to Zsolt, but we've supported inline
inclusions in HBA for a few releases now. (I just frequently forget
they exist.)

pg_hba.conf:

hostssl all all 0.0.0.0/0 oauth @oauth-settings.conf

oauth-settings.conf:

issuer=https://oauth.example.org/v2
scope="openid email let-me-into-pg"
validator=example_org
map=examplemap

And for smaller annoyances, you can wrap lines with backslash continuation.

I haven't used these new features much, since I forget they exist, so
if there are usability problems in practice please say something so we
can fix it.

--Jacob

#7Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Zsolt Parragi (#5)
Re: Custom oauth validator options

On Wed, Dec 17, 2025 at 1:28 AM Zsolt Parragi <zsolt.parragi@percona.com> wrote:

Instead we decided to let everyone configure which claim they want to
use for user mapping. But because of that, this is a GUC, and they can
only configure it once pre server.

We're getting closer; I agree that this needs to be more flexible than
it is, and I'm on board with a change, but I'm still missing the
"killer app". What's the case where a user has multiple HBA lines that
all want to use unrelated claims for authentication to one Postgres
cluster? Is this multi-tenancy, or...?

I tried to propose simple things that are relatively easy to
implement, and wouldn't change too much at once, so there's a
realistic change for this making into PG19. I'm not against having a
bigger goal, and continuing making it even better after that.

Absolutely -- that's a tried and true strategy. No objections to that.

But I also didn't want to stay silent on my longer-term goals here.
That way (hopefully), no one's surprised to find I'm lukewarm on
patches that are extremely OAuth-specific, or that don't give us a way
to improve/evolve later. The additional flexibility of OAuth should
ideally be mirrored in other auth methods when possible.

A hypothetical PGC_HBA context would seem to fit nicely between
PGC_SIGHUP and PGC_SU_BACKEND.

How would you configure that since the hba lines don't have IDs?
Should we add a "guc_name" parameter to HBA for this or something like
that? I like this idea, it would be fun to implement and see how it
works, I'm just wondering how users could use it.

I hadn't thought it through very far; my initial impression was that
we'd need some sort of additional syntax. But I keep coming back to
httpd-style configs and then I choose something else from my TODO list
to focus on. :) See also the old conversation regarding LDAP hba/ident
[1]: /messages/by-id/CAOuzzgpFpuroNRabEvB9kST_TSyS2jFicBNoXvW7G2pZFixyBw@mail.gmail.com

On Wed, Dec 17, 2025 at 1:36 AM Zsolt Parragi <zsolt.parragi@percona.com> wrote:

Personally I would go with either (a) or (c), and I was planning to
clean up / improve / share my (c) patch as a second attempt for this
thread, if it didn't receive any replies. I can still do that, so that
we have multiple test implementations.

The more the merrier!

Thanks,
--Jacob

[1]: /messages/by-id/CAOuzzgpFpuroNRabEvB9kST_TSyS2jFicBNoXvW7G2pZFixyBw@mail.gmail.com

#8Zsolt Parragi
zsolt.parragi@percona.com
In reply to: Jacob Champion (#7)
Re: Custom oauth validator options

I forgot to mention in my reply to Zsolt, but we've supported inline
inclusions in HBA for a few releases now. (I just frequently forget
they exist.)

Thanks, I didn't know about that feature, that solves half of my problem.

What's the case where a user has multiple HBA lines that
all want to use unrelated claims for authentication to one Postgres
cluster? Is this multi-tenancy, or...?

For configuring the authn matching yes, the use case is multitenancy.

But for some other variables that we didn't implement yet, this could
be useful even without multitenancy.

One thing I mentioned in the previous email is the client id
validation. A practical use case of that would be restricting which
oauth clients can login to which database. I can't use a SUSET
variable with a check restricting it to ALTER DATABASE, because
database level variables are not yet available during the oauth
validator callback. I could use a login event trigger, but that seems
like a bad hack to me.

#9VASUKI M
vasukianand0119@gmail.com
In reply to: Jacob Champion (#7)
Re: Custom oauth validator options

On Thu, Dec 18, 2025 at 12:31 AM Jacob Champion <
jacob.champion@enterprisedb.com> wrote:

On Wed, Dec 17, 2025 at 1:28 AM Zsolt Parragi <zsolt.parragi@percona.com>
wrote:

Instead we decided to let everyone configure which claim they want to
use for user mapping. But because of that, this is a GUC, and they can
only configure it once pre server.

We're getting closer; I agree that this needs to be more flexible than
it is, and I'm on board with a change, but I'm still missing the
"killer app". What's the case where a user has multiple HBA lines that
all want to use unrelated claims for authentication to one Postgres
cluster? Is this multi-tenancy, or...?

Beyond multitenancy,per -HBA OAuth cases where options are needed for

safe provider migration[blue/green],per-database security policies,mixed
Human/machine authentication[JWT/Introspection] and incident-response
scenarios -all global GUCs are too coarse.

See also the old conversation regarding LDAP hba/ident

[1]

[1]
/messages/by-id/CAOuzzgpFpuroNRabEvB9kST_TSyS2jFicBNoXvW7G2pZFixyBw@mail.gmail.com

Thanks, Will go through it.

Regards,

Vasuki M
CDAC,Chennai.

#10Zsolt Parragi
zsolt.parragi@percona.com
In reply to: VASUKI M (#9)
1 attachment(s)
Re: Custom oauth validator options

Personally I would go with either (a) or (c), and I was planning to
clean up / improve / share my (c) patch as a second attempt for this
thread, if it didn't receive any replies. I can still do that, so that
we have multiple test implementations.

I attached the patch. It modifies one of the existing oauth_validator
tests to showcase how it works, but in theory it isn't dependent on
oauth. It however requires shared_preload_libraries (that is common
for all options), maybe oauth_validator_libraries could imply that?

Attachments:

0001-Adding-hooks-to-HBA-parsing-option-c.patchapplication/octet-stream; name=0001-Adding-hooks-to-HBA-parsing-option-c.patchDownload
From 296acdb1551db523009ce7201daa03ef3e33f182 Mon Sep 17 00:00:00 2001
From: Zsolt Parragi <zsolt.parragi@percona.com>
Date: Thu, 18 Dec 2025 08:25:46 +0000
Subject: [PATCH] Adding hooks to HBA parsing, option c

This commit showcases how we can add a generic, non oauth dependent hook
to parsing hba entries, and also adds a simple test to the existing
oauth_validator test suite.
---
 src/backend/libpq/hba.c                       | 34 ++++++++----
 src/include/libpq/hba.h                       | 31 +++++++++++
 .../modules/oauth_validator/t/002_client.pl   | 51 ++++++++++++++++++
 src/test/modules/oauth_validator/validator.c  | 53 +++++++++++++++++++
 4 files changed, 160 insertions(+), 9 deletions(-)

diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 4c259f58d77..409801ec6d8 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -125,6 +125,11 @@ static const char *const UserAuthName[] =
 StaticAssertDecl(lengthof(UserAuthName) == USER_AUTH_LAST + 1,
 				 "UserAuthName[] must match the UserAuth enum");
 
+/*
+ * Hook for plugins to extend pg_hba.conf option parsing.
+ */
+hba_parse_option_hook_type hba_parse_option_hook = NULL;
+
 
 static List *tokenize_expand_file(List *tokens, const char *outer_filename,
 								  const char *inc_filename, int elevel,
@@ -2507,15 +2512,26 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline,
 	}
 	else
 	{
-		ereport(elevel,
-				(errcode(ERRCODE_CONFIG_FILE_ERROR),
-				 errmsg("unrecognized authentication option name: \"%s\"",
-						name),
-				 errcontext("line %d of configuration file \"%s\"",
-							line_num, file_name)));
-		*err_msg = psprintf("unrecognized authentication option name: \"%s\"",
-							name);
-		return false;
+		bool		handled = false;
+
+		if (hba_parse_option_hook)
+		{
+			handled = (*hba_parse_option_hook) (name, val, hbaline,
+												elevel, err_msg);
+		}
+
+		if (!handled)
+		{
+			ereport(elevel,
+					(errcode(ERRCODE_CONFIG_FILE_ERROR),
+					 errmsg("unrecognized authentication option name: \"%s\"",
+							name),
+					 errcontext("line %d of configuration file \"%s\"",
+								line_num, file_name)));
+			*err_msg = psprintf("unrecognized authentication option name: \"%s\"",
+								name);
+			return false;
+		}
 	}
 	return true;
 }
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 7b93ba4a709..bd4658c72c8 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -172,6 +172,37 @@ typedef struct TokenizedAuthLine
 /* avoid including libpq/libpq-be.h here */
 typedef struct Port Port;
 
+/*
+ * Hook for plugins to extend pg_hba.conf option parsing.
+ *
+ * This hook is called by parse_hba_auth_opt() when it encounters an option
+ * name that it doesn't recognize. Plugins can use this to parse custom
+ * authentication.
+ *
+ * Parameters:
+ *   name     - The option name being parsed (e.g., "custom_option")
+ *   val      - The option value (may be NULL for boolean-style options)
+ *   hbaline  - The HbaLine structure being populated. Plugins should not
+ *              modify standard fields, but can use this to check auth_method,
+ *              conntype, etc. to validate option applicability.
+ *   elevel   - Error level for reporting (LOG, ERROR, etc.)
+ *   err_msg  - Output parameter for error messages. Set this to a palloc'd
+ *              string if returning false due to a validation error.
+ *
+ * Return value:
+ *   true  - The hook recognized and successfully handled this option.
+ *   false - The hook doesn't recognize this option, or encountered an error.
+ *           If an error occurred, the hook should set *err_msg and/or call
+ *           ereport().
+ */
+typedef bool (*hba_parse_option_hook_type) (const char *name,
+											const char *val,
+											HbaLine *hbaline,
+											int elevel,
+											char **err_msg);
+
+extern PGDLLIMPORT hba_parse_option_hook_type hba_parse_option_hook;
+
 extern bool load_hba(void);
 extern bool load_ident(void);
 extern const char *hba_authname(UserAuth auth_method);
diff --git a/src/test/modules/oauth_validator/t/002_client.pl b/src/test/modules/oauth_validator/t/002_client.pl
index e6c91fc911c..6576d6e41e0 100644
--- a/src/test/modules/oauth_validator/t/002_client.pl
+++ b/src/test/modules/oauth_validator/t/002_client.pl
@@ -29,6 +29,8 @@ $node->init;
 $node->append_conf('postgresql.conf', "log_connections = all\n");
 $node->append_conf('postgresql.conf',
 	"oauth_validator_libraries = 'validator'\n");
+$node->append_conf('postgresql.conf',
+	"shared_preload_libraries = 'validator'\n");
 # Needed to inspect postmaster log after connection failure:
 $node->append_conf('postgresql.conf', "log_min_messages = debug2");
 $node->start;
@@ -115,6 +117,55 @@ test(
 	expected_stdout => qr/connection succeeded/,
 	log_like => [qr/oauth_validator: token="my-token", role="$user"/]);
 
+# Test custom HBA option parsing hook
+my $log_start_custom = -s $node->logfile;
+unlink($node->data_dir . '/pg_hba.conf');
+$node->append_conf(
+	'pg_hba.conf', qq{
+local all test oauth issuer="$issuer" scope="$scope" test_custom_claim="my_custom_value"
+});
+$node->reload;
+$node->wait_for_log(qr/reloading configuration files/, $log_start_custom);
+
+$node->wait_for_log(
+	qr/oauth_validator: parsed custom HBA option test_custom_claim="my_custom_value"/,
+	$log_start_custom);
+
+test(
+	"custom HBA option is parsed and used",
+	flags => [
+		"--token", "test-token",
+		"--expected-uri", "$issuer/.well-known/openid-configuration",
+		"--expected-scope", $scope,
+	],
+	expected_stdout => qr/connection succeeded/,
+	log_like => [qr/oauth_validator: custom_claim="my_custom_value"/]);
+
+# Test that unknown HBA options still fail
+my $log_start_unknown = -s $node->logfile;
+unlink($node->data_dir . '/pg_hba.conf');
+$node->append_conf(
+	'pg_hba.conf', qq{
+local all test oauth issuer="$issuer" scope="$scope" unknown_option="value"
+});
+$node->reload;
+$node->wait_for_log(qr/reloading configuration files/, $log_start_unknown);
+
+# Check that the server logged the error about the unknown option
+$node->wait_for_log(
+	qr/unrecognized authentication option name: "unknown_option"/,
+	$log_start_unknown);
+pass("unknown HBA option is rejected");
+
+# Restore working configuration
+unlink($node->data_dir . '/pg_hba.conf');
+$node->append_conf(
+	'pg_hba.conf', qq{
+local all test oauth issuer="$issuer" scope="$scope"
+});
+$node->reload;
+$node->wait_for_log(qr/reloading configuration files/);
+
 if ($ENV{with_libcurl} ne 'yes')
 {
 	# libpq should help users out if no OAuth support is built in.
diff --git a/src/test/modules/oauth_validator/validator.c b/src/test/modules/oauth_validator/validator.c
index 42b69646fbb..0115f228cea 100644
--- a/src/test/modules/oauth_validator/validator.c
+++ b/src/test/modules/oauth_validator/validator.c
@@ -14,6 +14,7 @@
 #include "postgres.h"
 
 #include "fmgr.h"
+#include "libpq/hba.h"
 #include "libpq/oauth.h"
 #include "miscadmin.h"
 #include "utils/guc.h"
@@ -41,6 +42,50 @@ static const OAuthValidatorCallbacks validator_callbacks = {
 static char *authn_id = NULL;
 static bool authorize_tokens = true;
 
+static char *custom_claim = NULL;
+
+static hba_parse_option_hook_type prev_hba_parse_option_hook = NULL;
+
+static bool
+validator_hba_parse_option(const char *name, const char *val,
+						   HbaLine *hbaline, int elevel, char **err_msg)
+{
+	int			line_num = hbaline->linenumber;
+	char	   *file_name = hbaline->sourcefile;
+
+	if (prev_hba_parse_option_hook)
+	{
+		if ((*prev_hba_parse_option_hook) (name, val, hbaline,
+										   elevel, err_msg))
+			return true;
+	}
+
+	if (strcmp(name, "test_custom_claim") == 0)
+	{
+		if (val == NULL || val[0] == '\0')
+		{
+			ereport(elevel,
+					(errcode(ERRCODE_CONFIG_FILE_ERROR),
+					 errmsg("test_custom_claim requires a value"),
+					 errcontext("line %d of configuration file \"%s\"",
+								line_num, file_name)));
+			*err_msg = pstrdup("test_custom_claim requires a value");
+			return false;
+		}
+
+		if (custom_claim)
+			pfree(custom_claim);
+		custom_claim = pstrdup(val);
+
+		elog(LOG, "oauth_validator: parsed custom HBA option test_custom_claim=\"%s\"",
+			 custom_claim);
+
+		return true;
+	}
+
+	return false;
+}
+
 /*---
  * Extension entry point. Sets up GUCs for use by tests:
  *
@@ -55,6 +100,8 @@ static bool authorize_tokens = true;
 void
 _PG_init(void)
 {
+	elog(LOG, "oauth_validator: _PG_init() called, installing HBA parse option hook");
+
 	DefineCustomStringVariable("oauth_validator.authn_id",
 							   "Authenticated identity to use for future connections",
 							   NULL,
@@ -73,6 +120,9 @@ _PG_init(void)
 							 NULL, NULL, NULL);
 
 	MarkGUCPrefixReserved("oauth_validator");
+
+	prev_hba_parse_option_hook = hba_parse_option_hook;
+	hba_parse_option_hook = validator_hba_parse_option;
 }
 
 /*
@@ -133,6 +183,9 @@ validate_token(const ValidatorModuleState *state,
 		 MyProcPort->hba->oauth_issuer,
 		 MyProcPort->hba->oauth_scope);
 
+	if (custom_claim)
+		elog(LOG, "oauth_validator: custom_claim=\"%s\"", custom_claim);
+
 	res->authorized = authorize_tokens;
 	if (authn_id)
 		res->authn_id = pstrdup(authn_id);
-- 
2.43.0

#11Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Zsolt Parragi (#10)
Re: Custom oauth validator options

On Thu, Dec 18, 2025 at 1:08 AM Zsolt Parragi <zsolt.parragi@percona.com> wrote:

It however requires shared_preload_libraries (that is common
for all options), maybe oauth_validator_libraries could imply that?

Haven't looked at the patch yet, but I think most people probably want
to use session_preload_libraries, not shared_preload_libraries, so
that a security update to their validator doesn't require a restart of
the cluster.

If a particular validator implementation requires shared preload, so
be it; but I don't think we want to force it. Might be more reason to
look into the GUC system?

--Jacob

#12Zsolt Parragi
zsolt.parragi@percona.com
In reply to: Jacob Champion (#11)
Re: Custom oauth validator options

Might be more reason to look into the GUC system?

I am already thinking about that, I have some ideas for a proof of
concept, but no working prototype yet. But without requiring
shared_preload_libraries, we can't do early error reporting during
postmaster startup about custom parameters. Is that okay? GUCs already
work this way, and this could be a bit safer (reporting unknown
parameters/refusing to proceed during login, when we can completely
parse all parameters), but it would be different compared to how
pg_hba is handled currently.

#13Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Zsolt Parragi (#12)
Re: Custom oauth validator options

On Thu, Dec 18, 2025 at 10:28 AM Zsolt Parragi
<zsolt.parragi@percona.com> wrote:

But without requiring
shared_preload_libraries, we can't do early error reporting during
postmaster startup about custom parameters. Is that okay?

I think I need to do more staring at the intersection of GUC
registration and session_preload_libraries, because my memory of the
order of operations was faulty. I won't be able to do that before the
holidays, most likely.

--Jacob

#14Zsolt Parragi
zsolt.parragi@percona.com
In reply to: Jacob Champion (#13)
Re: Custom oauth validator options

I think I need to do more staring at the intersection of GUC
registration and session_preload_libraries, because my memory of the
order of operations was faulty. I won't be able to do that before the
holidays, most likely.

Maybe I'm missing something, but why do we need
session_preload_libraries? oauth_validator_libraries is processed
earlier, it can already define sighup GUCs, it should also work with a
new level around that. I assume that if postgres gets another
authentication plugin point later, it will be executed around the same
place, during authentication, so that also shouldn't be an issue.

The question is if non-validator libraries should be able to define
PGC_HBA variables. If yes, then either

* we don't validate that all HBA variables are valid - if somebody
made a typo, we can't detect it
* we add a sighup guc with a manual whitelist
* require shared preload libraries or oauth_validator_libraries,
because those are loaded before or during authentication
* require session_preload_libraries. We proceed with authentication
even with unresolved HBA variables, but abort the connection if there
are still unknown parameters after loading session preload.

#15Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Zsolt Parragi (#14)
Re: Custom oauth validator options

On Thu, Dec 18, 2025 at 12:29 PM Zsolt Parragi
<zsolt.parragi@percona.com> wrote:

I think I need to do more staring at the intersection of GUC
registration and session_preload_libraries, because my memory of the
order of operations was faulty. I won't be able to do that before the
holidays, most likely.

Maybe I'm missing something, but why do we need
session_preload_libraries?

Well, how do you want "global" GUCs registered by the validator to
behave when OAuth isn't used for the connection?

The question is if non-validator libraries should be able to define
PGC_HBA variables.

I think we should try for that, yeah. Otherwise I suspect considerable
pushback on the idea of modifying the GucContext enum for something
that can only be used by OAuth.

* require session_preload_libraries. We proceed with authentication
even with unresolved HBA variables, but abort the connection if there
are still unknown parameters after loading session preload.

Of those choices, this _seems_ nicest. It'd be good to get a feel for
how it behaves in practice though.

Thanks,
--Jacob