Skip to content

Spring Boot 2.3.x refuses JWT tokens with custom typ header #8730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jrehwaldt opened this issue Jun 19, 2020 · 5 comments
Closed

Spring Boot 2.3.x refuses JWT tokens with custom typ header #8730

jrehwaldt opened this issue Jun 19, 2020 · 5 comments
Assignees
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement
Milestone

Comments

@jrehwaldt
Copy link
Contributor

jrehwaldt commented Jun 19, 2020

Spring Boot 2.3.x.RELEASE applies additional non-standard validation on JWT tokens due to upgrade to NimbusDS 8.x.

With Spring Boot 2.2.2.RELEASE a JWT token with header field typ: "JWS" validates fine. In Spring Boot 2.3.0.RELEASE such a token is rejected due to a breaking change in NimbusDS 8.x, which requires typ to be set to either JWT or omitted.

As per RFC 7515 there's no dedicated typ mandated.

The issue is that the builder design in NimbusJwtDecoder (in my case NimbusJwtDecoder.withPublicKey(publicKey).build()) does not allow to go back to the old behavior, nor does it allow to change the JWSTypeVerifier/JWETypeVerifier set in NimbusDS's DefaultJWTProcessor. Therefore, it is currently necessary to duplicate the complete builder code, which is making me uneasy considering it's a security relevant part and a future change in Spring Security/Nimbus might render my code insecure.

Current Behavior

JWT tokens with typ: JWS are refused since Spring Boot 2.3.x

Expected Behavior

Either one of:

Context

Dependency: org.springframework.security:spring-security-oauth2-jose:5.3.3.RELEASE
Class: org.springframework.security.oauth2.jwt.NimbusJwtDecoder

Unfortunately, I am not in control of the authorization server, which generates these custom JWTs. At the same time, I do not want to copy security relevant code.

Possible solutions:

  1. restore previous behavior by setting JWSTypeVerifier/JWETypeVerifier to no-op verifiers in the builder(s)
  2. allow to configure allowed types via config/builder
  3. keep as is and require users to duplicate the builder code to apply either 1. or 2.
Stacktrace
{
   "cause":null,
   "stackTrace":[
      {
         "classLoaderName":"app",
         "moduleName":null,
         "moduleVersion":null,
         "methodName":"authenticate",
         "fileName":"JwtAuthenticationProvider.java",
         "lineNumber":86,
         "nativeMethod":false,
         "className":"org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider"
      },
      {
         "classLoaderName":"app",
         "moduleName":null,
         "moduleVersion":null,
         "methodName":"authenticate",
         "fileName":"ProviderManager.java",
         "lineNumber":199,
         "nativeMethod":false,
         "className":"org.springframework.security.authentication.ProviderManager"
      },
      {
         "classLoaderName":"app",
         "moduleName":null,
         "moduleVersion":null,
         "methodName":"doFilterInternal",
         "fileName":"BearerTokenAuthenticationFilter.java",
         "lineNumber":124,
         "nativeMethod":false,
         "className":"org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter"
      }
      // ... [snip]
   ],
   "title":"Unauthorized",
   "status":"UNAUTHORIZED",
   "detail":"An error occurred while attempting to decode the Jwt: JOSE header \"typ\" (type) \"JWS\" not allowed"
}
@jrehwaldt jrehwaldt added status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement labels Jun 19, 2020
@mrguamos
Copy link

This is my problem too. Since the IdentityServer4 uses “at+jwt” JWT typ. Token validation always fail. Good thing I have control in the IS4 and set its typ to “jwt”

@jzheaux jzheaux added in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 19, 2020
@jzheaux
Copy link
Contributor

jzheaux commented Jun 19, 2020

Thanks for the heads up, @jrehwaldt and @materia2021.

While this could be solved by manually constructing a DefaultJWTProcessor and passing it to the NimbusJwtDecoder constructor, I think it'd be nice for the builders to be equipped with a post-processor to save some of that boilerplate.

This isn't the first time that a desire to post-process the JWTProcessor has come up, so I think this could potentially address more than one issue.

At that point, you could do:

NimbusJwtDecoder jwtDecoder = withPublicKey(key)
        .jwtProcessor(jwtProcessor -> jwtProcessor.setJWSTypeVerifier(...))
        .build();

Can you confirm that this would resolve your issue?

If so, would one of you be able to put together a PR to add a post-processor to each of the builders?

@jrehwaldt
Copy link
Contributor Author

jrehwaldt commented Jun 20, 2020

@jzheaux I had the same thought. There is a catch, though: JwtProcessor Does not implement the required methods. We‘d need to pass the DefaultJwtProcessor to the post-processor. If that’s okay I am happy to draft a PR.

On a side note why I did not propose it: I was concerned one could somehow break the security by misconfiguring Nimbus, making it a risky extension. On the other hand, it is for advanced usage and people should have an idea what that are doing anyway 🤷‍♂️

@jzheaux
Copy link
Contributor

jzheaux commented Jun 20, 2020

@jrehwaldt I think if you have it pass a ConfigurableJWTProcessor<SecurityContext>, then that will do the trick.

I was concerned one could somehow break the security by misconfiguring Nimbus, making it a risky extension

It certainly does give the user more power, but it's no more power than they already have with the NimbusJwtDecoder constructor (which takes a fully-configured JWTProcessor).

If that’s okay I am happy to draft a PR.

Sounds great, @jrehwaldt.

@jrehwaldt
Copy link
Contributor Author

@jzheaux I created a draft PR in #8745 for PublicKeyJwtDecoderBuilder only. If that's the way to go I'll go ahead and add the same functionality for the other two builders. Please leave a review and comment on naming preferences and Javadoc improvements you'd like to see.

@jzheaux jzheaux added this to the 5.4.0-M2 milestone Aug 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants