2

I am using GAE for java and trying to read files from google drive using apis. I used the standard implementation from DrEdit. I have a servlet which authenticate with my account and store the credentials using the following snippet:

 protected void handleCallbackIfRequired(HttpServletRequest req,
      HttpServletResponse resp) throws IOException {
    String code = req.getParameter("code");
System.out.println("Code:" + code);

if (code != null) {
  // retrieve new credentials with code
  Credential credential = credentialManager.retrieve(code);

credentialManager.save(id, credential);
System.out.println("access token:" + credential.getAccessToken());
System.out.println("refresh token:" + credential.getRefreshToken());
  resp.sendRedirect("/");
}

}

  public Credential retrieve(String code) {
    System.out.println("Passed code to retrieve is:" + code);
      try {
      GoogleTokenResponse response = new GoogleAuthorizationCodeTokenRequest(
          transport,
          jsonFactory,
          clientSecrets.getWeb().getClientId(),
          clientSecrets.getWeb().getClientSecret(),
          code,
          clientSecrets.getWeb().getRedirectUris().get(0)).execute();

      Credential cred = buildEmpty();
      cred.setRefreshToken(response.getRefreshToken());
      cred.setAccessToken(response.getAccessToken());
      return cred;

    } catch (IOException e) {
      new RuntimeException("An unknown problem occured while retrieving token");
    }
    return null;
  }
}

Code for saving the accessToken & refreshToken:

protected void handleCallbackIfRequired(HttpServletRequest req,
      HttpServletResponse resp) throws IOException {
    String code = req.getParameter("code");
    System.out.println("Code:" + code);

    if (code != null) {
      // retrieve new credentials with code
      Credential credential = credentialManager.retrieve(code);

    credentialManager.save(id, credential);
    System.out.println("access token:" + credential.getAccessToken());
    System.out.println("refresh token:" + credential.getRefreshToken());
      resp.sendRedirect("/");
    }
  }

After this I am expecting the GAE to retrieve my credentials automatically each time and let me call the drive apis. However, I am seeing below message in my logs. So, I am not sure why that is happening. Please note that the authorization url i created includes offline scope.

  "code" : 401,
    "errors" : [ {
    "domain" : "global",
    "location" : "Authorization",
    "locationType" : "header",
    "message" : "Invalid Credentials",
    "reason" : "authError"
    } ],
    "message" : "Invalid Credentials"
    }

Logs after forcing a fresh reauthentication:

2013-09-08 22:51:28.512
[s~sakshumweb-hrd/3.370083570818804963].<stdout>: Code:4/jYpKc6Mit2_0OTgR7dhpve0YGQCG.UoLMhsf6Fd4SEnp6UAPFm0GoUpACggI

I 2013-09-08 22:51:28.512
[s~sakshumweb-hrd/3.370083570818804963].<stdout>: Passed code to retrieve is:4/jYpKc6Mit2_0OTgR7dhpve0YGQCG.UoLMhsf6Fd4SEnp6UAPFm0GoUpACggI

I 2013-09-08 22:51:29.423
[s~sakshumweb-hrd/3.370083570818804963].<stdout>: access token:ya29.AHES6ZS3x8fPpq5G9YHmIvFHE098izZ0zyn7BCnZRDhYf3zdA-qNDtw

I 2013-09-08 22:51:29.424
[s~sakshumweb-hrd/3.370083570818804963].<stdout>: refresh token:null

I 2013-09-08 22:51:29.450
[s~sakshumweb-hrd/3.370083570818804963].<stdout>: authorization url:https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=auto&client_id=955443778501.apps.googleusercontent.com&redirect_uri=http://www.sakshum.org/GoogleOauth&response_type=code&scope=https://www.googleapis.com/auth/drive.readonly%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile
Vik
  • 8,721
  • 27
  • 83
  • 168
  • 2
    401 means the access token is invalid. You should check your code to see you are correctly obtaining and, where necessary, refreshing the access token. – pinoyyid Sep 07 '13 at 06:21
  • Thanks! for me refresh token comes null all the time. The code I am using is added above. – Vik Sep 08 '13 at 23:00
  • The refresh token is only provided once. Subsequently it will be null. You might need to "force" re authorisation. – pinoyyid Sep 09 '13 at 02:41
  • I just forced and still see the refreshToken as null. I added the log in to the original question – Vik Sep 09 '13 at 05:53
  • 1
    That log says approval prompt= auto. Try setting it to force – pinoyyid Sep 09 '13 at 09:25
  • Also, I can't see anywhere in your code where you save the refresh token – pinoyyid Sep 09 '13 at 09:30
  • Thanks changing to force generated the refreshToken. I have updated the code where I am saving it to the store. Please advise what else has to be done to let my GAE code keep using drive api without expiration and using the same accessToken and refreshToken. – Vik Sep 09 '13 at 19:57

3 Answers3

1

"without expiration and using the same accessToken"???? Really? Have you read https://developers.google.com/accounts/docs/OAuth2WebServer ?

pinoyyid
  • 21,499
  • 14
  • 64
  • 115
  • 1
    Sorry I have read it and it says it will generate the accessToken using the refreshToken. I could not find the code which will do that. Can u point me to specifically that code which will take care of it on google app engine for java? – Vik Sep 10 '13 at 06:47
  • 1
    I can't point you to where your code does it. There is an example in the answer to this question http://stackoverflow.com/questions/18585279/headless-obtain-token-with-gtmoauth2signin/18587677#18587677 – pinoyyid Sep 10 '13 at 07:42
0

If you have Google two-stage verification on, then it doesn't matter what your Google password is, it won't be accepted. You need to generate (on Google) what is called an Application Specific Password (ASP). Go to https://www.google.com/settings/account and set up an ASP, enter the password you generate as the password in your code, and you're done.

0

Try to replace in the retrieve(String code) method, instead of:

Credential cred = buildEmpty();
cred.setRefreshToken(response.getRefreshToken());
cred.setAccessToken(response.getAccessToken());
return cred;

replace with:

Credential cred = buildEmpty();
cred.setFromTokenResponse(response);
return cred;
Aerox
  • 669
  • 1
  • 13
  • 28