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.
}