最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Spring Boot 3.X, Spring security 6 and Oauth 2 - client authorization - auth code not processed - Stack Overflow

programmeradmin2浏览0评论

I've been trying to use Spring Boot 3.3.3 with Spring security 6.4.2 to get authorization from a user in a third party server (not Google, Github, etc.), declared server below, and to get some developer's data that the user granted permissions for.

My flow is the following:

  1. The user is redirected to the server's login page.
  2. They log in.
  3. They immediately get authorization request from us
  4. I get back the server's auth code (pretty standard flow up to here)
  5. I need an access and refresh tokens to get data that I was authorized to. Note that from this point I don't need the user to be logged in anymore.

From Spring terminology, I assume this workflow falls in the case of Authorized Client

I expect to have to rewrite some logic, however, Spring fails after point 4 to get an access token from the server. I successfully did so by Postman, once I got the auth code, however my client didn't succeed to do it, and I expect this should be standard OAuth2 framework operation.

application.yml :

   spring:
      application:
        name: glorious-name
      security:
        oauth2:
          client:
            registration:
              cool-client:
                provider:                     server
                client-id:                    cool-client-s-app-id
                client-secret:                cool-client-s-app-secret
                authorization-grant-type:     authorization_code
                redirect-uri:                 http://localhost:8080/oauth2/authorization/cool-client
                client-authentication-method: client_credentials
                scope:                        scopes_that_matter
                state:                        true
            provider:
              server:
                authorization-uri:            
                token-uri:                    

Execution result - note that the auth code arrives to /oauth2/authorization/cool-client but it does not get redirected to the token endpoint as it should. My Controller doesn't get hit at all, or at least no logs about it. Is there a hidden error?

417+02:00 DEBUG 232660 --- [glorious-name] [nio-8581-exec-1] [hash1] o.s.s.web.DefaultRedirectStrategy        : Redirecting to http://localhost:8080/oauth2/authorization/cool-client
424+02:00 DEBUG 232660 --- [glorious-name] [nio-8581-exec-2] [hash2] o.s.security.web.FilterChainProxy        : Securing GET /oauth2/authorization/cool-client
431+02:00 DEBUG 232660 --- [glorious-name] [nio-8581-exec-2] [hash2] o.s.s.web.DefaultRedirectStrategy        : Redirecting to ;client_id=cool-client-id&scope=encoded_scopes&state=...D&redirect_uri=http://localhost:8080/oauth2/authorization/cool-client
540+02:00 DEBUG 232660 --- [glorious-name] [nio-8581-exec-3] [hash3] o.s.security.web.FilterChainProxy        : Securing GET /oauth2/authorization/cool-client?code=...&scope=encoded_scopes&state=...
544+02:00 DEBUG 232660 --- [glorious-name] [nio-8581-exec-3] [hash3] o.s.s.web.DefaultRedirectStrategy        : Redirecting to ;client_id=cool_client_id&scope=encoded_scopes&state=...&redirect_uri=http://localhost:8080/oauth2/authorization/cool-client

Here is my debug controller, I have tried all variants from the documentation.

    @GetMapping("/oauth2/authorization/cool-client")
// public ResponseEntity<String> exchangeCodeForToken(@RequestParam(name = "code") String code, @RequestParam(name = "state") String state, @RequestParam(name = "scope") String scope) {
// public ResponseEntity<String> exchangeCodeForToken(@RegisteredOAuth2AuthorizedClient("cool-client") OAuth2AuthorizedClient authorizedClient) {
public ResponseEntity<String> exchangeCodeForToken(@AuthenticationPrincipal OAuth2User user) {

    // log.info("!!!!! SUCCESS !!!!!" + authorizedClient.getClientRegistration().getRegistrationId());
    log.info("USER " + user.getAttributes());
    // log.info("!!!!! THE CODE!!!!! from authorization/lh"  + code);

    return ResponseEntity.ok("Successfully reading the auth code");
}

And SecurityConfig.java (of course I tried customizations, but the problem remains):

