spring-projects / spring-authorization-server

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

The Oauth server return `invalid_client` with valid token request #141

Closed daniDevKr closed 3 years ago

daniDevKr commented 3 years ago

Describe the bug The Oauth server return invalid_client with valid token request.

To Reproduce

  1. I navigate with the browser to the /oauth2/authorize endpoint;
  2. After the login process, the server get me the authorization code;
  3. I use the authorization code to obtain the token for the next requests:
POST /oauth2/token HTTP/1.1
     Host: localhost:9000
     Content-Type: application/x-www-form-urlencoded

     grant_type=authorization_code&code=<my code>
     &redirect_uri=<my redirect uri>&client_id=<my client id>
  1. The server response is:

    {"error":"invalid_client"}

Expected behavior

 HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }

My oauth server configuration file:

@EnableWebSecurity
@Import(OAuth2AuthorizationServerConfiguration.class)
public class AuthorizationServerConfig {

    // @formatter:off
    @Bean
    public RegisteredClientRepository registeredClientRepository() {

        Consumer<Set<String>> c = (s) -> s.addAll(Set.of("http://localhost:4200", "http://localhost:8080/authorized"));

        RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("messaging-client")
                .clientSecret("secret")
                .clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)

                .redirectUris(c)
                .scope("message.read")
                .scope("message.write")
              .clientSettings(clientSettings -> clientSettings.requireUserConsent(true))
                .build();
        return new InMemoryRegisteredClientRepository(registeredClient);
    }
    // @formatter:on

    @Bean
    public KeyManager keyManager() {
        return new StaticKeyGeneratingKeyManager();
    }

    // @formatter:off
    @Bean
    public UserDetailsService users() {
        UserDetails user = User.withDefaultPasswordEncoder()
                .username("user1")
                .password("password")
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(user);
    }
    // @formatter:on
}
daniDevKr commented 3 years ago

I have put the header Authorization: Basic <encoded client credentials> in the request.

daniDevKr commented 3 years ago

Now, the server get me the access token but in the response there isn't the refresh token.

Server response:

{
"access_token": "<the token>",
"expires_in": "3599"
"scope": "message.read message.write"
"token_type": "Bearer"
}

How can I enable it ?

jgrandja commented 3 years ago

@jhonToni Refresh token support will be merged soon. See #128

MossounAndre commented 1 year ago

I have the same problem despite adding the Authorization Basic header

@Configuration(proxyBeanMethods = false) public class AuthorizationServerConfig { private final KeyManager keyManager;

public AuthorizationServerConfig(KeyManager keyManager) {
    this.keyManager = keyManager;
}

@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
    http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
            .oidc(Customizer.withDefaults());   // Enable OpenID Connect 1.0
    http
            // Redirect to the login page when not authenticated from the
            // authorization endpoint
            .exceptionHandling((exceptions) -> exceptions
                    .defaultAuthenticationEntryPointFor(
                            new LoginUrlAuthenticationEntryPoint("/login"),
                            new MediaTypeRequestMatcher(MediaType.TEXT_HTML)
                    )
            )
            // Accept access tokens for User Info and/or Client Registration
            .oauth2ResourceServer((resourceServer) -> resourceServer
                    .jwt(Customizer.withDefaults()));

    return http.build();
}

@Bean
public RegisteredClientRepository registeredClientRepository() {
    RegisteredClient clientRepository = RegisteredClient.withId(UUID.randomUUID().toString())
            .clientId("orbis-station-client")
            .clientName("Orbis Mandataire")
            .clientSecret("{noop}secret")
            .clientAuthenticationMethod(ClientAuthenticationMethod.NONE)
            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
            .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
            .scope(OidcScopes.EMAIL)
            .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
            .redirectUri("https://127.0.0.1:8000/dashboard")
            .build();

    return new InMemoryRegisteredClientRepository(clientRepository);
}

@Bean
public AuthorizationServerSettings authorizationServerSettings() {
    return AuthorizationServerSettings.builder()
            .issuer("https://account.orbis-identity.com:8080")

            .build();
}

@Bean
public JWKSource<SecurityContext> jwkSource() {
    KeyPair keyPair = keyManager.rsaKey();
    RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
    RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
    RSAKey rsaKey = new RSAKey.Builder(publicKey)
            .privateKey(privateKey)
            .keyID(UUID.randomUUID().toString())
            .build();
    JWKSet jwkSet = new JWKSet(rsaKey);
    return new ImmutableJWKSet<>(jwkSet);
}

@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
    return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}

}