Paul A. Hoadley
Paul A. Hoadley

Reputation: 1545

Google API authentication in Java without using environment variable

I have set up a simple test app to interact with Google's Natural Language API. I created a service account, and downloaded the JSON credentials. I am running on a local development machine, so I set the GOOGLE_APPLICATION_CREDENTIALS environment variable to point to the JSON file. To be clear, this works: the app successfully makes some API calls and displays the results.

I would like to remove the dependence on the environment variable. How can I use the known location of the JSON file (or any other approach) in the application to create the LanguageServiceClient with those credentials?

Upvotes: 23

Views: 9667

Answers (5)

stzoannos
stzoannos

Reputation: 938

You can always pass the full json file as String as follows:

        CredentialsProvider credentialsProvider;
        String credentials = "[YOUR JSON FILE CONTENT]";

        try {

            credentialsProvider
                    = FixedCredentialsProvider.create(
                            ServiceAccountCredentials.fromStream(new ByteArrayInputStream(credentials.getBytes())));          

        } catch (IOException ex) {
            Logger.getLogger(GoogleNLPService.class.getName()).log(Level.SEVERE, null, ex);
        }

        LanguageServiceSettings.Builder languageServiceSettingsBuilder
                = LanguageServiceSettings.newBuilder();

        LanguageServiceSettings languageServiceSettings = languageServiceSettingsBuilder.setCredentialsProvider(credentialsProvider).build();

        List<NamedEntity> entities = new ArrayList<>();
        try (LanguageServiceClient language = LanguageServiceClient.create(languageServiceSettings)) {

         ...

        }

Alternatively, you can place your json file in resources folder and then read it as:

    credentialsProvider
            = FixedCredentialsProvider.create(
                    ServiceAccountCredentials.fromStream(new FileInputStream("./src/main/resources/FILENAME.json")));

However, this relative path didn't work when I uploaded my app in Heroku. So, I have decided to use the String solution.

Upvotes: 3

Kieran Fraser
Kieran Fraser

Reputation: 45

Following the advice from tokyohans answer above, I can confirm this works for LanguageServiceClient:

    // old-school Google Authentication     
    GoogleCredential credential = null;
    credential = GoogleCredential.fromStream(new FileInputStream("google.json"));

    Collection<String> scopes = Collections.singleton("https://www.googleapis.com/auth/cloud-language");

    if (credential.createScopedRequired()) {
          credential = credential.createScoped(scopes);
    }

    // copy over key values, note the additional "s", set some expiry
    // com.google.auth.oauth2.GoogleCredentials 
    GoogleCredentials sac = ServiceAccountCredentials.newBuilder()
                .setPrivateKey(credential.getServiceAccountPrivateKey())
                .setPrivateKeyId(credential.getServiceAccountPrivateKeyId())
                .setClientEmail(credential.getServiceAccountId())
                .setScopes(scopes)
                .setAccessToken(new AccessToken(credential.getAccessToken(), new LocalDate().plusYears(1).toDate()))
                .build();

    // Latest generation Google libs, GoogleCredentials extends Credentials
    CredentialsProvider cp = FixedCredentialsProvider.create(sac);
    LanguageServiceSettings settings = (LanguageServiceSettings) LanguageServiceSettings.newBuilder().setCredentialsProvider(cp).build();
    return LanguageServiceClient.create(settings);

Upvotes: 3

tokyohans
tokyohans

Reputation: 81

This looks like an older thread but sharing our findings for what it's worth.

This example is for the Google ImageAnnotatorClient, but I am pretty sure it is very similar for LanguageServiceClient.

Old-school google libraries (P12 file era) use GoogleCredential vs. the new GoogleCredentials. They look very similar. Digging into the Type hierarchy I found a FixedCredentialsProvider which seems to do the trick.

This worked for us, we got the Google Vision API up and running with an existing P12 file without environment variable. It does look like Google wants us to migrate away from this so not recommending this approach long-term.

// old-school Google Authentication
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();

// Spring code
String pemFile = "yourPemFile.p12";
Resource r = new ClassPathResource(pemFile);
String serviceAccountEmail = "[email protected]";

// com.google.api.client.googleapis.auth.oauth2.GoogleCredential.Builder
Builder credentialBuilder = new GoogleCredential.Builder()
            .setTransport(httpTransport)
            .setJsonFactory(jsonFactory)
            .setServiceAccountId(serviceAccountEmail)
            .setServiceAccountPrivateKeyFromP12File(r.getFile());

// Cloud API endpoints, make sure that the API is enabled
Collection<String> scopes = Collections.singleton("https://www.googleapis.com/auth/cloud-vision");
GoogleCredential credential = credentialBuilder
            .setServiceAccountScopes(scopes).build();

// copy over key values, note the additional "s", set some expiry
// com.google.auth.oauth2.GoogleCredentials 
GoogleCredentials sac = ServiceAccountCredentials.newBuilder()
            .setPrivateKey(gc.getServiceAccountPrivateKey())
            .setPrivateKeyId(gc.getServiceAccountPrivateKeyId())
            .setClientEmail(gc.getServiceAccountId())
            .setScopes(scopes)
            .setAccessToken(new AccessToken(gc.getAccessToken(), new LocalDate().plusYears(1).toDate()))
            .build();

// Latest generation Google libs, GoogleCredentials extends Credentials
CredentialsProvider cp = FixedCredentialsProvider.create(sac);
ImageAnnotatorSettings settings = ImageAnnotatorSettings.newBuilder().setCredentialsProvider(cp).build();
ImageAnnotatorClient googleApi = ImageAnnotatorClient.create(settings);

Upvotes: 1

Steve Harrington
Steve Harrington

Reputation: 942

We use a service account + GoogleCredential.Builder -- (note that this example uses a credential file in p12 format); example follows:

 private GoogleCredential authorize() throws IOException, GeneralSecurityException
{
    return new GoogleCredential.Builder()
    .setTransport(HTTP_TRANSPORT)
    .setJsonFactory(JSON_FACTORY)
    .setServiceAccountId(serviceAccount)
    .setServiceAccountScopes(SCOPES)
    .setServiceAccountUser(serviceAccountUser)
    // variable p12File is a String w/ path to the .p12 file name
    .setServiceAccountPrivateKeyFromP12File(new java.io.File(p12File))
      .build();
}

Upvotes: 2

Jochen Bedersdorfer
Jochen Bedersdorfer

Reputation: 4122

You can register is like this:

DatastoreOptions options = DatastoreOptions.newBuilder()
  .setProjectId(PROJECT_ID)
  .setAuthCredentials(AuthCredentials.createForJson(
    new FileInputStream(PATH_TO_JSON_KEY))).build();

Does that help?

Upvotes: 3

Related Questions