Authorization to Google Client
Asked Answered
D

2

4

I am writing a class for creating authorization to BigQuery and Google Cloud Storage.

In the past I have used CredentialStore which has been deprecated. I am trying to use DataStoreFactory but I discovered that it allows me to use only StoredCredential while I need a Credential.

I know one can convert from Credential to StoredCredential but I am not sure how to convert them in the opposite direction (StoredCredential to Credential). For example I am creating my connection like this:

Storage.Builder(HttpTransport transport,
    JsonFactory jsonFactory,
    HttpRequestInitializer httpRequestInitializer);


Could anyone point me in a direction about how to achieve this?

Thank you!

Dressmaker answered 19/12, 2013 at 14:27 Comment(0)
C
2

In most cases, wherever you use Credential, you could use StoredCredential. There is only one point you would work with Credential, which is retrieving the Access Token during the OAuth callback. From there the Credential can be converted to StoreCredential and stored into the DataStore. After that storage and retrieval all works with StoredCredential.

But there are places were StoredCredential can't be used. I just encountered one trying to create the Google Drive API Service wrapper.

There is a way to get around this with the GoogleCredential object, it can be created from StoredCredential as per this answer:
Stored Credential from Google API to be reused using Java

import com.google.api.client.auth.oauth2.StoredCredential;

public static GoogleCredential createGoogleCredential(StoredCredential storedCredential) {
    GoogleCredential googleCredential = new GoogleCredential.Builder()
        .setTransport(new NetHttpTransport())
        .setJsonFactory(new JacksonFactory())
        .setClientSecrets("client_id", "client_secret")
        .setAccessToken(storedCredential.getAccessToken())
        .build();

    return googleCredential;
}
Consultant answered 19/12, 2013 at 14:27 Comment(2)
Which one is which in ur code? What is the credential object? I presume storedCredential is the one in your own DB.Heavily
Yes. I have edited the answer to make this explicit.Consultant
L
1

I'm using google-oauth-client-1.22.0.jar.

I have a Java server with static Service Account credentials that authenticates with Google Cloud.

Here is the salient code that I use.

The key here is to add a CredentialRefreshListener which, when you successfully authenticate, then the Google OAuth client library will call and give you a StoredCredential object which you can serialize and store. You store it, and retrieve it, to a location of your choice by writing or instantiating an implemenation of the DataStore interface. Your DataStore implementation is constructed using a DataStoreFactory implementation.

After building my GoogleCredential, then I can read the last access token, refresh token and expiration date from my DataStore. If the access token isn't about to expire, then the Google client API will use it to log in. When it's about to expire, or this is the first time this code is called, then the Google Client API will invoke the refresh listener and it will store the first access token, refresh token and expiration date.

import com.google.api.client.auth.oauth2.DataStoreCredentialRefreshListener;
import com.google.api.client.auth.oauth2.StoredCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.IOUtils;
import com.google.api.client.util.store.AbstractDataStore;
import com.google.api.client.util.store.AbstractDataStoreFactory;
import com.google.api.client.util.store.DataStore;
import com.google.api.client.util.store.DataStoreFactory;
import com.google.api.services.storage.Storage;
import com.google.api.services.storage.StorageScopes;
import com.google.api.services.storage.model.StorageObject;

import java.io.IOException;
import java.io.Serializable;
import java.util.Base64;

public class StackOverflow {

  public static void main(final String... args) throws Exception {
    final String clientEmail = "[email protected]";
    final HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
    final JsonFactory jsonFactory = new JacksonFactory();
    // This implementation generates an that stores and retrieves StoredCredential objects
    final DataStoreFactory dataStoreFactory = new AbstractDataStoreFactory() {
      @Override
      protected <V extends Serializable> DataStore<V> createDataStore(final String id) {
        return new MyDataStore<>(this, id);
      }
    };
    // construct a GoogleCredential object to access Google Cloud
    final GoogleCredential credential = new GoogleCredential.Builder()
        .setTransport(transport)
        .setJsonFactory(jsonFactory)
        .setServiceAccountId(clientEmail)
        .setServiceAccountScopes(StorageScopes.all())
        .setServiceAccountPrivateKey(readEncryptedPemFile())
        .setServiceAccountPrivateKeyId("___static_get_this_from_google_console___")
        .addRefreshListener(new DataStoreCredentialRefreshListener(clientEmail, dataStoreFactory))
        .build();
    // See I have an access token, refresh token and expiration date stored in my DataStore.
    // If so, set them on the GoogleCredential
    final StoredCredential storedCredential = StoredCredential.getDefaultDataStore(dataStoreFactory).get(clientEmail);
    if (storedCredential != null) {
      credential.setAccessToken(storedCredential.getAccessToken());
      credential.setRefreshToken(storedCredential.getRefreshToken());
      credential.setExpirationTimeMilliseconds(storedCredential.getExpirationTimeMilliseconds());
    }
    // Now I can use Google Cloud
    final Storage storage = new Storage.Builder(credential.getTransport(), credential.getJsonFactory(), credential).setApplicationName("Aimless").build();
    storage.objects().insert("soem bucket", new StorageObject());
  }

  private static class MyDataStore<V extends Serializable> extends AbstractDataStore<V> {

    MyDataStore(DataStoreFactory dataStoreFactory1, String id1) {
      super(dataStoreFactory1, id1);
    }

    @Override
    public DataStore<V> set(String key, V value) throws IOException {
      final String encoded = Base64.getEncoder().encodeToString(IOUtils.serialize(value));
      db.save(key, encoded);
      return this;
    }

    @Override
    public V get(String key) throws IOException {
      final String encoded = db.get(key);
      if (encoded == null) {
        return null;
      }
      return IOUtils.deserialize(Base64.getDecoder().decode(encoded));
    }

    // etc.
  }
Lough answered 28/2, 2017 at 20:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.