Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OAuth 2.0 Access Tokens and Refresh Tokens

I have difficult in understanding the proper usage of refresh and access tokens. I know that refresh tokens are related to authorization and access tokens are related to authentication.I would like to explain my use case better so that someone could help me out here. I have a Multi Account Center in Google Merchant Center. I would like to integrate the latest OAuth 2.0 authentication mechanism in my code. I did and could authenticate successfully. I use Google Credential mechanism of building a credential object and inject in using the httprequestinitializer mechanism during httprequest to google. When the google credential object is created , I see that there is no access tokens when I do a googleCredential.getAccessToken(), but then when I do a googleCredential.refreshToken() and then a googleCredential.getAccessToken() , I get an accessToken. However, I was testing how the tokens are created and I am not explicitly passing these tokens in the request to google. All I pass is just the googleCredential object with client secrets and other private keys. The task I am doing is just uploading the sub account product feeds to google via cron script.

My questions are,

  1. Do I have to take care of the refreshing tokens here while passing the googleCredential object here ? (Assume script runs for a more than a day)
  2. When should one use refresh tokens and access tokens, what would a proper choice for me in above use case? (Though for now I am not passing anything explicitly other than googleCredential Object)
  3. What is the validity time for a access token and refresh token(not related to above use case, just to know, some say 14 days for refresh tokens, some say indefinite till user revokes access , etc)

I would be great full if someone clarifies me and pulls me out. I know this platform is to clarify issues majorly on code but I google forum isn't helping either. So posting here.

Sorry for being very verbose.

Thanks in advance.

like image 508
thirstyladagain Avatar asked Feb 02 '15 07:02

thirstyladagain


People also ask

What is refresh token and access token in OAuth2?

An OAuth Refresh Token is a string that the OAuth client can use to get a new access token without the user's interaction. A refresh token must not allow the client to gain any access beyond the scope of the original grant.

What is difference between refresh token and access token?

The lifetime of a refresh token is much longer compared to the lifetime of an access token. Refresh tokens can also expire but are quiet long-lived. When current access tokens expire or become invalid, the authorization server provides refresh tokens to the client to obtain new access token.

How does access token and refresh token work?

A refresh token is a special token that is used to obtain additional access tokens. This allows you to have short-lived access tokens without having to collect credentials every time one expires.

Does refresh token invalidate access token?

Each revocation request invalidates not only the specific token but all other tokens based on the same authorization grant. This means that all refresh tokens that have been issued for the same user, application, and audience will be revoked.


1 Answers

A refresh token is required for so called OfflineCredentials. These are credentials, that can be used by applications, which are not running in a browser (e.g. desktop applications or some batch processing without UI) and therefore cannot perform an OAuth2 flow.

Please have a look at Using OAuth 2.0 to Access Google APIs

  1. Refresh the access token, if necessary.

Access tokens have limited lifetimes. If your application needs access to a Google API beyond the lifetime of a single access token, it can obtain a refresh token. A refresh token allows your application to obtain new access tokens.

Note: Save refresh tokens in secure long-term storage and continue to use them as long as they remain valid. Limits apply to the number of refresh tokens that are issued per client-user combination, and per user across all clients, and these limits are different. If your application requests enough refresh tokens to go over one of the limits, older refresh tokens stop working.

Some more information to Offline Access!

In Java, it will look like this:

import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.auth.OfflineCredentials.ForApiBuilder;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.client.auth.oauth2.Credential;

// ...

// Generate offline credentials
// With a previously created OAuth2 refresh token (see API examples)
ForApiBuilder forApiBuilder = new OfflineCredentials.Builder().forApi(Api.ADWORDS);
forApiBuilder.withClientSecrets(clientId, clientSecret);
forApiBuilder.withRefreshToken(refreshToken);

Credential credential = null;
try {
  credential = forApiBuilder.build().generateCredential();
} catch (OAuthException e) {
  throw new Exception("The given credential could not be refreshed: " + e.getMessage());
} catch (ValidationException e) {
  throw new Exception("Client ID, client secret or refresh token are not valid: " + e.getMessage());
}

