Search code examples
javagoogle-cloud-platformgoogle-vision

Unable to authenticate service account - Google Cloud


I'll premise that I've already googled and read the documentation before writing, I've noticed that it's a popular discussion here on StackOverflow as well, but none of the answers already given have helped me.

I created a Google Cloud account to use the API: Google Vision.

To do this I followed the steps of creating the project, adding the above API and finally creating a service account with a key.

I downloaded the key and put it in a folder in the java project on the PC.

Then, since it is a maven project I added the dependencies to the pom as described in the tutorials.

At this point I inserted the suggested piece of code to start using the API.

Everything seemed to be OK, everything was read, the various libraries/interfaces were imported.

But an error came up as soon as I tried to run the program:

The Application Default Credentials are not available. They are available if running in Google Compute Engine. Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined pointing to a file defining the credentials.

I must admit I didn't know what 'Google Compute Engine' was, but since there was an alternative and I had some credentials, I wanted to try and follow that.

So I follow the instructions:

After creating your service account, you need to download the service account key to your machine(s) where your application runs. You can either use the GOOGLE_APPLICATION_CREDENTIALS environment variable or write code to pass the service account key to the client library.

OK, I tried the first way, to pass the credentials via environment variable:

  • With powershell -> no response
$env:GOOGLE_APPLICATION_CREDENTIALS="my key path"
  • With cmd -> no response either
set GOOGLE_APPLICATION_CREDENTIALS=my key path

So I tried the second way, passing credentials using code and if I'm here something else must have gone wrong, in fact with what I have it was only possible to import io.grpc.Context, while everything else gives the error "Cannot resolve symbol ..".

import com.google.common.collect.Lists;
import io.grpc.Context;

import java.io.FileInputStream;
import java.io.IOException;

public class Main
{
    static void authExplicit(String jsonPath)
    {
        GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream(jsonPath))
                .createScoped( Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"));
        Context.Storage storage = StorageOptions.newBuilder().setCredentials(credentials).build().getService();

        System.out.println("Buckets:");
        Page<Bucket> buckets = storage.list();
        for (Bucket bucket : buckets.iterateAll()) {
            System.out.println(bucket.toString());
        }
    }

    public static void main(String[] args) throws IOException
    {
        OCR.detectText();
    }
}

(I don't think I can upload a screen of the code to show where it gives me errors, however it is this)

PS: I also already installed the Cloud SDK and restarted the PC because some comments said to do that to fix things.

I also tried setting the environment variable manually, but nothing changes: enter image description here

Solution

I don't know if it all worked out because of a series of operations I performed I for this one command line, anyway, for posterity's sake:

  • Fill in these fields manually using the email field in the json file and the path to the json file, both without inverted commas, then start cmd, paste the string and run!

gcloud auth activate-service-account your_account_email_id --key-file=json_file_path

It also helped me to reboot the PC afterwards.


Solution

  • Please, consider read the ImageAnnotationClient class level javadocs, it gives you the right guidance about how to accomplish the authentication process. I modified the provided code to give you the full example:

    // Please, set the appropriate path to your JSON credentials file here
    String credentialsPath = "..."; 
    // The credentials could be loaded as well as this.getClass().getResourceAsStream(), for example
    GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream(credentialsPath))
        .createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"));
    
    // Use that credentials to build your image annotation client
    ImageAnnotatorSettings imageAnnotatorSettings =
      ImageAnnotatorSettings.newBuilder()
        .setCredentialsProvider(FixedCredentialsProvider.create(credentials))
        .build()
    ;
    
    ImageAnnotatorClient imageAnnotatorClient = ImageAnnotatorClient.create(imageAnnotatorSettings);
    // Perform the stuff you need to...
    

    The only dependency you need to provide in your pom.xml is this:

    <dependency>
        <groupId>com.google.cloud</groupId>
        <artifactId>google-cloud-vision</artifactId>
        <version>2.0.18</version>
    </dependency>
    

    In any case, please, consider for reference the pom.xml provided in the Cloud Vision examples.

    The Cloud Vision examples repository gives some useful code snippets as well in the Detect class for the detection process itself.

    Be sure that the service account you are using to connect to Google Cloud has the necessary permissions.

    Although this solution could work, it has the drawback that you probably need to store the credentials file somewhere in your machine, maybe in your source code repository, etcetera, and it can suppose a security risk. If your are running your program from Google Cloud is always advisable to grant to the VM or service you are using the necessary permissions and use the default application credentials.

    The use of the GOOGLE_APPLICATION_CREDENTIALS could be preferable as well. If you are trying using this variable, initially, try configuring it using your IDE provided mechanisms instead of cmd, PS, or bash, and see if it works.

    For using any of the two last mentioned solutions you don't need to provide any additional information when constructing your ImageAnnotatorClient:

    ImageAnnotatorClient imageAnnotatorClient = ImageAnnotatorClient.create();