I tried debugging the requests. It appears the reason why I get the following:
Code:
error="access_denied", error_description="Access token denied."
org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:93)
org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:161)
is because the other parameters required in retrieving an access token is never passed by Spring. Based on Google's OAuth 2.0 docs, the following parameters need to be passed (of course with the correct data):
Code:
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=8819981768.apps.googleusercontent.com&
client_secret={client_secret}&
redirect_uri=https://oauth2-login-demo.appspot.com/code&
grant_type=authorization_code
All I see from the debug results is a call https://accounts.google.com/o/oauth2/token, and hence an "Access token denied" is returned.
To test this observation, I fired up RESTClient (see http://rest-client.googlecode.com/) to simulate a post request to https://accounts.google.com/o/oauth2/token. And here's what I got:
Code:
{
"error" : "invalid_request"
}
It's interesting that this is the same error I got from my app:
Code:
error="invalid_request", error_description="invalid_request"
org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionDeserializer.deserialize(OAuth2ExceptionDeserializer.java:81)
org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionDeserializer.deserialize(OAuth2ExceptionDeserializer.java:30)
org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2391)
org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1651)
Just to verify it again, I opened up Google's OAuth 2.0 Playground (see https://code.google.com/oauthplayground) and tried modifying the authorization code:
Code:
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-length: 183
content-type: application/x-www-form-urlencoded
user-agent: google-oauth-playground
code=gfj&redirect_uri=https%3A%2F%2Fcode.google.com%2Foauthplayground&client_id=***************=&client_secret=************&grant_type=authorization_code
And the result:
Code:
HTTP/1.1 400 Ok
status: 400
content-length: 31
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
expires: Fri, 01 Jan 1990 00:00:00 GMT
x-google-cache-control: remote-fetch
server: GSE
via: HTTP/1.1 GWA
pragma: no-cache
cache-control: no-cache, no-store, max-age=0, must-revalidate
date: Sun, 10 Jun 2012 10:20:31 GMT
x-frame-options: SAMEORIGIN
content-type: application/json
-content-encoding: gzip
{
"error" : "invalid_grant"
}
So my conclusion here is that in the first place Spring OAuth is not sending the correct HTTP parameters because if it did it would show in the Debug details and it would throw an invalid_grant error instead (if the values are wrong).