= OAuth 2.0 Changes == Validate `typ` Header with `JwtTypeValidator` `NimbusJwtDecoder` in Spring Security 7 will move `typ` header validation to `JwtTypeValidator` intsead of relying on Nimbus. This brings it in line with `NimbusJwtDecoder` validating claims instead of relying on Nimbus to validate them. If you are changing Nimbus's default type validation in a `jwtProcessorCustomizer` method, then you should move that to `JwtTypeValidator` or an implementation of `OAuth2TokenValidator` of your own. To check if you are prepared for this change, add the default `JwtTypeValidator` to your list of validators, as this will be included by default in 7: [tabs] ====== Java:: + [source,java,role="primary"] ---- @Bean JwtDecoder jwtDecoder() { NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location) .validateTypes(false) <1> // ... your remaining configuration .build(); jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators( new JwtIssuerValidator(location), JwtTypeValidator.jwt())); <2> return jwtDecoder; } ---- Kotlin:: + [source,kotlin,role="secondary"] ---- @Bean fun jwtDecoder(): JwtDecoder { val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location) .validateTypes(false) <1> // ... your remaining configuration .build() jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators( JwtIssuerValidator(location), JwtTypeValidator.jwt())) <2> return jwtDecoder } ---- ====== <1> - Switch off Nimbus verifying the `typ` (this will be off by default in 7) <2> - Add the default `typ` validator (this will be included by default in 7) Note the default value verifies that the `typ` value either be `JWT` or not present, which is the same as the Nimbus default. It is also aligned with https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.9[RFC 7515] which states that `typ` is optional. === I'm Using A `DefaultJOSEObjectTypeVerifier` If you have something like the following in your configuration: [tabs] ====== Java:: + [source,java,role="primary"] ---- @Bean JwtDecoder jwtDecoder() { NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location) .jwtProcessorCustomizer((c) -> c .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>("JOSE")) ) .build(); return jwtDecoder; } ---- Kotlin:: + [source,kotlin,role="secondary"] ---- @Bean fun jwtDecoder(): JwtDecoder { val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location) .jwtProcessorCustomizer { it.setJWSTypeVerifier(DefaultJOSEObjectTypeVerifier("JOSE")) } .build() return jwtDecoder } ---- ====== Then change this to: [tabs] ====== Java:: + [source,java,role="primary"] ---- @Bean JwtDecoder jwtDecoder() { NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location) .validateTypes(false) .build(); jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators( new JwtIssuerValidator(location), new JwtTypeValidator("JOSE"))); return jwtDecoder; } ---- Kotlin:: + [source,kotlin,role="secondary"] ---- @Bean fun jwtDecoder(): JwtDecoder { val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location) .validateTypes(false) .build() jwtDecoder.setJwtValidator(JwtValidators.createDefaultWithValidators( JwtIssuerValidator(location), JwtTypeValidator("JOSE"))) return jwtDecoder } ---- ====== To indicate that the `typ` header is optional, use `#setAllowEmpty(true)` (this is the equivalent of including `null` in the list of allowed types in `DefaultJOSEObjectTypeVerifier`). === I want to opt-out If you want to keep doing things the way that you are, then the steps are similar, just in reverse: [tabs] ====== Java:: + [source,java,role="primary"] ---- @Bean JwtDecoder jwtDecoder() { NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location) .validateTypes(true) <1> .jwtProcessorCustomizer((c) -> c .setJWSTypeVerifier(new DefaultJOSEObjectTypeVerifier<>("JOSE")) ) .build(); jwtDecoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>( new JwtTimestampValidator(), new JwtIssuerValidator(location))); <2> return jwtDecoder; } ---- Kotlin:: + [source,kotlin,role="secondary"] ---- @Bean fun jwtDecoder(): JwtDecoder { val jwtDecoder = NimbusJwtDecoder.withIssuerLocation(location) .validateTypes(true) <1> .jwtProcessorCustomizer { it.setJWSTypeVerifier(DefaultJOSEObjectTypeVerifier("JOSE")) } .build() jwtDecoder.setJwtValidator(DelegatingOAuth2TokenValidator( JwtTimestampValidator(), JwtIssuerValidator(location))) <2> return jwtDecoder } ---- ====== <1> - leave Nimbus type verification on <2> - specify the list of validators you need, excluding `JwtTypeValidator` For additional guidance, please see the xref:servlet/oauth2/resource-server/jwt.adoc#oauth2resourceserver-jwt-validation[JwtDecoder Validators] section in the reference.