Google Drive Auth with a service account running locally but breaks when deployed on the application engine

advertisements

I am writing an App Engine web application that loads a gallery of images from a folder on Google Drive. The code works just fine when running locally (the images are retrieved and showed on the webpage correctly), but it breaks when deployed on Google App Engine. Specifically, when launching the following method, the returned Drive service is null, with no exception thrown. Credentials (SERVICE_ACCOUNT_EMAIL and PKCS12 file) should be correct, since they work when running the code locally. What am I missing here? Thanks in advance.

public static Drive getDriveService() {
    HttpTransport httpTransport = new NetHttpTransport();
    GsonFactory jsonFactory = new GsonFactory();
    GoogleCredential credential;
    Drive service = null;
    List<String> scopes = Arrays.asList(DriveScopes.DRIVE);
    try {
        credential = new GoogleCredential.Builder()
                .setTransport(httpTransport)
                .setJsonFactory(jsonFactory)
                .setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
                .setServiceAccountScopes(scopes)
                .setServiceAccountPrivateKeyFromP12File(
                        new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))
                .build();
        service = new Drive.Builder(httpTransport, jsonFactory, null).setApplicationName("MyAppName")
                .setHttpRequestInitializer(credential).build();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return service;
}


There are actually two ways to authenticate with a service account with the Drive Api. The one you are using is ok if you're debugging on your local machine with the Dev App Server, but won't work once deployed to GAE. You can authenticate with this code snippet as taken from the Drive API Reference on

https://developers.google.com/drive/service-accounts#google_app_engine_project_service_accounts

Just put your API Key obtained from the console in the code. This is the only working solution i've found for GAE authentication for Drive API.

This is the code you are looking for, to add into your project:

import com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential;
import com.google.api.client.googleapis.services.CommonGoogleClientRequestInitializer;
import com.google.api.client.googleapis.services.GoogleClientRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
...

/** The API Key of the project */
private static final String API_KEY = "the_api_key_of_the_project";

/**
 * Build and returns a Drive service object authorized with the
 * application's service accounts.
 *
 * @return Drive service object that is ready to make requests.
 */
public static Drive getDriveService() throws GeneralSecurityException,
    IOException, URISyntaxException {
  HttpTransport httpTransport = new NetHttpTransport();
  JsonFactory jsonFactory = new JacksonFactory();
  AppIdentityCredential credential =
      new AppIdentityCredential.Builder(DriveScopes.DRIVE).build();
  GoogleClientRequestInitializer keyInitializer =
      new CommonGoogleClientRequestInitializer(API_KEY);
  Drive service = new Drive.Builder(httpTransport, jsonFactory, null)
      .setHttpRequestInitializer(credential)
      .setGoogleClientRequestInitializer(keyInitializer)
      .build();
  return service;
}