Periodic authorization expiration checks using GoAway message

Started by Ajit Awekar14 days ago11 messages
#1Ajit Awekar
Ajit Awekar
ajitpostgres@gmail.com
1 attachment(s)

This patch introduces a mechanism to address the security issue of stale,
authorized connections persisting beyond their validity period. .
Currently, once a session is established, postgres does not automatically
re-validate credentials. If a password expires (rolvaliduntil) the session
remains active indefinitely. Same applies to centralized authentication
systems (like Kerberos or OAuth).

This patch depends on the "GoAway" protocol message proposal currently
under review here:
/messages/by-id/DDPQ1RV5FE9U.I2WW34NGRD8Z@jeltef.nl
Please apply this patch on top of the GoAway patch.

The Solution: To handle this authorization gap gracefully, this patch
leverages the pending GoAway protocol message to notify clients.

Please find below summary of the solution

New GUC: auth_expiration_check_interval (integer, minutes). Controls the
frequency of checking a session's authorization status. Setting it to 0
(default) disables the check.

Periodic Idle Check: When a backend process is idle (waiting for the next
command) and the timeout is reached, the server calls a placeholder
function check_external_auth_status_expired().

Graceful Disconnect: If authorization is revoked/expired, the server sends
the GoAway message. This allows the client to finish any current
processing and reconnect cleanly.

Thanks & Best Regards,
Ajit Awekar

Attachments:

