spring-security: adding query parameter to authorization_uri creates malformed url
Summary
When creating the authorization uri to login with google, there is the option to add a query parameter in order to get back the refresh token. However, when the authorization_uri is set to:
https://accounts.google.com/o/oauth2/v2/auth?access_type=offline
The uri that I get redirect to is:
https://accounts.google.com/o/oauth2/v2/auth?access_type=offline?response_type=code&client_id=[my client id]&scope=[scopes]&state=[state]&redirect_uri=[redirect uri]
Note the ?access_type=offlince?response_type… This url is malformed and google complains saying response_type and basic query params are not passed in.
Actual Behavior
- User goes to /login
- User sees an error from Google due to malformed URL
Expected Behavior
- User goes to /login
- User sees the google login page and the following URL in the address bar:
https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&response_type=code&client_id=[my client id]&scope=[scopes]&state=[state]&redirect_uri=[redirect uri]The access_type query parameter is after the ? and following query parameters should have an & between them. The order of the query params does not matter.
Configuration
My application.yaml
spring:
security:
oauth2:
client:
registration:
google:
client-id: xxxxx
client-secret: yyyyy
scope: profile,email,https://www.googleapis.com/auth/analytics
provider:
google:
authorization-uri: https://accounts.google.com/o/oauth2/v2/auth?access_type=offline
My WebSecurityConfigurationAdapter
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
//.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.failureUrl("/loginFailure")
.authorizationEndpoint()
.authorizationRequestRepository(authorizationRequestRepository())
.and()
.tokenEndpoint().accessTokenResponseClient(accessTokenResponseClient());
}
@Bean
public AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository() {
HttpSessionOAuth2AuthorizationRequestRepository request = new HttpSessionOAuth2AuthorizationRequestRepository();
return request;
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient() {
return new NimbusAuthorizationCodeTokenResponseClient();
}
}
My pom.xml (only including security and oauth2 dependencies)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.1.0.M2</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
<version>5.1.0.RC1</version>
</dependency>
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 6
- Comments: 33 (9 by maintainers)
Commits related to this issue
- Fixes gh-5760 - Check for query parameters in the authorization uri and pass them as additional parameters to the Oauth2Authorization request builder — committed to mlevkovsky/spring-security by mlevkovsky 6 years ago
- Fixes gh-5760 - fix static import — committed to mlevkovsky/spring-security by mlevkovsky 6 years ago
- Fixes gh-5760 - removes hard coded url parsing and fetches the query string from the request — committed to mlevkovsky/spring-security by mlevkovsky 6 years ago
- Fixes gh-5760 - remove non needed unit test — committed to mlevkovsky/spring-security by mlevkovsky 6 years ago
- Revert "Fixes gh-5760" This reverts commit 43ca84f — committed to mlevkovsky/spring-security by mlevkovsky 6 years ago
- authorization_uri Uses UriComponentsBuilder Because of this, authorization_uri can now be a fully-qualified url. Fixes: gh-5760 — committed to jzheaux/spring-security by jzheaux 6 years ago
- authorization_uri Uses UriComponentsBuilder Because of this, authorization_uri can now be a fully-qualified url. Fixes: gh-5760 — committed to spring-projects/spring-security by jzheaux 6 years ago
- authorization_uri Uses UriComponentsBuilder Because of this, authorization_uri can now be a fully-qualified url. Fixes: gh-5760 — committed to spring-projects/spring-security by jzheaux 6 years ago
@jgrandja I have the same issue and was about to post something similar, so I’m pleased I found this issue first. I’ll take a look at using a
OAuth2AuthorizatioNRequestResolver@jgrandja
Thanks for your guidance and quick response! That was definitely the problem. I am still getting familiar with how Kotlin handles or does not handle nulls. Basically I needed to add a bunch of
?and a!!in some of my type declarations and statements to get my IDE to stop bugging me about returning nulls.For anyone who’s interested in doing the same in Kotlin, this is what my resolver ended up looking like:
@jgrandja
Just as a follow up, I if I run in the Intellij IDEA debugger, I catch a breakpoint in this function multiple times, but it never seems to run into the return statement that does the customization – which doesn’t really make any sense to me…
Called multiple times:
Never catches breakpoint:
private fun customAuthorizationRequest(authorizationRequest: OAuth2AuthorizationRequest): OAuth2AuthorizationRequestUPDATE: It appears that
OAuth2AuthorizationRequestRedirectFilteris catching an exception in itsdoFilterInternalmethod and callingthis.unsuccessfulRedirectForAuthorization(request, response, failed)This appears to be the root cause of why my customization function is never called. Part of the issue seems to be that the
registrationIdisnull, but I’m not exactly clear on what’s going on.How do I ensure the proper
resolvemethod gets called so thatregistrationIdis notnull?resolve(request: HttpServletRequest?, clientRegistrationId: String?)instead of:
resolve(request: HttpServletRequest?)Just a reminder that using
access_type=offlinewill only return a refresh_token on first access, usually when you give consent. Therefore you need to persist the refresh_token somewhere.Alternatively you can add query parameter
prompt=consentto return a refresh_token every time, but this requires the user to consent every time, which I think is annoying from a user perspective !@matthewbluezyoncom thank you very much! It worked for me. Now I get it and I will fix my PR accordingly
I got this working so I could add access_type=offline to get a refresh token.
See my code below, from the overidden
configuremethod of myWebSecurityConfigurerAdapterconfiguration class its a bit rough around the edges but it works.I decided it was safest to create a new redirect filter based on the default filter and append the extra request parameter on the end of the authorization request uri.
NOTE: Since we are releasing 5.1.0.RC2 on Friday and you won’t get to it until this weekend I pushed this back to 5.1.0
@rwinch absolutely 😃 will try to get it done over the weekend 👍