@Slf4j
@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
            .authorizeHttpRequests(authorize -> authorize
                    .requestMatchers("/", "/error", "/login/**", "/oauth2/**").permitAll()
                    .anyRequest().authenticated()
            )
            .oauth2Login(oauth -> oauth
                    .failureUrl("/oauth2/error")
            )
            .oauth2Client(Customizer.withDefaults());

    return http.build();
}

}

I started writing the call for the access token myself, however, this feels wrong. What modification/configuration do I need to modify, in order to get the right authentication pattern?

Or can someone confirm that in my case I need to rewrite the logic of getting the access token myself? Any fancy debug/tracing hints? ( I already use TRACE logging level, Postman and the browser's webtools`)

I've been trying to use Spring Boot 3.3.3 with Spring security 6.4.2 to get authorization from a user in a third party server (not Google, Github, etc.), declared server below, and to get some developer's data that the user granted permissions for.

My flow is the following:

  1. The user is redirected to the server's login page.
  2. They log in.
  3. They immediately get authorization request from us
  4. I get back the server's auth code (pretty standard flow up to here)
  5. I need an access and refresh tokens to get data that I was authorized to. Note that from this point I don't need the user to be logged in anymore.

From Spring terminology, I assume this workflow falls in the case of Authorized Client

I expect to have to rewrite some logic, however, Spring fails after point 4 to get an access token from the server. I successfully did so by Postman, once I got the auth code, however my client didn't succeed to do it, and I expect this should be standard OAuth2 framework operation.

application.yml :

   spring:
      application:
        name: glorious-name
      security:
        oauth2:
          client:
            registration:
              cool-client:
                provider:                     server
                client-id:                    cool-client-s-app-id
                client-secret:                cool-client-s-app-secret
                authorization-grant-type:     authorization_code
                redirect-uri:                 http://localhost:8080/oauth2/authorization/cool-client
                client-authentication-method: client_credentials
                scope:                        scopes_that_matter
                state:                        true
            provider:
              server:
                authorization-uri:            https://server/oauth/oauth2/auth
                token-uri:                    https://server/oauth/oauth2/token

Execution result - note that the auth code arrives to /oauth2/authorization/cool-client but it does not get redirected to the token endpoint as it should. My Controller doesn't get hit at all, or at least no logs about it. Is there a hidden error?

417+02:00 DEBUG 232660 --- [glorious-name] [nio-8581-exec-1] [hash1] o.s.s.web.DefaultRedirectStrategy        : Redirecting to http://localhost:8080/oauth2/authorization/cool-client
424+02:00 DEBUG 232660 --- [glorious-name] [nio-8581-exec-2] [hash2] o.s.security.web.FilterChainProxy        : Securing GET /oauth2/authorization/cool-client
431+02:00 DEBUG 232660 --- [glorious-name] [nio-8581-exec-2] [hash2] o.s.s.web.DefaultRedirectStrategy        : Redirecting to https://server/oauth/oauth2/auth?response_type=code&client_id=cool-client-id&scope=encoded_scopes&state=...D&redirect_uri=http://localhost:8080/oauth2/authorization/cool-client
540+02:00 DEBUG 232660 --- [glorious-name] [nio-8581-exec-3] [hash3] o.s.security.web.FilterChainProxy        : Securing GET /oauth2/authorization/cool-client?code=...&scope=encoded_scopes&state=...
544+02:00 DEBUG 232660 --- [glorious-name] [nio-8581-exec-3] [hash3] o.s.s.web.DefaultRedirectStrategy        : Redirecting to https://server/oauth/oauth2/auth?response_type=code&client_id=cool_client_id&scope=encoded_scopes&state=...&redirect_uri=http://localhost:8080/oauth2/authorization/cool-client

Here is my debug controller, I have tried all variants from the documentation.

    @GetMapping("/oauth2/authorization/cool-client")
// public ResponseEntity<String> exchangeCodeForToken(@RequestParam(name = "code") String code, @RequestParam(name = "state") String state, @RequestParam(name = "scope") String scope) {
// public ResponseEntity<String> exchangeCodeForToken(@RegisteredOAuth2AuthorizedClient("cool-client") OAuth2AuthorizedClient authorizedClient) {
public ResponseEntity<String> exchangeCodeForToken(@AuthenticationPrincipal OAuth2User user) {

    // log.info("!!!!! SUCCESS !!!!!" + authorizedClient.getClientRegistration().getRegistrationId());
    log.info("USER " + user.getAttributes());
    // log.info("!!!!! THE CODE!!!!! from authorization/lh"  + code);

    return ResponseEntity.ok("Successfully reading the auth code");
}

And SecurityConfig.java (of course I tried customizations, but the problem remains):

@Slf4j
@Configuration
@EnableWebSecurity
public class SecurityConfig {

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
            .authorizeHttpRequests(authorize -> authorize
                    .requestMatchers("/", "/error", "/login/**", "/oauth2/**").permitAll()
                    .anyRequest().authenticated()
            )
            .oauth2Login(oauth -> oauth
                    .failureUrl("/oauth2/error")
            )
            .oauth2Client(Customizer.withDefaults());

    return http.build();
}

}

