Refresh Token with Google API Java Client Library
Asked Answered
L

2

5

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!

Luxor answered 19/2, 2013 at 1:52 Comment(0)
U
6

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;
    }
Unmoor answered 7/11, 2019 at 3:48 Comment(1)
Thank you so much, this solved perfectly my issue.Periodontal
N
2

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();
Network answered 22/2, 2013 at 13:26 Comment(3)
Thanks for the help. Does this work with the account chooser though (i.e. does it work with GoogleAccountCredential?)Luxor
I guess, since GoogleAccountCredential implements HttpRequestInitializer. but trying it helps to find out ;)Network
I have no clue of how to integrate this with GoogleAccountCredential, any hints? :(Shirt

© 2022 - 2024 — McMap. All rights reserved.