1818
1919import java .nio .charset .StandardCharsets ;
2020import java .security .MessageDigest ;
21- import java .time .Clock ;
2221import java .time .Instant ;
22+ import java .time .temporal .ChronoUnit ;
2323import java .util .Base64 ;
2424import java .util .Collections ;
25+ import java .util .LinkedHashMap ;
2526import java .util .Map ;
26- import java .util .concurrent .ConcurrentHashMap ;
2727import java .util .function .Function ;
2828
2929import com .nimbusds .jose .JOSEException ;
@@ -146,7 +146,7 @@ private static Function<DPoPProofContext, OAuth2TokenValidator<Jwt>> defaultJwtV
146146
147147 private static final class JtiClaimValidator implements OAuth2TokenValidator <Jwt > {
148148
149- private static final Map <String , Long > jtiCache = new ConcurrentHashMap <>( );
149+ private static final Map <String , Long > JTI_CACHE = Collections . synchronizedMap ( new JtiCache () );
150150
151151 @ Override
152152 public OAuth2TokenValidatorResult validate (Jwt jwt ) {
@@ -166,8 +166,8 @@ public OAuth2TokenValidatorResult validate(Jwt jwt) {
166166 OAuth2Error error = createOAuth2Error ("jti claim is invalid." );
167167 return OAuth2TokenValidatorResult .failure (error );
168168 }
169- Instant now = Instant .now (Clock . systemUTC () );
170- if ((jtiCache .putIfAbsent (jtiHash , now .toEpochMilli ())) != null ) {
169+ Instant expiry = Instant .now (). plus ( 1 , ChronoUnit . HOURS );
170+ if ((JTI_CACHE .putIfAbsent (jtiHash , expiry .toEpochMilli ())) != null ) {
171171 // Already used
172172 OAuth2Error error = createOAuth2Error ("jti claim is invalid." );
173173 return OAuth2TokenValidatorResult .failure (error );
@@ -185,6 +185,21 @@ private static String computeSHA256(String value) throws Exception {
185185 return Base64 .getUrlEncoder ().withoutPadding ().encodeToString (digest );
186186 }
187187
188+ private static final class JtiCache extends LinkedHashMap <String , Long > {
189+
190+ private static final int MAX_SIZE = 1000 ;
191+
192+ @ Override
193+ protected boolean removeEldestEntry (Map .Entry <String , Long > eldest ) {
194+ if (size () > MAX_SIZE ) {
195+ return true ;
196+ }
197+ Instant expiry = Instant .ofEpochMilli (eldest .getValue ());
198+ return Instant .now ().isAfter (expiry );
199+ }
200+
201+ }
202+
188203 }
189204
190205}
0 commit comments