| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 | 
							- = 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.
 
 
  |