Skip to content

fix(auth): bind internal JWTs to principal secret generation#5053

Open
vigneshio wants to merge 5 commits into
apache:mainfrom
vigneshio:fix/jwt-bind-credentials-epoch
Open

fix(auth): bind internal JWTs to principal secret generation#5053
vigneshio wants to merge 5 commits into
apache:mainfrom
vigneshio:fix/jwt-bind-credentials-epoch

Conversation

@vigneshio

Copy link
Copy Markdown
Contributor

Internal JWTs are bound to the principal's current main secret hash (cv claim). After credential rotate or reset, previously issued access tokens are rejected on verify so sessions cannot outlive a secret compromise response.

Tokens minted before this change (missing cv) are also rejected and must be reissued via client credentials.

No schema migration: the fingerprint is the existing mainSecretHash.

@github-project-automation github-project-automation Bot moved this to PRs In Progress in Basic Kanban Board Jul 13, 2026
@vigneshio
vigneshio force-pushed the fix/jwt-bind-credentials-epoch branch from 5925d16 to 1a98a23 Compare July 16, 2026 13:35

@dimas-b dimas-b left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your diligence, @vigneshio ! The general idea is very reasonable. Some implementation comments below.

@dimas-b
dimas-b requested review from adutra and snazy July 16, 2026 22:47
@vigneshio
vigneshio force-pushed the fix/jwt-bind-credentials-epoch branch from 1a98a23 to 083f99e Compare July 17, 2026 08:02
*/
@Nullable
public String getCredentialsVersion() {
return mainSecretHash == null ? null : DigestUtils.sha256Hex(mainSecretHash);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should salt this hash for good measure.

Also, "version" processing should respect the "secondary" hash too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dimas-b Thanks for the review!.. I updated the credentials version to use a salted fingerprint (secretSalt) instead of hashing the main secret hash alone, and verify now accepts either the main or secondary generation. That keeps JWT binding aligned with dual-secret rotate: one rotation leaves the previous generation valid via secondary; another rotate/reset drops it...

@dimas-b dimas-b left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

partial review

Embed a credentials-generation fingerprint (polaris-cv claim) in minted
access tokens. The version is derived from the principal's current main
secret hash (hash of the hash), so the secret-verification artifact
itself is never exposed in the unencrypted token and no schema change
is needed.

On verify (and thus token exchange), tokens whose version no longer
matches are rejected, so credential rotate/reset invalidates
outstanding sessions without waiting for token expiry.

Tokens minted before this change carry no claim and remain valid until
expiry for upgrade compatibility; they become bound on the next
rotate/reset.
Access tokens are bound to per-realm principal secret hashes. Reusing a
POLARIS admin token against POLARIS2 correctly returns 401. Bootstrap
both realms with known credentials and obtain a POLARIS2 token for the
cross-realm rate-limit isolation assertion.
Address review feedback on JWT credentials binding: derive polaris-cv
with the principal secret salt, and accept tokens matching the main or
secondary secret-hash fingerprint so dual-secret rotate grace aligns
with client-secret matching. A second rotate/reset invalidates older
bound tokens.
@vigneshio
vigneshio force-pushed the fix/jwt-bind-credentials-epoch branch from bba3287 to a66743e Compare July 20, 2026 20:56
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.

2 participants