Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refresh Token with Google API Java Client Library

I'm using the Google API Java Client http://code.google.com/p/google-api-java-client/ and am able to get the access token successfully for Android.

    // Google Accounts
credential = GoogleAccountCredential.usingOAuth2(this, CalendarScopes.CALENDAR);
SharedPreferences settings = getPreferences(Context.MODE_PRIVATE);
credential.setSelectedAccountName(settings.getString(PREF_ACCOUNT_NAME, null));

As I'd like my web server to make offline API calls, I need a refresh token. I have been searching extensively and have not yet figured out how to do so.

Ideally, I'd prefer to use the Google API Java Client over the WebView to grab the refresh token (no need to enter a username or password).

Any help would be appreciated!

like image 985
Delos Chang Avatar asked Oct 21 '22 17:10

Delos Chang


2 Answers

You can also do this by creating a refresh token configured to a OAuth 2.0 Client Id.

Go to https://console.developers.google.com/apis/credentials

  1. Click 'Create Credential'.
  2. Click 'OAuth client Id'.
  3. Select 'Web application' > Give a name.
  4. Add https://developers.google.com/oauthplayground to 'Authorized redirect URIs'.
  5. Click Create.

You will need the ClientId and the Secret for next steps.

Then go to https://developers.google.com/oauthplayground/

  1. Click 'AOuth 2.0 Configuration' on right upper corner.
  2. Check 'Use your own OAuth credentials'.
  3. Update 'OAuth Client ID' and 'OAuth Client secret' with client id and secret of above created OAuth 2.0 credential.
  4. In Step 1 on left corner, Select all the necessary scopes.(Please note that unmatching scopes in request will return 'invalid_scopes'.)
  5. Click 'Authorize APIs'. This will redirect you to a consent page to allow permissions.
  6. In Step 2, click 'Exchange authorization code for tokens'
  7. You will get an Access Token with a Refresh Token. We will need this Refresh Token for the next step.

You can use this access token to authenticate to services you specified in scopes. Access Tokens are short lived and Refresh tokens expire after 24 hours unless it is not bound to a OAuth 2.0 client (We just made our refresh token to last until it is revoked by the user or expires due to 6 months inactivity).

You need to refresh the Access Token before it expires. Check out following example to see how.

    public String getNewToken(String refreshToken, String clientId, String clientSecret) throws IOException {
            ArrayList<String> scopes = new ArrayList<>();
    
            scopes.add(CalendarScopes.CALENDAR);
    
            TokenResponse tokenResponse = new GoogleRefreshTokenRequest(new NetHttpTransport(), new JacksonFactory(),
                    refreshToken, clientId, clientSecret).setScopes(scopes).setGrantType("refresh_token").execute();
    
            return tokenResponse.getAccessToken();
    }

clientId and clientSecret in above example refers to OAuth 2.0 client credentials.

You can create a 'GoogleCredential' with that like this

    public Credential getCredentials() throws GeneralSecurityException, IOException, FileNotFoundException {
        final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
        final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

        // Load client secrets.
        String CREDENTIALS_FILE_PATH = "/credentials.json"; //OAuth 2.0 clinet credentials json
        InputStream in = DriveQuickstart.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
        if (in == null) {
            throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
        }
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        String clientId = clientSecrets.getDetails().getClientId();
        String clientSecret = clientSecrets.getDetails().getClientSecret();

        GoogleCredential credential = new GoogleCredential.Builder()
                .setTransport(HTTP_TRANSPORT)
                .setJsonFactory(JSON_FACTORY)
                .setClientSecrets(clientId, clientSecret)
                .build();

        String refreshToken = "<REFRESH-TOKEN>"; //Find a secure way to store and load refresh token
        credential.setAccessToken(getNewToken(refreshToken, clientId, clientSecret));
        credential.setRefreshToken(refreshToken);

        return credential;
    }
like image 58
Pubudu Sitinamaluwa Avatar answered Nov 09 '22 15:11

Pubudu Sitinamaluwa


You need to set the following when you initiate the authorization flow :

  • approval prompt = force
  • access type = offline

With these params set, google will return a refresh token and the library will deal with refreshes. This works for me :

new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, getClientCredential(),
                Arrays.asList(SCOPES)).setCredentialStore(new OAuth2CredentialStore()).setAccessType("offline")
                .setApprovalPrompt("force").build();
like image 30
koma Avatar answered Nov 09 '22 16:11

koma