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:
- The user is redirected to the server's login page.
- They log in.
- They immediately get authorization request from us
- I get back the server's auth code (pretty standard flow up to here)
- 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:
- The user is redirected to the server's login page.
- They log in.
- They immediately get authorization request from us
- I get back the server's auth code (pretty standard flow up to here)
- 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 |1 Answer
Reset to default 0I 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.
redirect-uri: "http://localhost:8080/login/oauth2/code/{registrationId}"
. And for provider.server, you should useissuer-uri
. Please note that the redirect-uri has to be registered in the auth-server. – Roar S. Commented Feb 15 at 18:45redirect-uri
is registered with the server (it otherwise complains). The callback path depends on theclient_authorization_method
and I useclient_credentials
which corresponds to the one above. The path you cite is associated withclient_secret_post
. Surprisingly, this is not well described in the documentation at all. Can you be more specific aboutissuer-uri
? What should be the value? – Mateva Commented Feb 15 at 23:18