4

In the QuickStart.java example on Java Quickstart they use OAuth client ID to identify the application, and this pops up a windows asking for Google credentials to use the application. You have to download a client_secret.json to modify a Google Sheet.

My question is: Can you evade the popping up window asking for Google credentials using an API Key or something else? And, if it's possible, how do you change the Java code in order to do that?

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
Mr. Kevin
  • 327
  • 4
  • 12

2 Answers2

5

An API key could only work when accessing the resources owned by the project that created the key.

For resources like spreadsheets, you're typically accessing resources owned by a user. It would be pretty awful if you got access to my private sheets simply by having an API key.

So no, I wouldn't expect there to be any way to avoid getting authorization to work with a user's documents. However, you should be able to use the Java OAuth library to retain the auth token so you can avoid needing to ask for it more than once. (Unless the user revokes access, of course.)

As DalmTo says, you can use service account credentials if you're trying to access resources owned by the project (or which the project can be granted access to). Note that if you're running on AppEngine, Google Kubernetes Engine or Google Compute Engine, the service account credentials for that environment should be available automatically.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
4

The popup window you are seeing is the Oauth2 consent screen. In order to access private user data you need to have consent of the user in order to access their data.

There is another option its called a service account. If the sheet you are trying to access is one that you as the developer have control of then you can create service account credeitals take the service account email address and grant the service account access to the sheet.

The best example for service account access with java that i am aware of is the one for Google Analytics you will have to alter it for Google sheets i may be able to help with that if you have any issues. hello analytics service account.

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.gson.GsonFactory;

import com.google.api.services.analytics.Analytics;
import com.google.api.services.analytics.AnalyticsScopes;
import com.google.api.services.analytics.model.Accounts;
import com.google.api.services.analytics.model.GaData;
import com.google.api.services.analytics.model.Profiles;
import com.google.api.services.analytics.model.Webproperties;

import java.io.FileInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.io.IOException;


/**
 * A simple example of how to access the Google Analytics API using a service
 * account.
 */
public class HelloAnalytics {


  private static final String APPLICATION_NAME = "Hello Analytics";
  private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
  private static final String KEY_FILE_LOCATION = "<REPLACE_WITH_JSON_FILE>";
  public static void main(String[] args) {
    try {
      Analytics analytics = initializeAnalytics();

      String profile = getFirstProfileId(analytics);
      System.out.println("First Profile Id: "+ profile);
      printResults(getResults(analytics, profile));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Initializes an Analytics service object.
   *
   * @return An authorized Analytics service object.
   * @throws IOException
   * @throws GeneralSecurityException
   */
  private static AnalyticsReporting initializeAnalytic() throws GeneralSecurityException, IOException {

    HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
    GoogleCredential credential = GoogleCredential
        .fromStream(new FileInputStream(KEY_FILE_LOCATION))
        .createScoped(AnalyticsScopes.all());

    // Construct the Analytics service object.
    return new Analytics.Builder(httpTransport, JSON_FACTORY, credential)
        .setApplicationName(APPLICATION_NAME).build();
  }


  private static String getFirstProfileId(Analytics analytics) throws IOException {
    // Get the first view (profile) ID for the authorized user.
    String profileId = null;

    // Query for the list of all accounts associated with the service account.
    Accounts accounts = analytics.management().accounts().list().execute();

    if (accounts.getItems().isEmpty()) {
      System.err.println("No accounts found");
    } else {
      String firstAccountId = accounts.getItems().get(0).getId();

      // Query for the list of properties associated with the first account.
      Webproperties properties = analytics.management().webproperties()
          .list(firstAccountId).execute();

      if (properties.getItems().isEmpty()) {
        System.err.println("No Webproperties found");
      } else {
        String firstWebpropertyId = properties.getItems().get(0).getId();

        // Query for the list views (profiles) associated with the property.
        Profiles profiles = analytics.management().profiles()
            .list(firstAccountId, firstWebpropertyId).execute();

        if (profiles.getItems().isEmpty()) {
          System.err.println("No views (profiles) found");
        } else {
          // Return the first (view) profile associated with the property.
          profileId = profiles.getItems().get(0).getId();
        }
      }
    }
    return profileId;
  }

  private static GaData getResults(Analytics analytics, String profileId) throws IOException {
    // Query the Core Reporting API for the number of sessions
    // in the past seven days.
    return analytics.data().ga()
        .get("ga:" + profileId, "7daysAgo", "today", "ga:sessions")
        .execute();
  }

  private static void printResults(GaData results) {
    // Parse the response from the Core Reporting API for
    // the profile name and number of sessions.
    if (results != null && !results.getRows().isEmpty()) {
      System.out.println("View (Profile) Name: "
        + results.getProfileInfo().getProfileName());
      System.out.println("Total Sessions: " + results.getRows().get(0).get(0));
    } else {
      System.out.println("No results found");
    }
  }
}
Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
  • Thank you for the answer. If I'm reading and writing on that sheet, I will have to use `client_secrets.json`, right? – Mr. Kevin Mar 27 '18 at 11:31
  • 1
    You will need to download a new client on google developer console of type service account. the current clinet_secrets.json file you have now is used for Oauth2 it wont work. – Linda Lawton - DaImTo Mar 27 '18 at 11:35
  • 1
    I'm using Google Sheets with Java to build an app that will be distributed with `.jar` extension. Google Sheets are like an online database for the application. The problem is that I have to set the sheets' privacy public, in order to modify the spreadsheets. There is anyway to protect the sheets and keep modifying them? – Mr. Kevin Mar 27 '18 at 11:36
  • 1
    Well assuming that these sheets are designed to only be used by your application then using a service account will be ideal for your use case. Its like a dummy user. You should the sheets to private and share it with the service account. I have a blog post that explains how service accounts work. http://www.daimto.com/google-developer-console-service-account/ – Linda Lawton - DaImTo Mar 27 '18 at 11:37
  • Are you telling me that with a service account I can set spreadsheets to private and keep modifying them with the application? – Mr. Kevin Mar 27 '18 at 11:39
  • 1
    Yes a service account is a dummy user. You can share a sheet with it and it will be able to access it just like a normal user. The sheet can then be set to private so that only you and the service account will actually be able to access it. Your application can then use the service account to write to the sheet as needed. Service accounts are preauthorized by sharing the file with the service account using its service account email address. – Linda Lawton - DaImTo Mar 27 '18 at 11:40
  • Remember to accept an answer if it helped and let me know if you have any issues with the example i should be able to help you translate it to sheets. – Linda Lawton - DaImTo Mar 27 '18 at 11:48
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/167635/discussion-between-mr-kevin-and-daimto). – Mr. Kevin Mar 27 '18 at 12:21