'Getting Invalid grant, malformed auth code while verifying token on server side

We are trying to use Google OAuth in our product. The flow would be to get Client get the auth from the users and send the token to server. On server side I need to verify the token is valid. For now, I am using OAuth2Sample provided by Google as client. when I verify the sent token on server side, I am getting the following exception:

com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request

{
"error" : "invalid_grant",
"error_description" : "Malformed auth code."
}

at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)

at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287) at com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest.execute(GoogleAuthorizationCodeTokenRequest.java:158)

Here is the code on the server side:

GoogleTokenResponse tokenResponse =
              new GoogleAuthorizationCodeTokenRequest(
                  new NetHttpTransport(),
                  JacksonFactory.getDefaultInstance(),
                  "https://www.googleapis.com/oauth2/v4/token",

                  CLIENT_ID,
                  CLIENT_SECRET,

                  authToken, //Sent from the client
                  "")  // specify an empty string if you do not have redirect URL
                  .execute();

Here is how I get the accesstoken on the client side:

private static final List<String> SCOPES = Arrays.asList(
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email");
//...

GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
        httpTransport, JSON_FACTORY, 
clientSecrets, //Client ID and Client Secret
SCOPES).setDataStoreFactory(
        dataStoreFactory).build();

LocalServerReceiver lsr = new LocalServerReceiver();
Credential cr = new AuthorizationCodeInstalledApp(flow, lsr).authorize("user");
return cr.getAccessToken(); //send this to server for verification

The token is not corrupted on the way to server and it is:

ya29.Glx_BUjV_zIiDzq0oYMqoXkxz8VGzt8GCQuBiaaJ3FxN0qaLxbBXvnWXjNKZbpeu4jraoEqw6Mj9D7LpTx_8Ts_8TH0VGT5cbrooGcAOF0wKMc1DDEjm6p5m-MvtFA

If I try to access profile and email from the client side, it works fine. Same token does not work on the server side gets malformed token exception.



Solution 1:[1]

I am using Node.js googleapis client library, Here is my case:

The authorization code in the url hash fragment is encoded by encodeURIComponent api, so if you pass this code to request access token. It will throw an error:

{ "error": "invalid_grant", "error_description": "Malformed auth code." }

So I use decodeURIComponent to decode the authorization code.

decodeURIComponent('4%2F_QCXwy-PG5Ub_JTiL7ULaCVb6K-Jsv45c7TPqPsG2-sCPYMTseEtqHWcU_ynqWQJB3Vuw5Ad1etoWqNPBaGvGHY')

After decode, the authorization code is:

"4/_QCXwy-PG5Ub_JTiL7ULaCVb6K-Jsv45c7TPqPsG2-sCPYMTseEtqHWcU_ynqWQJB3Vuw5Ad1etoWqNPBaGvGHY"

In Java, maybe you can use URLDecoder.decode handle the code.

Solution 2:[2]

Thanks to slideshowp2's answer, and Subhadeep Banerjee's comment.

I am using server-side web app with HTTP/REST ,also facing the same problem and yes, the reason is that authorization code return from URL is encoded.

After decode, everything work fine to get access token.

p.s. here is some info about encodedURL

since our Content-Type: application/x-www-form-urlencoded

Solution 3:[3]

For anyone who might face this in the future. I faced this issue and decodeURIComponent did not work with me. The previous answers work with for different issue.

From the question itself, you can see that the token starts with ya29.

ya29.Glx_BUjV_zIiDzq0oYMqoXkxz8VGzt8GCQuBiaaJ3FxN0qaLxbBXvnWXjNKZbpeu4jraoEqw6Mj9D7LpTx_8Ts_8TH0VGT5cbrooGcAOF0wKMc1DDEjm6p5m-MvtFA

That indicates that the token is an online token. In case of the online login, you can see that the response looks like this enter image description here

But that will not work with server side login. So, when using some Google client library, please note that there are two variables that you need to check:

  • access_type: offline
  • responseType: code

Once you configure Google client library with those fields, you can see that the response of the login will change to something like this

{
    "code": "4/0AX4XfWgaJJc3bsUYZugm5-Y5lPu3muSfUqCrpY5KZoGEGAHuw0jrkg_xkD_RX-6bNUq-vA"
}

Then you can send that code to the backend and it will work.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Omar Muhtaseb