3333import javax .crypto .SecretKey ;
3434
3535import com .nimbusds .jose .JOSEException ;
36+ import com .nimbusds .jose .JOSEObjectType ;
3637import com .nimbusds .jose .JWSAlgorithm ;
3738import com .nimbusds .jose .KeySourceException ;
3839import com .nimbusds .jose .RemoteKeySourceException ;
4142import com .nimbusds .jose .jwk .source .JWKSetSource ;
4243import com .nimbusds .jose .jwk .source .JWKSource ;
4344import com .nimbusds .jose .jwk .source .JWKSourceBuilder ;
45+ import com .nimbusds .jose .proc .DefaultJOSEObjectTypeVerifier ;
46+ import com .nimbusds .jose .proc .JOSEObjectTypeVerifier ;
4447import com .nimbusds .jose .proc .JWSKeySelector ;
4548import com .nimbusds .jose .proc .JWSVerificationKeySelector ;
4649import com .nimbusds .jose .proc .SecurityContext ;
@@ -265,11 +268,20 @@ public static SecretKeyJwtDecoderBuilder withSecretKey(SecretKey secretKey) {
265268 */
266269 public static final class JwkSetUriJwtDecoderBuilder {
267270
271+ private static final JOSEObjectTypeVerifier <SecurityContext > JWT_TYPE_VERIFIER = new DefaultJOSEObjectTypeVerifier <>(
272+ JOSEObjectType .JWT , null );
273+
274+ private static final JOSEObjectTypeVerifier <SecurityContext > NO_TYPE_VERIFIER = (header , context ) -> {
275+ };
276+
268277 private Function <RestOperations , String > jwkSetUri ;
269278
270279 private Function <JWKSource <SecurityContext >, Set <JWSAlgorithm >> defaultAlgorithms = (source ) -> Set
271280 .of (JWSAlgorithm .RS256 );
272281
282+ private JOSEObjectTypeVerifier <SecurityContext > typeVerifier = new DefaultJOSEObjectTypeVerifier <>(
283+ JOSEObjectType .JWT , null );
284+
273285 private Set <SignatureAlgorithm > signatureAlgorithms = new HashSet <>();
274286
275287 private RestOperations restOperations = new RestTemplate ();
@@ -295,6 +307,54 @@ private JwkSetUriJwtDecoderBuilder(Function<RestOperations, String> jwkSetUri,
295307 };
296308 }
297309
310+ /**
311+ * Whether to use Nimbus's typ header verification. This is {@code true} by
312+ * default, however it may change to {@code false} in a future major release.
313+ *
314+ * <p>
315+ * By turning off this feature, {@link NimbusJwtDecoder} expects applications to
316+ * check the {@code typ} header themselves in order to determine what kind of
317+ * validation is needed
318+ * </p>
319+ *
320+ * <p>
321+ * This is done for you when you use {@link JwtValidators} to construct a
322+ * validator.
323+ *
324+ * <p>
325+ * That means that this: <code>
326+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer).build();
327+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
328+ * </code>
329+ *
330+ * <p>
331+ * Is equivalent to this: <code>
332+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
333+ * .validateType(false)
334+ * .build();
335+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
336+ * </code>
337+ *
338+ * <p>
339+ * The difference is that by setting this to {@code false}, it allows you to
340+ * provide validation by type, like for {@code at+jwt}:
341+ *
342+ * <code>
343+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
344+ * .validateType(false)
345+ * .build();
346+ * jwtDecoder.setJwtValidator(new MyAtJwtValidator());
347+ * </code>
348+ * @param shouldValidateTypHeader whether Nimbus should validate the typ header or
349+ * not
350+ * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
351+ * @since 6.5
352+ */
353+ public JwkSetUriJwtDecoderBuilder validateType (boolean shouldValidateTypHeader ) {
354+ this .typeVerifier = shouldValidateTypHeader ? JWT_TYPE_VERIFIER : NO_TYPE_VERIFIER ;
355+ return this ;
356+ }
357+
298358 /**
299359 * Append the given signing
300360 * <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
@@ -389,6 +449,7 @@ JWKSource<SecurityContext> jwkSource() {
389449 JWTProcessor <SecurityContext > processor () {
390450 JWKSource <SecurityContext > jwkSource = jwkSource ();
391451 ConfigurableJWTProcessor <SecurityContext > jwtProcessor = new DefaultJWTProcessor <>();
452+ jwtProcessor .setJWSTypeVerifier (this .typeVerifier );
392453 jwtProcessor .setJWSKeySelector (jwsKeySelector (jwkSource ));
393454 // Spring Security validates the claim set independent from Nimbus
394455 jwtProcessor .setJWTClaimsSetVerifier ((claims , context ) -> {
@@ -481,8 +542,17 @@ public void close() {
481542 */
482543 public static final class PublicKeyJwtDecoderBuilder {
483544
545+ private static final JOSEObjectTypeVerifier <SecurityContext > JWT_TYPE_VERIFIER = new DefaultJOSEObjectTypeVerifier <>(
546+ JOSEObjectType .JWT , null );
547+
548+ private static final JOSEObjectTypeVerifier <SecurityContext > NO_TYPE_VERIFIER = (header , context ) -> {
549+ };
550+
484551 private JWSAlgorithm jwsAlgorithm ;
485552
553+ private JOSEObjectTypeVerifier <SecurityContext > typeVerifier = new DefaultJOSEObjectTypeVerifier <>(
554+ JOSEObjectType .JWT , null );
555+
486556 private RSAPublicKey key ;
487557
488558 private Consumer <ConfigurableJWTProcessor <SecurityContext >> jwtProcessorCustomizer ;
@@ -495,6 +565,54 @@ private PublicKeyJwtDecoderBuilder(RSAPublicKey key) {
495565 };
496566 }
497567
568+ /**
569+ * Whether to use Nimbus's typ header verification. This is {@code true} by
570+ * default, however it may change to {@code false} in a future major release.
571+ *
572+ * <p>
573+ * By turning off this feature, {@link NimbusJwtDecoder} expects applications to
574+ * check the {@code typ} header themselves in order to determine what kind of
575+ * validation is needed
576+ * </p>
577+ *
578+ * <p>
579+ * This is done for you when you use {@link JwtValidators} to construct a
580+ * validator.
581+ *
582+ * <p>
583+ * That means that this: <code>
584+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer).build();
585+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
586+ * </code>
587+ *
588+ * <p>
589+ * Is equivalent to this: <code>
590+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
591+ * .validateType(false)
592+ * .build();
593+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
594+ * </code>
595+ *
596+ * <p>
597+ * The difference is that by setting this to {@code false}, it allows you to
598+ * provide validation by type, like for {@code at+jwt}:
599+ *
600+ * <code>
601+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
602+ * .validateType(false)
603+ * .build();
604+ * jwtDecoder.setJwtValidator(new MyAtJwtValidator());
605+ * </code>
606+ * @param shouldValidateTypHeader whether Nimbus should validate the typ header or
607+ * not
608+ * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
609+ * @since 6.5
610+ */
611+ public PublicKeyJwtDecoderBuilder validateType (boolean shouldValidateTypHeader ) {
612+ this .typeVerifier = shouldValidateTypHeader ? JWT_TYPE_VERIFIER : NO_TYPE_VERIFIER ;
613+ return this ;
614+ }
615+
498616 /**
499617 * Use the given signing
500618 * <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
@@ -533,6 +651,7 @@ JWTProcessor<SecurityContext> processor() {
533651 + this .jwsAlgorithm + ". Please indicate one of RS256, RS384, or RS512." );
534652 JWSKeySelector <SecurityContext > jwsKeySelector = new SingleKeyJWSKeySelector <>(this .jwsAlgorithm , this .key );
535653 DefaultJWTProcessor <SecurityContext > jwtProcessor = new DefaultJWTProcessor <>();
654+ jwtProcessor .setJWSTypeVerifier (this .typeVerifier );
536655 jwtProcessor .setJWSKeySelector (jwsKeySelector );
537656 // Spring Security validates the claim set independent from Nimbus
538657 jwtProcessor .setJWTClaimsSetVerifier ((claims , context ) -> {
@@ -557,10 +676,19 @@ public NimbusJwtDecoder build() {
557676 */
558677 public static final class SecretKeyJwtDecoderBuilder {
559678
679+ private static final JOSEObjectTypeVerifier <SecurityContext > JWT_TYPE_VERIFIER = new DefaultJOSEObjectTypeVerifier <>(
680+ JOSEObjectType .JWT , null );
681+
682+ private static final JOSEObjectTypeVerifier <SecurityContext > NO_TYPE_VERIFIER = (header , context ) -> {
683+ };
684+
560685 private final SecretKey secretKey ;
561686
562687 private JWSAlgorithm jwsAlgorithm = JWSAlgorithm .HS256 ;
563688
689+ private JOSEObjectTypeVerifier <SecurityContext > typeVerifier = new DefaultJOSEObjectTypeVerifier <>(
690+ JOSEObjectType .JWT , null );
691+
564692 private Consumer <ConfigurableJWTProcessor <SecurityContext >> jwtProcessorCustomizer ;
565693
566694 private SecretKeyJwtDecoderBuilder (SecretKey secretKey ) {
@@ -570,6 +698,54 @@ private SecretKeyJwtDecoderBuilder(SecretKey secretKey) {
570698 };
571699 }
572700
701+ /**
702+ * Whether to use Nimbus's typ header verification. This is {@code true} by
703+ * default, however it may change to {@code false} in a future major release.
704+ *
705+ * <p>
706+ * By turning off this feature, {@link NimbusJwtDecoder} expects applications to
707+ * check the {@code typ} header themselves in order to determine what kind of
708+ * validation is needed
709+ * </p>
710+ *
711+ * <p>
712+ * This is done for you when you use {@link JwtValidators} to construct a
713+ * validator.
714+ *
715+ * <p>
716+ * That means that this: <code>
717+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer).build();
718+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
719+ * </code>
720+ *
721+ * <p>
722+ * Is equivalent to this: <code>
723+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
724+ * .validateType(false)
725+ * .build();
726+ * jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithIssuer(issuer);
727+ * </code>
728+ *
729+ * <p>
730+ * The difference is that by setting this to {@code false}, it allows you to
731+ * provide validation by type, like for {@code at+jwt}:
732+ *
733+ * <code>
734+ * NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer)
735+ * .validateType(false)
736+ * .build();
737+ * jwtDecoder.setJwtValidator(new MyAtJwtValidator());
738+ * </code>
739+ * @param shouldValidateTypHeader whether Nimbus should validate the typ header or
740+ * not
741+ * @return a {@link JwkSetUriJwtDecoderBuilder} for further configurations
742+ * @since 6.5
743+ */
744+ public SecretKeyJwtDecoderBuilder validateType (boolean shouldValidateTypHeader ) {
745+ this .typeVerifier = shouldValidateTypHeader ? JWT_TYPE_VERIFIER : NO_TYPE_VERIFIER ;
746+ return this ;
747+ }
748+
573749 /**
574750 * Use the given
575751 * <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1" target=
@@ -615,6 +791,7 @@ JWTProcessor<SecurityContext> processor() {
615791 this .secretKey );
616792 DefaultJWTProcessor <SecurityContext > jwtProcessor = new DefaultJWTProcessor <>();
617793 jwtProcessor .setJWSKeySelector (jwsKeySelector );
794+ jwtProcessor .setJWSTypeVerifier (this .typeVerifier );
618795 // Spring Security validates the claim set independent from Nimbus
619796 jwtProcessor .setJWTClaimsSetVerifier ((claims , context ) -> {
620797 });
0 commit comments