3
votes

I am trying to authenticate my application to Google contacts API. I have gone though the first step in the Oauth2 flow and have an authorization code. I am trying to exchange this code for an access token and refresh token, but when i try to get Token from googleapis.com/oauth2/v4/token receive with

response : "invalid_grant" "Bad request" Error 400.

My code

try
        {
            Map<String,Object> params = new LinkedHashMap<>();
            params.put("grant_type","authorization_code");
            params.put("code", authCode);
            params.put("client_id",CLIENTE_ID);
            params.put("client_secret",CLIENTE_ID_SECRETO);
            params.put("redirect_uri","http://localhost:8080/conob/api2/contatos/insert");

            StringBuilder postData = new StringBuilder();
            for(Map.Entry<String,Object> param : params.entrySet())
            {
                if(postData.length() != 0){
                    postData.append('&');
                }

                postData.append(URLEncoder.encode(param.getKey(),"UTF-8"));
                postData.append('=');
                postData.append(URLEncoder.encode(String.valueOf(param.getValue()),"UTF-8"));
            }

            byte[] postDataBytes = postData.toString().getBytes("UTF-8");

            URL url = new URL("https://www.googleapis.com/oauth2/v4/token");
            HttpURLConnection con = (HttpURLConnection)url.openConnection();
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setUseCaches(false);
            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            con.setRequestProperty("charset", "utf-8");
            con.setRequestProperty("Content-Length", postData.toString().length() + "");
            con.getOutputStream().write(postDataBytes);


            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new InputStreamReader(con.getInputStream()));

                StringBuffer buffer = new StringBuffer();

                for (String line = reader.readLine(); line != null; line = reader.readLine()){
                    buffer.append(line);
                }

                JSONObject json = new JSONObject(buffer.toString());
                String accessToken = json.getString("access_token");

                return accessToken;
            } catch (Exception e) {
                reader = new BufferedReader(new InputStreamReader(con.getErrorStream()));

                StringBuffer buffer = new StringBuffer();

                for (String line = reader.readLine(); line != null; line = reader.readLine()){
                    buffer.append(line);
                }

                System.out.println(buffer.toString());
                System.out.println(e.toString());
            }

        }
        catch (Exception ex)
        {
            ex.printStackTrace(); 
        }
        return null;

Parameters output:

grant_type=authorization_code&code=AUTHORIZATION_CODE&client_id=CLIENTE_ID&client_secret=CLIENTE_SECRET&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fconob%2Fapi2%2Fcontatos%2Finsert

I'm searching for many hours in many forums but not conclude a solution for my problem.

Basically, my app needs to insert new contact on a google accounts in company intranet.

My question is what the response is "invalid_grant"?

Good code and thanks since now;

1
What the reponse is "Bad Request" in this case, sorry :/Nicolas Santos
Any reason you are not using the google api java client libraryDaImTo
@bogl the question and issue were quite clear to me. However since you where having issues understanding it I have edited his question. Is it more clear now?DaImTo
Welcome on stackoverflow, Nicolas! The question is much more readable now, thanks a lot!bogl

1 Answers

2
votes

In the OAuth2 spec, "invalid_grant" is sort of a catch-all for all error response related to invalid/expired/revoked tokens (auth grant or refresh token).

common causes

  1. User has actively revoked access to our app
  2. User has reset/recovered their Google password In December 2015, Google changed their default behavior so that password resets for non-Google Apps users would automatically revoke all the user's apps refresh tokens. This is not true for all apis contacts is not one of them but i thought i would note it anyway.

Apart from those, there's a myriad of other potential causes that could trigger the error:

  1. Server clock/time is out of sync
  2. Not authorized for offline access
  3. Throttled by Google
  4. Using expired refresh tokens
  5. using an expired authorization code.
  6. User has been inactive for 6 months
  7. Incorrect or invalid refresh token
  8. Use service worker email instead of client ID
  9. Too many access tokens in short time
  10. Client SDK might be outdated

Endpoint

I realize that the discovery document says googleapis.com/oauth2/v4/token but for some reason this end point does not always work try using accounts.google.com/o/oauth2/token

redirect_uri_mismatch

Means that the redirect uri you are sending with your request http://localhost:8080/conob/api2/contatos/insert is not one of the ones you have added in the Google developer console. You need to go back to the google developer console and add this redirect uri.

Note you may want to consider working with the google people api its a much easier api to work with then the old google contacts api.