feat(jwt): per-audience access-token TTLs via TokenTtlPolicy SPI#12
Merged
Conversation
Replaces JwtConfig.tokenTtl (single Duration) with a TokenTtlPolicy SPI
keyed on the JWT aud claim, so multi-client deployments can issue
different access-token lifetimes per audience (e.g. web=15m, cli=1h)
without forking PkAuthJwtIssuer. The validator now accepts the union
of {defaultAudience} ∪ ttlPolicy.knownAudiences(). See ADR 0014.
JwtClaims gains an optional `audience` field; null falls back to
JwtConfig.defaultAudience(). Validator returns the matched audience on
the reconstructed claims so callers can read what the token was for.
Adapter property records (Spring/Dropwizard/Micronaut) gain
`defaultTtl` + `ttlsByAudience` and rename their single-TTL field.
This is the first of three PRs landing on the 1.1.0 train; the next
two add stateful access tokens (Feature 3) and rotating refresh tokens
with family-based replay defense (Feature 1).
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
TokenTtlPolicySPI inpk-auth-jwtkeyed on the JWTaudclaim, replacing the singleJwtConfig.tokenTtlDuration. Multi-client deployments (web vs cli vs mobile) can now configure different access-token lifetimes per audience without forkingPkAuthJwtIssuer.JwtConfig.audience→defaultAudience. Validator accepts the union{defaultAudience} ∪ ttlPolicy.knownAudiences(), so one validator bean serves every audience the policy declares.audiencefield toJwtClaims. Null means "use the issuer's default audience". The validator returns the matched audience on the reconstructedJwtClaimsso callers can read what the token was issued for.PkAuthProperties.Jwt, DropwizardPkAuthConfig.Jwt, MicronautPkAuthConfiguration.Jwt) each gaindefaultTtl+ttlsByAudienceand rename their single-TTL field. Adapters build the policy viaTokenTtlPolicy.fixed(...)/TokenTtlPolicy.single(...).This is PR 1 of 3 landing on the 1.1.0 train (see
docs/adr/0014-per-audience-ttl-policy.mdand the rollout plan inCHANGELOG.md). PR 2 adds stateful access tokens; PR 3 adds rotating refresh tokens with family-based replay defense.Test plan
./gradlew :pk-auth-jwt:test— 28 tests pass, including 5 new cases (perAudienceTtlPolicyDispatches,audienceAbsentFromClaimsUsesDefaultAudienceAndDefaultTtl,validatorAcceptsAudiencesDeclaredByPolicy,validatorRejectsUnknownAudienceEvenIfIssuedBySameKey,allowedAudiencesIncludesDefaultPlusPolicyKnownAudiences)../gradlew check— full build green across all 14 modules including Postgres Testcontainers and DynamoDB Local integration tests, all three adapter integration tests, all three example demos.PkAuthDevModeGuardTest(which broke initially due to Spring's record-binding picking the wrong constructor) passes after removing the auxiliary constructor fromPkAuthProperties.Jwt.🤖 Generated with Claude Code