Tom
Tom

Reputation: 61

GoogleMail: Refresh Access Token with OAuth 2.0

I have below method to get Google Mail credential. However Access Token is short lived and expire after 24 hours. How to refresh it?

My method:

 private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
        // Load client secrets.
        InputStream in = GoogleMail.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
        if (in == null) {
            throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
        }
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(GSON_FACTORY, new InputStreamReader(in));

        // Build flow and trigger user authorization request.
        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                HTTP_TRANSPORT, GSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline")
                .setApprovalPrompt("force")
                .build();
        LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
        return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
    }

I have seen a token refresh method but how can I combine it with my method (getCredentials)?

public Credential refreshAccessToken(String refreshToken, String clientId, String clientSecret) throws IOException {
try {
  TokenResponse response =
  new GoogleRefreshTokenRequest(new NetHttpTransport(), new JacksonFactory(),
      refreshToken, clientId, clientSecret).execute();
  System.out.println("Access token: " + response.getAccessToken());
  return buildEmpty().setAccessToken(response.getAccessToken());
} catch (TokenResponseException e) {
  if (e.getDetails() != null) {
    System.err.println("Error: " + e.getDetails().getError());
    if (e.getDetails().getErrorDescription() != null) {
      System.err.println(e.getDetails().getErrorDescription());
    }
    if (e.getDetails().getErrorUri() != null) {
      System.err.println(e.getDetails().getErrorUri());
    }
  } else {
    System.err.println(e.getMessage());
  }
}

Upvotes: 1

Views: 900

Answers (2)

Anders Lindgren
Anders Lindgren

Reputation: 388

According to the documentation of the Credential class you should do it like this when you create your Credentials:

public static Credential createCredentialWithRefreshToken(
    HttpTransport transport, 
    JsonFactory jsonFactory, 
    TokenResponse tokenResponse) {
    return new Credential.Builder(BearerToken.authorizationHeaderAccessMethod())
       .setTransport(transport)
       .setJsonFactory(jsonFactory)
       .setTokenServerUrl(new GenericUrl("https://server.example.com/token"))
       .setClientAuthentication(new BasicAuthentication("s6BhdRkqt3", "7Fjfp0ZBr1KtDRbnfVdmIw"))
       .build()
       .setFromTokenResponse(tokenResponse);
 }

Upvotes: 0

Linda Lawton - DaImTo
Linda Lawton - DaImTo

Reputation: 117321

Actually access tokens expire in an hour not 24 hours. You should not need to refresh the access token thats with the client library is designed to do for you.

if you follow Java quickstart

Notice how it uses something called TOKENS_DIRECTORY_PATH. When the user authorizes the application for the first time they will be asked to consent to your applications access. If the user grants your application access then an access token and refresh token will be returned to your application and stored as a file in this TOKENS_DIRECTORY_PATH.

// Build flow and trigger user authorization request.
    GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
            HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
            .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
            .setAccessType("offline")
            .build();

A little further down in the example you will find this line

return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");

This tells the client library to authorize the application on behalf of a user named "user". What the library then does is looks in TOKENS_DIRECTORY_PATH for a file with a name that contains "user" if it does not exist then the consent screen is popped up and the access is requested. If it does exist then the library will read the refresh token from within the file and refresh the access token for you.

If your code is configured properly you should not be worrying about refreshing the access token the client library will handle all that for you.

Upvotes: 1

Related Questions