I started writing the call for the access token myself, however, this feels wrong. What modification/configuration do I need to modify, in order to get the right authentication pattern?

Or can someone confirm that in my case I need to rewrite the logic of getting the access token myself? Any fancy debug/tracing hints? ( I already use TRACE logging level, Postman and the browser's webtools`)

Share Improve this question edited Feb 17 at 22:17 dur 17k26 gold badges88 silver badges143 bronze badges asked Feb 15 at 17:46 MatevaMateva 8121 gold badge9 silver badges29 bronze badges 2
  • Please try redirect-uri: "http://localhost:8080/login/oauth2/code/{registrationId}". And for provider.server, you should use issuer-uri. Please note that the redirect-uri has to be registered in the auth-server. – Roar S. Commented Feb 15 at 18:45
  • Thanks @RoarS. , redirect-uri is registered with the server (it otherwise complains). The callback path depends on the client_authorization_method and I use client_credentials which corresponds to the one above. The path you cite is associated with client_secret_post. Surprisingly, this is not well described in the documentation at all. Can you be more specific about issuer-uri? What should be the value? – Mateva Commented Feb 15 at 23:18
Add a comment  | 

1 Answer 1

Reset to default 0

I finally succeeded to produce the needed configuration.

First, I did not need to override the controller's /login/authorization/code/{registrationId} endpoint.

Next, I had to make slight changes to the application.yml:

spring:
      application:
        name: glorious-name
      security:
        oauth2:
          client:
            registration:
              cool-client:
                provider:                     server
                client-id:                    cool-client-s-app-id
                client-secret:                cool-client-s-app-secret
                authorization-grant-type:     authorization_code
                redirect-uri:                 http://localhost:8080/login/oauth2/code/cool-client
                client-authentication-method: client_secret_post
                scope:                        scopes_that_matter
                state:                        true
            provider:
              server:
                authorization-uri:            https://server/oauth/oauth2/auth
                token-uri:                    https://server/oauth/oauth2/token
                user-info-uri:                https://server/user/uri/that/I/had/to/figure/out/on/my/own
                user-name-attribute:          user_id_attribute_name

Third, it was useful to implement a login success page, so that I know when I'm finally there.

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
            .authorizeHttpRequests(authorize -> authorize
                    .requestMatchers( "/error", "/login/**", "/oauth2/**").permitAll()
                    .anyRequest().authenticated()
            )
            .oauth2Login(oauth -> oauth
                    .defaultSuccessUrl("/user/profile")
            )
            .oauth2Client(Customizer.withDefaults());

    return http.build();
}

On the /user/profile/ endpoint I added an authorized call to the API that looked like this.

@GetMapping("/user/profile")
public ResponseEntity<String> getUserProfile() {

    String resourceUri = <user_profile_uri>;
    ResponseEntity<Object> body = this.restClient.get()
            .uri(resourceUri)
            .header("Content-Type", MediaType.APPLICATION_JSON_VALUE)
            .retrieve()
            .toEntity(Object.class);

    return ResponseEntity.ok(body.toString());
}

I hope this is useful to someone, it costed me a lot of headache to fix.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论