spring-projects / spring-authorization-server

Spring Authorization Server
https://spring.io/projects/spring-authorization-server
Apache License 2.0
4.82k stars 1.27k forks source link

How-to: Override default algorithm used to sign Jwt #1030

Open sapradhan opened 1 year ago

sapradhan commented 1 year ago

Expected Behavior One should be able to choose Signature Algorithm used to sign access tokens.

Current Behavior No configuration parameter exists in TokenSettings to choose signature algo for access token. It is hard coded as RS256 while generating Jwt.

https://github.com/spring-projects/spring-authorization-server/blob/aed93f38acabaeade63b03b8bc5305f9807ef20a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/JwtGenerator.java#L93-L102

Context Because of this, cannot choose another algorithm like HSxxx or EDxxx for access tokens. TokenSettings does allow to configuring signing algo for Id Token using idTokenSignatureAlgorithm(SignatureAlgorithm idTokenSignatureAlgorithm) method in the Builder.

jgrandja commented 1 year ago

@sapradhan

One should be able to choose Signature Algorithm used to sign access tokens.

Not all access tokens are signed. This only applies to OAuth2TokenFormat.SELF_CONTAINED access tokens, e.g. Jwt.

However, some clients may be configured for opaque tokens (OAuth2TokenFormat.REFERENCE), and therefore the proposed TokenSettings.accessTokenSignatureAlgorithm would be redundant. Furthermore, there are no specifications that define a default algorithm for access tokens so I'm reluctant on adding this enhancement since there is no standard defined.

Because of this, cannot choose another algorithm like HSxxx or EDxxx for access tokens.

You can override the default algorithm by configuring an OAuth2TokenCustomizer @Bean:

@Bean
OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
    return context -> {
        if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) {
            context.getJwsHeader().algorithm(MacAlgorithm.HS512);
        }
    };
}

This should work for your configuration.

sapradhan commented 1 year ago

@jgrandja Thank you for the explanation, with that I am in agreement with your view on not having JWT specific setting on access token settings in general.

I also tried out your suggestion and it works for my use case. However this was not obvious to me, as a specific algorithm setting is exists for idToken. Should we have a how-to for this use case somewhere? (please let me know if one exists already)

jgrandja commented 1 year ago

@sapradhan

Should we have a how-to for this use case somewhere?

Yes, this question will come up again so we'll document it in the reference. I changed the subject of the issue.

I'll close the associated PR and we'll address this soon in the reference manual.

TelmaCorreia commented 7 months ago

👋 @jgrandja I also want to use ES256 but the solution proposed above is not working for me. I did some debugging and I noticed that RS256 is also hardcoded here and then jwt encoding is always using RS256.

Am I missing something?

sapradhan commented 7 months ago

@TelmaCorreia if you follow the discussion above, this is by design. Access token does not have to be a JWT and thus it does not make sense to put a JWT signing algorithm in access token setting. Did you try setting up a token customizer and change algorithm to your preference -

@Bean
OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer() {
    return context -> {
        if (OAuth2TokenType.ACCESS_TOKEN.equals(context.getTokenType())) {
            context.getJwsHeader().algorithm(SignatureAlgorithm.ES256);
        }
    };
}

You may also have to setup a EC256 compatible JWKSource

chenzhenjia commented 1 month ago

Clear the default idToken algorithm and add all algorithms supported by jwk

new OAuth2AuthorizationServerConfigurer().oidc(oidc -> {
        oidc.providerConfigurationEndpoint(providerConfigurationEndpoint -> {
          List<String> jwkAlgs = applicationContext.getBeanProvider(JWK.class).orderedStream()
              .map(JWK::getAlgorithm).map(Algorithm::getName).toList();
          providerConfigurationEndpoint.providerConfigurationCustomizer(builder -> {
            builder.idTokenSigningAlgorithms(algs -> {
              algs.clear();
              algs.addAll(jwkAlgs);
            });
          });
        });
      })