OIDC ClockSkewAware implementation

10 views
Skip to first unread message

Kaushal Senevirathne

unread,
Jul 29, 2026, 11:49:41 PMJul 29
to Pac4j development mailing list
Hi Pac4j Team,

I’ve been looking at how pac4j-oidc handles clock skew for OpenID Connect tokens and wanted to confirm the intended behavior.

From the current code:

ID token (and logout token) validation uses Nimbus IDTokenValidator / LogoutTokenValidator, which implement com.nimbusds.jwt.proc.ClockSkewAware. In TokenValidator, pac4j calls setMaxClockSkew(config.getMaxClockSkew()) so OidcConfiguration.maxClockSkew is honored during cryptographic JWT validation (exp / nbf / related checks).

Access token expiry, however, does not go through a ClockSkewAware validator. In OidcProfile, expiration is derived from the token response lifetime or from a JWT exp claim, and isExpired() only considers tokenExpirationAdvance — not maxClockSkew.

Could you clarify whether this asymmetry is intentional?

Jérôme LELEU

unread,
Jul 30, 2026, 7:01:07 AMJul 30
to Kaushal Senevirathne, Pac4j development mailing list
Hi,

I think it's an oversight. That said, should we really apply an extra clock skew for the profile expiration?
Thanks.
Best regards,
Jérôme


--
You received this message because you are subscribed to the Google Groups "Pac4j development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pac4j-dev+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/pac4j-dev/bc80a425-2d88-44cf-b871-61d400374c81n%40googlegroups.com.

Kaushal Senevirathne

unread,
Jul 31, 2026, 4:12:50 AMJul 31
to Jérôme LELEU, Pac4j development mailing list
Hi Jérôme, 

Our concrete case is a multi-hop check on the same access token:

  1. OAuth proxy validates the access token at the edge and accepts the request.
  2. The request is then forwarded to the web server / app (pac4j).
  3. By the time pac4j evaluates profile / access-token expiry, the token can already look expired (or fail the time check), even though the proxy just treated it as valid.

So we end up with:

  • Proxy entry: token valid
  • App / pac4j: token (or profile) considered expired

That mismatch usually comes from small clock drift between proxy and app, plus the time spent in transit / processing — not from a bad token. For ID tokens, maxClockSkew already absorbs that. For access-token-driven profile expiry, we don’t get the same tolerance today, so the second hop is stricter than the first.

That’s why we raised it: not because we want sessions kept alive long after real expiry, but because we need the app’s time check to be consistent with the proxy’s under normal skew.

 Thanks
Kaushal,

Jérôme LELEU

unread,
Jul 31, 2026, 5:25:33 AMJul 31
to Kaushal Senevirathne, Pac4j development mailing list
Hi,

OK. That makes sense.
Please submit a PR to address this use case.
Thanks.
Best regards,
Jérôme

Reply all
Reply to author
Forward
0 new messages