v1-Allow-client-goaway.patchtext/x-patch; charset=US-ASCII; name=v1-Allow-client-goaway.patch
#2Jelte Fennema-Nio
Jelte Fennema-Nio
postgres@jeltef.nl
In reply to: Ajit Awekar (#1)
Re: Periodic authorization expiration checks using GoAway message

On Fri, Nov 28, 2025, 04:39 Ajit Awekar <ajitpostgres@gmail.com> wrote:

This patch depends on the "GoAway" protocol message proposal currently
under review here:
/messages/by-id/DDPQ1RV5FE9U.I2WW34NGRD8Z@jeltef.nl
Please apply this patch on top of the GoAway patch.

A review of the GoAway patch from you would definitely be appreciated (even
if there's no actionable feedback like: "this looks good and I managed use
it for my own patch successfully")

The Solution: To handle this authorization gap gracefully, this patch

leverages the pending GoAway protocol message to notify clients.

I didn't look at the patch (I'm on my phone). But my first thought is that
only relying on the proposed version of GoAway is insufficient for anything
related to security. The GoAway message is both best effort, and only
supported with newer protocol versions. So while I think it's a good
usecase for GoAway, I think there *also* needs to be a hard timeout at
which point the connection gets forcefully terminated if it's using old
credentials.

Regarding the configurable interval that you describe for checking auth
changes, I think it might be better to register a SysCache update receiver
instead (or just poll the SysCache value

Finally, can you register this patch on the commitfest?
https://commitfest.postgresql.org/

Show quoted text
#3Hannu Krosing
Hannu Krosing
hannuk@google.com
In reply to: Jelte Fennema-Nio (#2)
Re: Periodic authorization expiration checks using GoAway message

Also have not looked at the patch, but we should also make sure that
there is not just be GoAway, but also a way to re-authenticate or
"extend lease" or whatever the terminology is for a specific
authentication method.

So maybe the message should be ReAuthentiocateOrElse" ?

Show quoted text

On Fri, Nov 28, 2025 at 6:19 PM Jelte Fennema-Nio <postgres@jeltef.nl> wrote:

On Fri, Nov 28, 2025, 04:39 Ajit Awekar <ajitpostgres@gmail.com> wrote:

This patch depends on the "GoAway" protocol message proposal currently under review here: /messages/by-id/DDPQ1RV5FE9U.I2WW34NGRD8Z@jeltef.nl Please apply this patch on top of the GoAway patch.

A review of the GoAway patch from you would definitely be appreciated (even if there's no actionable feedback like: "this looks good and I managed use it for my own patch successfully")

The Solution: To handle this authorization gap gracefully, this patch leverages the pending GoAway protocol message to notify clients.

I didn't look at the patch (I'm on my phone). But my first thought is that only relying on the proposed version of GoAway is insufficient for anything related to security. The GoAway message is both best effort, and only supported with newer protocol versions. So while I think it's a good usecase for GoAway, I think there *also* needs to be a hard timeout at which point the connection gets forcefully terminated if it's using old credentials.

Regarding the configurable interval that you describe for checking auth changes, I think it might be better to register a SysCache update receiver instead (or just poll the SysCache value

Finally, can you register this patch on the commitfest? https://commitfest.postgresql.org/

#4Ajit Awekar
Ajit Awekar
ajitpostgres@gmail.com
In reply to: Hannu Krosing (#3)
1 attachment(s)
Re: Periodic authorization expiration checks using GoAway message

Hello all,

Following the discussion regarding how to enforce rolvaliduntil for users
within an active session, I have implemented a solution that uses the
pg_authid SysCache listener mechanism as suggested. Please find the
attached patch for review.

Below is use case details for same

User3 started session

edb@localhost:~$ psql -U user3 -d postgres
psql (19devel)
Type "help" for help.
postgres=> \d
Did not find any relations.
postgres=> \d *<= prior to this command, password was expired in another
session by super user as shown below and it reflected immediately in active
session (prior active session was not impacted)*
FATAL: Connection expired due to internal password policy enforcement
DETAIL: User's password expired at 2025-11-02 16:59:37.462644+05:30.
HINT: Reconnect with a renewed password or obtain new authorization.

Before executing second \d command below super user session expired the
password of user3 as below

edb@localhost:~/Downloads/pg/postgres$ psql -d postgres
psql (19devel)
Type "help" for help.
postgres=# ALTER USER user3 VALID UNTIL '2025-11-02 16:59:37.462644+05:30';
ALTER ROLE

Thanks,
Ajit Awekar

On Fri, 28 Nov 2025 at 23:22, Hannu Krosing <hannuk@google.com> wrote:

Show quoted text

Also have not looked at the patch, but we should also make sure that
there is not just be GoAway, but also a way to re-authenticate or
"extend lease" or whatever the terminology is for a specific
authentication method.

So maybe the message should be ReAuthentiocateOrElse" ?

On Fri, Nov 28, 2025 at 6:19 PM Jelte Fennema-Nio <postgres@jeltef.nl>
wrote:

On Fri, Nov 28, 2025, 04:39 Ajit Awekar <ajitpostgres@gmail.com> wrote:

This patch depends on the "GoAway" protocol message proposal currently

under review here:
/messages/by-id/DDPQ1RV5FE9U.I2WW34NGRD8Z@jeltef.nl
Please apply this patch on top of the GoAway patch.

A review of the GoAway patch from you would definitely be appreciated

(even if there's no actionable feedback like: "this looks good and I
managed use it for my own patch successfully")

The Solution: To handle this authorization gap gracefully, this patch

leverages the pending GoAway protocol message to notify clients.

I didn't look at the patch (I'm on my phone). But my first thought is

that only relying on the proposed version of GoAway is insufficient for
anything related to security. The GoAway message is both best effort, and
only supported with newer protocol versions. So while I think it's a good
usecase for GoAway, I think there *also* needs to be a hard timeout at
which point the connection gets forcefully terminated if it's using old
credentials.

Regarding the configurable interval that you describe for checking auth

changes, I think it might be better to register a SysCache update receiver
instead (or just poll the SysCache value

Finally, can you register this patch on the commitfest?

https://commitfest.postgresql.org/

Attachments:

password_expire.patchapplication/octet-stream; name=password_expire.patch
#5Jacob Champion
Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Hannu Krosing (#3)
Re: Periodic authorization expiration checks using GoAway message

(To call it out explicitly: I work with Ajit, and I asked him to take
a look at GoAway, and I'm particularly interested in the
"reauthenticate or else" case. Let me know if any of that is
problematic -- or if anyone's worried that it will become so -- so I
can course-correct sooner rather than later.)

On Fri, Nov 28, 2025 at 9:52 AM Hannu Krosing <hannuk@google.com> wrote:

Also have not looked at the patch, but we should also make sure that
there is not just be GoAway, but also a way to re-authenticate or
"extend lease" or whatever the terminology is for a specific
authentication method.

I agree. I like the idea of the server coordinating (and then
enforcing) connection lifetime and cross-connection handoffs with the
client, but like Jelte said, the current GoAway proposal isn't really
built for that.

Is there enough interest in the more general problem for us to try
combining the use cases? Or should they remain separate?

Thanks,
--Jacob

#6Jelte Fennema-Nio
Jelte Fennema-Nio
postgres@jeltef.nl
In reply to: Jacob Champion (#5)
Re: Periodic authorization expiration checks using GoAway message

On Wed, 10 Dec 2025 at 21:02, Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

(To call it out explicitly: I work with Ajit, and I asked him to take
a look at GoAway, and I'm particularly interested in the
"reauthenticate or else" case. Let me know if any of that is
problematic -- or if anyone's worried that it will become so -- so I
can course-correct sooner rather than later.)

I think password rollover without downtime requires more thought than
discussed in this thread so far. Currently the simplest way (that I
know of) to rollover passwords without downtime is to have two users
that you can switch between, and one has been configured with:
ALTER USER b SET ROLE = a;

So both effectively log in as a.

Reading between the lines, I guess you're looking at this from the
OAuth lens. Not "normal" passwords.

On Fri, Nov 28, 2025 at 9:52 AM Hannu Krosing <hannuk@google.com> wrote:

Also have not looked at the patch, but we should also make sure that
there is not just be GoAway, but also a way to re-authenticate or
"extend lease" or whatever the terminology is for a specific
authentication method.

I agree. I like the idea of the server coordinating (and then
enforcing) connection lifetime and cross-connection handoffs with the
client, but like Jelte said, the current GoAway proposal isn't really
built for that.

If you want to re-authenticate over the existing connection (and
keeping your session etc), then I think that's a very different thing
than what I intended the GoAway message to be used for.

Is there enough interest in the more general problem for us to try
combining the use cases? Or should they remain separate?

I'm not sure what you mean with "combine the use cases". If you think
the GoAway protocol message definition could be extended slightly to
better serve this use case somehow. For instance if you think we
should have the GoAway message include an (optional) number of
seconds, so a client could say to the user: "Disconnect within 6
minutes". (just an example, not necessarily something I think is a
good idea)

If you mean combining by introducing a single shared protocol message
for both the "re-authenticate on existing session" and "please
reconnect asap", then I'd say: No, let's keep them separate.

I think for "re-authenticate now on existing connection" it'd be much
more natural for the server to simply send a new authentication
request message, and expect the client to respond to that. The auth
flow based on these messages is already implemented by each client,
they'd only need to change it so that it could be called into at any
moment (or maybe certain defined moments like in between queries).

#7Ajit Awekar
Ajit Awekar
ajitpostgres@gmail.com
In reply to: Jelte Fennema-Nio (#6)
Re: Periodic authorization expiration checks using GoAway message

Thanks a lot Jacob and Jelte for your valuable insights.

I agree that the seamless re-authentication model (re-authentication over
the active connection) is suited only for external centralized
authentication methods like OAuth2 and LDAP.

I have below questions

- Does the client need to pause current operations, execute a
simplified re-authentication sequence (triggered by the server's
Authentication Request), and then transparently resume the session upon
success?
- How frequently should the authorization expiration check occur in the
backend, Would the frequency be tied to a new session GUC (e.g.,
authorization_check_interval), allowing administrators to configure it?
- What should the behavior be for older version clients (backward
compatibility) that do not understand this new server-initiated
reauthentication message? In this case is the safest approach for the
server to terminate the connection?

Thanks & Best Regards,
Ajit

On Thu, 11 Dec 2025 at 02:50, Jelte Fennema-Nio <postgres@jeltef.nl> wrote:

Show quoted text

On Wed, 10 Dec 2025 at 21:02, Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

(To call it out explicitly: I work with Ajit, and I asked him to take
a look at GoAway, and I'm particularly interested in the
"reauthenticate or else" case. Let me know if any of that is
problematic -- or if anyone's worried that it will become so -- so I
can course-correct sooner rather than later.)

I think password rollover without downtime requires more thought than
discussed in this thread so far. Currently the simplest way (that I
know of) to rollover passwords without downtime is to have two users
that you can switch between, and one has been configured with:
ALTER USER b SET ROLE = a;

So both effectively log in as a.

Reading between the lines, I guess you're looking at this from the
OAuth lens. Not "normal" passwords.

On Fri, Nov 28, 2025 at 9:52 AM Hannu Krosing <hannuk@google.com> wrote:

Also have not looked at the patch, but we should also make sure that
there is not just be GoAway, but also a way to re-authenticate or
"extend lease" or whatever the terminology is for a specific
authentication method.

I agree. I like the idea of the server coordinating (and then
enforcing) connection lifetime and cross-connection handoffs with the
client, but like Jelte said, the current GoAway proposal isn't really
built for that.

If you want to re-authenticate over the existing connection (and
keeping your session etc), then I think that's a very different thing
than what I intended the GoAway message to be used for.

Is there enough interest in the more general problem for us to try
combining the use cases? Or should they remain separate?

I'm not sure what you mean with "combine the use cases". If you think
the GoAway protocol message definition could be extended slightly to
better serve this use case somehow. For instance if you think we
should have the GoAway message include an (optional) number of
seconds, so a client could say to the user: "Disconnect within 6
minutes". (just an example, not necessarily something I think is a
good idea)

If you mean combining by introducing a single shared protocol message
for both the "re-authenticate on existing session" and "please
reconnect asap", then I'd say: No, let's keep them separate.

I think for "re-authenticate now on existing connection" it'd be much
more natural for the server to simply send a new authentication
request message, and expect the client to respond to that. The auth
flow based on these messages is already implemented by each client,
they'd only need to change it so that it could be called into at any
moment (or maybe certain defined moments like in between queries).

#8Jacob Champion
Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Jelte Fennema-Nio (#6)
Re: Periodic authorization expiration checks using GoAway message

On Wed, Dec 10, 2025 at 1:21 PM Jelte Fennema-Nio <postgres@jeltef.nl> wrote:

I think password rollover without downtime requires more thought than
discussed in this thread so far.

Sure. See also

/messages/by-id/CAGB+Vh5SQQorNDEKP+0G=smxHRhbhs+VkmQWD5Vh98fmn8X4dg@mail.gmail.com

Reading between the lines, I guess you're looking at this from the
OAuth lens.

Yes. Or Kerberos.

Not "normal" passwords.

I could see a case for kicking connections after a SCRAM password
change, if they're not able to reauthenticate in X interval. But I
wouldn't make it my top priority, necessarily.

Is there enough interest in the more general problem for us to try
combining the use cases? Or should they remain separate?

I'm not sure what you mean with "combine the use cases". If you think
the GoAway protocol message definition could be extended slightly to
better serve this use case somehow.

Just that the two cases of "please consider reconnecting due to a
topology change" and "you didn't reauthenticate in time, so now you
_have_ to reconnect, bye" seem like they might be related at the
protocol level, since some types of topology changes might warrant a
harsher approach, and some types of authentication might do well with
a gentler one.

If you mean combining by introducing a single shared protocol message
for both the "re-authenticate on existing session" and "please
reconnect asap", then I'd say: No, let's keep them separate.

Agreed; I did not mean that.

I think for "re-authenticate now on existing connection" it'd be much
more natural for the server to simply send a new authentication
request message, and expect the client to respond to that. The auth
flow based on these messages is already implemented by each client,
they'd only need to change it so that it could be called into at any
moment (or maybe certain defined moments like in between queries).

I think that's probably the hard part. "in between" is not
particularly well-defined, especially once you add in some async
pipelining, right? Contrast with HTTP/3's GOAWAY, especially its
graceful shutdown flow.

--Jacob

#9Jacob Champion
Jacob Champion
jacob.champion@enterprisedb.com
In reply to: Ajit Awekar (#7)
Re: Periodic authorization expiration checks using GoAway message

On Thu, Dec 11, 2025 at 2:52 AM Ajit Awekar <ajitpostgres@gmail.com> wrote:

I agree that the seamless re-authentication model (re-authentication over the active connection) is suited only for external centralized authentication methods like OAuth2 and LDAP.

Well, see my response to Jelte above. But I think it's certainly
easier to pitch the usefulness of the feature for external methods.

Does the client need to pause current operations, execute a simplified re-authentication sequence (triggered by the server's Authentication Request), and then transparently resume the session upon success?

I think it would have to. But we don't number our conversations like
the other protocols with GOAWAY do, so it's not immediately clear to
me how we would do it.

The reauthentication sequence isn't guaranteed to be silent, either.
Imagine that you were typing a SQL command and psql popped up a
password prompt right in the middle; that's not a good user
experience.

How frequently should the authorization expiration check occur in the backend, Would the frequency be tied to a new session GUC (e.g., authorization_check_interval), allowing administrators to configure it?

I don't think there's one answer, so it'd probably have to be
configurable. Offline tokens and Kerberos tickets might have a known
timestamp for expiration, so you could just do a cheap timestamp
comparison for every single request. Online checks (to allow
revocation) would need more thought by the DBA; there's a
performance-staleness tradeoff there.

What should the behavior be for older version clients (backward compatibility) that do not understand this new server-initiated reauthentication message? In this case is the safest approach for the server to terminate the connection?

"Safe" is decided by the DBA, I think. Turning this on might imply
that you care more about security than the cost of cleaning up after a
client that got kicked off halfway through an important transaction...
or it might not.

--Jacob

#10Jelte Fennema-Nio
Jelte Fennema-Nio
postgres@jeltef.nl
In reply to: Jacob Champion (#8)
Re: Periodic authorization expiration checks using GoAway message

On Fri, 12 Dec 2025 at 01:10, Jacob Champion
<jacob.champion@enterprisedb.com> wrote:

/messages/by-id/CAGB+Vh5SQQorNDEKP+0G=smxHRhbhs+VkmQWD5Vh98fmn8X4dg@mail.gmail.com

Thanks, I hadn't seen that one before.

"you didn't reauthenticate in time, so now you
_have_ to reconnect, bye"

I might be missing something but I feel like we currently do this in
various other places using:
FATAL: <message explaining reason>
<connection close>

I think that's probably the hard part. "in between" is not
particularly well-defined, especially once you add in some async
pipelining, right?

Yeah, pipelining is annoying for these kind of things. But looking
it's not so bad. What if you define the flow as:
1. server sends 'R' message when it realizes it wants a
re-authentication (allowed whenever, just like NoticeResponse)
2. client can continue to send whatever and server will respond accordingly
3a. client starts authentication flow by sending a 'p' message
3b. client did not complete auth flow within timeout of the server, so
server sends FATAL + closes connection.

#11Zsolt Parragi
Zsolt Parragi
zsolt.parragi@percona.com
In reply to: Jelte Fennema-Nio (#10)
Re: Periodic authorization expiration checks using GoAway message

Would client side revalidation allow re-authentication while a
long-running query is in progress? Or would it kick out a connection
because it can't reauthenticate after some grace period? A strict OIDC
setup might use 5 or 10 minute access tokens, where this is a
realistic issue.

Online checks (to allow revocation) would need more thought by the DBA; there's a performance-staleness tradeoff there.

Are revocation checks really related to GoAway? Even with offline OIDC
tokens, we can implement periodic server side checks to see if a long
lived token is still alive using an introspection endpoint.

I think this should be already possible with current validators, by
closing the connection if we find out that a token was revoked -
trying to implement this is on my TODO list. Should we really handle
this through GoAway, and allow a graceful period? If a token was
revoked, there's usually a good reason for that.