// Build session
// ...

The refresh token need to be passed to the credential builder in addition to the client ID and the client secret. With the valid OfflineCredentials you are now able to build a new session for a specific Google API.

Regarding your third question: See the accepted answer of following question

Here the source code, which shows how to obtain a refresh token for Google AdWords (see scope) once via commandline. The client ID and the client secret must be passed as commandline arguments.

import java.io.BufferedReader;
import java.io.InputStreamReader;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;

import com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder;
import com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder.Api;
import com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder.GoogleClientSecretsForApiBuilder;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.common.collect.Lists;

// ...

  private static final String SCOPE = "https://adwords.google.com/api/adwords";

  // This callback URL will allow you to copy the token from the success screen
  private static final String CALLBACK_URL = "urn:ietf:wg:oauth:2.0:oob";

  public static void main(String[] args) throws Exception {
    if (args.length != 2) {
      System.err.println("Please provide client ID and secret as commandline arguments!");
      System.err.println("If you do not have a client ID or secret, please create one in the API console: https://code.google.com/apis/console#access");
      System.exit(1);
    }

    GoogleClientSecrets clientSecrets = null;
    try {
      Configuration configuration = new PropertiesConfiguration();
      configuration.setProperty("api.adwords.clientId", args[0]);
      configuration.setProperty("api.adwords.clientSecret", args[1]);

      GoogleClientSecretsForApiBuilder googleClientSecretsForApiBuilder = new GoogleClientSecretsBuilder().forApi(Api.ADWORDS);
      googleClientSecretsForApiBuilder.from(configuration);

      clientSecrets = googleClientSecretsForApiBuilder.build();
    } catch (ValidationException e) {
      System.err.println("Invalid client ID or secret!");
      System.exit(1);
    }

    // Get the OAuth2 credential
    Credential credential = getOAuth2Credential(clientSecrets);

    System.out.printf("Your refresh token is: %s\n", credential.getRefreshToken());
    }
  }

  private static Credential getOAuth2Credential(GoogleClientSecrets clientSecrets) throws Exception {
    /*
     * Set the access type to offline so that the token can be refreshed. By
     * default, the library will automatically refresh tokens when it can, but
     * this can be turned off by setting api.adwords.refreshOAuth2Token=false
     */
    GoogleAuthorizationCodeFlow authorizationFlow = new GoogleAuthorizationCodeFlow.Builder(new NetHttpTransport(), new JacksonFactory(), clientSecrets, Lists.newArrayList(SCOPE)).setAccessType("offline").build();

    String authorizeUrl = authorizationFlow.newAuthorizationUrl().setRedirectUri(CALLBACK_URL).build();
    System.out.println("Paste this url in your browser: \n" + authorizeUrl + '\n');

    // Wait for the authorization code
    System.out.println("Type the code you received here: ");
    String authorizationCode = new BufferedReader(new InputStreamReader(System.in)).readLine();

    // Authorize the OAuth2 token
    GoogleAuthorizationCodeTokenRequest tokenRequest = authorizationFlow.newTokenRequest(authorizationCode);
    tokenRequest.setRedirectUri(CALLBACK_URL);
    GoogleTokenResponse tokenResponse = tokenRequest.execute();

    // Create the OAuth2 credential
    GoogleCredential credential = new GoogleCredential.Builder().setTransport(new NetHttpTransport()).setJsonFactory(new JacksonFactory()).setClientSecrets(clientSecrets).build();

    // Set authorized credentials
    credential.setFromTokenResponse(tokenResponse);

    return credential;
  }

The code is originally from a Goolge AdWords API example. My version is not reading from a configuration file, because I didn't want to store the client ID and secret in some resource file (which I forgot to remove later on). That's why the values are passed as arguments to the program.

like image 191
gclaussn Avatar answered Sep 29 '22 07:09

gclaussn