0

I am currently developping a small web application with spring boot. I would like to use google oauth2 to login my user. All worked like a charm in localhost on my computer but when I deploy my app in GAE I get an error.

Here is the error stack I got from dev server on GAE. I guess the error is the same in production mode.

[INFO] 2017-08-27 17:02:31.290 DEBUG 630 --- [tp1134612201-18] g.c.AuthorizationCodeAccessTokenProvider : Retrieving token from https://www.googleapis.com/oauth2/v4/token
[INFO] 2017-08-27 17:02:31.565 DEBUG 630 --- [tp1134612201-18] o.s.web.client.RestTemplate              : Created POST request for "https://www.googleapis.com/oauth2/v4/token"
[INFO] 2017-08-27 17:02:31.566 DEBUG 630 --- [tp1134612201-18] g.c.AuthorizationCodeAccessTokenProvider : Encoding and sending form: {grant_type=[authorization_code], code=[4/PmvPPmFGQF0PamafaItFDiqKT_RwZN4RkdoydpxOTD4], redirect_uri=[https://127.0.0.1:8080/login], client_id=[XXX], client_secret=[YYY]}
[INFO] 2017-08-27 17:02:32.905 DEBUG 630 --- [tp1134612201-18] o.s.web.client.RestTemplate              : POST request for "https://www.googleapis.com/oauth2/v4/token" resulted in 400 (OK); invoking error handler
[INFO] 2017-08-27 17:02:33.343 DEBUG 630 --- [tp1134612201-18] o.s.b.f.s.DefaultListableBeanFactory     : Returning cached instance of singleton bean 'delegatingApplicationListener'
[INFO] 2017-08-27 17:02:33.381 DEBUG 630 --- [tp1134612201-18] uth2ClientAuthenticationProcessingFilter : Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Could not obtain access token
[INFO]
[INFO] org.springframework.security.authentication.BadCredentialsException: Could not obtain access token
[INFO]  at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:107)
[INFO]  at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
[INFO]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
[INFO]  at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
[INFO]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
[INFO]  at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:100)
[INFO]  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
[INFO]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
[INFO]  at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
[INFO]  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
[INFO]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
[INFO]  at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
[INFO]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
[INFO]  at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
[INFO]  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
[INFO]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
[INFO]  at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)
[INFO]  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)
[INFO]  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
[INFO]  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
[INFO]  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1759)
[INFO]  at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
[INFO]  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
[INFO]  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1759)
[INFO]  at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:60)
[INFO]  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1759)
[INFO]  at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
[INFO]  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
[INFO]  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1759)
[INFO]  at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
[INFO]  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
[INFO]  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1759)
[INFO]  at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
[INFO]  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
[INFO]  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1759)
[INFO]  at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:115)
[INFO]  at org.springframework.boot.web.support.ErrorPageFilter.access$000(ErrorPageFilter.java:59)
[INFO]  at org.springframework.boot.web.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:90)
[INFO]  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
[INFO]  at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:108)
[INFO]  at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1759)
[INFO]  at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:582)
[INFO]  at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
[INFO]  at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524)
[INFO]  at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226)
[INFO]  at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1180)
[INFO]  at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:512)
[INFO]  at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
[INFO]  at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1112)
[INFO]  at com.google.appengine.tools.development.jetty9.DevAppEngineWebAppContext.doScope(DevAppEngineWebAppContext.java:94)
[INFO]  at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
[INFO]  at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
[INFO]  at com.google.appengine.tools.development.jetty9.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:597)
[INFO]  at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
[INFO]  at org.eclipse.jetty.server.Server.handle(Server.java:534)
[INFO]  at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:320)
[INFO]  at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
[INFO]  at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:283)
[INFO]  at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:108)
[INFO]  at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93)
[INFO]  at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303)
[INFO]  at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148)
[INFO]  at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:136)
[INFO]  at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671)
[INFO]  at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589)
[INFO]  at java.lang.Thread.run(Thread.java:748)
[INFO] Caused by: org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException: Access token denied.
[INFO]  at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:142)
[INFO]  at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:209)
[INFO]  at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
[INFO]  at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
[INFO]  at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:105)
[INFO]  ... 65 common frames omitted
[INFO] Caused by: org.springframework.security.oauth2.common.exceptions.RedirectMismatchException: Bad Request
[INFO]  at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:103)
[INFO]  at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:33)
[INFO]  at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
[INFO]  at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2922)
[INFO]  at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:237)
[INFO]  at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readInternal(AbstractJackson2HttpMessageConverter.java:217)
[INFO]  at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:193)
[INFO]  at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport$AccessTokenErrorHandler.handleError(OAuth2AccessTokenSupport.java:235)
[INFO]  at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
[INFO]  at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
[INFO]  at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:621)
[INFO]  at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:137)
[INFO]  ... 69 common frames omitted

Here is my configuration :

application.yml :

security:
  oauth2:
    client:
      clientId: XXXXX
      clientSecret: XXXXX
      accessTokenUri: https://www.googleapis.com/oauth2/v4/token
      userAuthorizationUri: https://accounts.google.com/o/oauth2/v2/auth
      clientAuthenticationScheme: form
      scope:
        - openid
        - email
        - profile
    resource:
      userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo
      preferTokenInfo: true

Spring Security configuration :

@Configuration
@EnableOAuth2Sso
@EnableWebSecurity
class WebSecurityConfig : WebSecurityConfigurerAdapter() {
    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) {
        http
                .authorizeRequests()
                    .antMatchers("/", "/home", "/webjars/**", "/count", "/login")
                    .permitAll()
                .anyRequest()
                    .authenticated()
                .and()
                    .formLogin()
                    .loginPage("/login")
                    .permitAll()
                .and()
                    .logout()
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/")
                    .permitAll()
    }
}

MVC controller :

@Configuration
class MvcConfiguration : WebMvcConfigurerAdapter() {

    override fun addViewControllers(registry: ViewControllerRegistry?) {
        super.addViewControllers(registry)
        registry?.addViewController("/home")?.setViewName("home");
        registry?.addViewController("/")?.setViewName("home");
        registry?.addViewController("/hello")?.setViewName("hello");
    }

}

The redirection page I set in my google api console is : https://my-awesome-app.appspot.com/login. All worked when I was testing on http://localhost:8080. There is maybe something with ssl ?

By the way, I am using kotlin. But it is very similar to Java

Can anyone help me ?

Thomas Betous
  • 4,633
  • 2
  • 24
  • 45

1 Answers1

0

It's hard to find the right answer as the full stack trace is not printed out.

Looking at the stack trace, a few key errors state:

[INFO] org.springframework.security.authentication.BadCredentialsException: Could not obtain access token
...
[INFO] Caused by: org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException: Access token denied.

This indicates that the OAuth Client for your application is not properly authenticated or that the credentials you are using are not valid.

Rather than setting your own Access Token and User Auth URIs, I recommend using the Google Java API Client which will handle this for you:

https://github.com/googleapis/google-api-java-client

We have some G Suite samples that show OAuth flows here: https://github.com/gsuitedevs/java-samples

Perhaps this answer may be useful too: Get user info via Google API

Grant Timmerman
  • 414
  • 5
  • 9