JwtAuth.verifyTimeBounds at lib/src/main/kotlin/dev/arcp/auth/JwtAuth.kt:53 rejects a token whenever exp is not strictly after Date() or nbf is strictly after Date(), with no leeway, which means routine multi-host clock drift of even a few hundred milliseconds turns a valid token into ARCPException.Unauthenticated("JWT expired") or "JWT not yet valid". RFC 7519 §4.1.4 explicitly recommends allowing a small skew for these claims, and every mainstream JWT library exposes the parameter. verify at lib/src/main/kotlin/dev/arcp/auth/JwtAuth.kt:21 also never checks the iss claim, so a token signed by the right key for the right audience but issued by an unrelated party still authenticates — leaving the runtime trusting any peer that shares the HMAC secret or signing key, even when the deployment has multiple issuers behind one verifier.
Fix prompt: Add an allowedClockSkew: Duration = 1.minutes parameter to JwtAuth and apply it to both exp and nbf comparisons. Add an expectedIssuer: String? = null parameter (and corresponding KDoc) that, when set, requires the JWT iss claim to match before returning the principal. Document the new parameters and update JwtAuth.hmac to forward them. Add unit tests in a new lib/src/test/kotlin/dev/arcp/auth/JwtAuthTest.kt covering: skew tolerance for exp and nbf, issuer match and mismatch, and the default behavior when expectedIssuer is unset.
JwtAuth.verifyTimeBoundsatlib/src/main/kotlin/dev/arcp/auth/JwtAuth.kt:53rejects a token wheneverexpis not strictly afterDate()ornbfis strictly afterDate(), with no leeway, which means routine multi-host clock drift of even a few hundred milliseconds turns a valid token intoARCPException.Unauthenticated("JWT expired")or"JWT not yet valid". RFC 7519 §4.1.4 explicitly recommends allowing a small skew for these claims, and every mainstream JWT library exposes the parameter.verifyatlib/src/main/kotlin/dev/arcp/auth/JwtAuth.kt:21also never checks theissclaim, so a token signed by the right key for the right audience but issued by an unrelated party still authenticates — leaving the runtime trusting any peer that shares the HMAC secret or signing key, even when the deployment has multiple issuers behind one verifier.Fix prompt: Add an
allowedClockSkew: Duration = 1.minutesparameter toJwtAuthand apply it to bothexpandnbfcomparisons. Add anexpectedIssuer: String? = nullparameter (and corresponding KDoc) that, when set, requires the JWTissclaim to match before returning the principal. Document the new parameters and updateJwtAuth.hmacto forward them. Add unit tests in a newlib/src/test/kotlin/dev/arcp/auth/JwtAuthTest.ktcovering: skew tolerance forexpandnbf, issuer match and mismatch, and the default behavior whenexpectedIssueris unset.