My Business
5.7K members online now
5.7K members online now
For developers who are using the Google My Business API to manage locations
Guide Me
star_border
Reply

401 Unauthorized when connecting

[ Edited ]
Visitor ✭ ✭ ✭
# 1
Visitor ✭ ✭ ✭

Hi,

 

I'm trying to connect using the AuthorizationCodeFlow example (from https://developers.google.com/my-business/content/set-up-java-client) but all I get is a 401 error.  I have logged into the console and created the API key, OAuth Client ID, and a Service Account Key, and downloaded the OAuth Client ID as JSON and stored it in the src directory as client_secrets.json.

 

This exception below occurs when the client tries to get the list of accounts, 

 

   Mybusiness.Accounts.List accountsList = mybusiness.accounts().list();
   ListAccountsResponse response = accountsList.execute();   //  <<-- raises exception here
   List accounts = response.getAccounts();

 

Here's the exception:

Exception in thread "main" com.google.api.client.auth.oauth2.TokenResponseException: 401 Unauthorized
at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)
at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)
at com.google.api.client.auth.oauth2.Credential.executeRefreshToken(Credential.java:572)
at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:217)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
at uk.co.spar.googleapi.AuthorizationFlowDemo.main(AuthorizationFlowDemo.java:80)

 

Also, where are the samples and instructions for the Java client library??  Your documentation is pretty clear that using the client libraries is recommended, but I can't find any samples on the "Downloads and Samples" page (https://developers.google.com/my-business/samples/).  It would also be very helpful if the page "Setup the Java Client" (https://developers.google.com/my-business/content/set-up-java-client) actually included instructions on how to setup the java client - specifically, I had to figure out the hard way what the 39 .jar dependencies are.

 

The only example I can find is the AuthorizationCodeFlow, and it's not even complete - no import statements, or any indication of what the APPLICATION_NAME constant should be set to (does it matter?)

 

It seems that there is endless pages of content that doesn't really say very much about how to get started or actually *do* anything - where is the reference guide for the java client?

 

Regards

John

1 Expert replyverified_user

401 Unauthorized when connecting

Visitor ✭ ✭ ✭
# 2
Visitor ✭ ✭ ✭

Bump.

 

Any chance of some technical support on this?  Im using your example and it doesn't work!

 

Regards

John

 

Re: 401 Unauthorized when connecting

[ Edited ]
Google Employee
# 3
Google Employee

Hi @SPAR D,

 

We discontinued offering the Java sample app since we launched v3.1 of the Google My Business API. You can find v3 of the Java sample app here.

 

Please note that API Key authentication is not supported by the Google My Business API. The Google My Business API accesses protected (non-public) data, therefore you should use an OAuth 2.0 client ID for letting your application request authorization to access your organization's location data on behalf of your app's users.

 

We strongly encourage you to use the client libraries that we provide when interacting with Google's OAuth 2.0 endpoints for the security implications of getting the implementation correct. You should download the Java client library. You should also download the Google API Client Library for Java in a zip file and extract it for the client library class jar files and the associated source jar files for each artifact and their dependencies. You should be able to set up the Java client library by Adding External JARs to an Eclipse project using the Java client library and the Google API Client Library for Java.

 

You can also use Gradle to prepare your application with the Java client library for use in the Eclipse IDE. Please place the Java client library in a directory named “libs” in your Eclipse project. Below is the content of the build.gradle file:

apply plugin: 'java'

apply plugin: 'application'

 

sourceCompatibility = 1.7

version = '1.0'

mainClassName = 'com.google.sample.MyBusinessClient'

 

repositories {

   mavenCentral()

   flatDir {

       dirs 'libs'

   }

}

 

dependencies {

   compile 'com.google.api-client:google-api-client:1.20.0'

   compile 'com.google.oauth-client:google-oauth-client-java6:1.20.0'

   compile 'com.google.oauth-client:google-oauth-client-jetty:1.20.0'

   compile name: 'google-api-services-mybusiness-v3p1-java-rev20160926-1'

}

 

Due to the complexities involved in using service accounts, we strongly recommend using the OAuth 2.0 installed application flow or the OAuth 2.0 web server application flow and persisting the refresh token. This way, your application will always be able to request a new access token when necessary. This process requires a user to manually authorize the application during the OAuth 2.0 flow only once.

 

Please follow the code snippet below for using an OAuth 2.0 client ID and persisting the refresh token with the Java client library:

 /**

  * Be sure to specify the name of your application. If the application name is {@code null} or

  * blank, the application will log a warning. Suggested format is "MyCompany-ProductName/1.0".

  */

 private static final String APPLICATION_NAME = "Google-My-Business-API-Tester/1.0";

 

 private static final java.io.File DATA_STORE_DIR =

     new java.io.File(System.getProperty("user.home"), ".store/mybusiness_sample");

 

 private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

 private static FileDataStoreFactory dataStoreFactory;

 private static HttpTransport httpTransport;

 private static Mybusiness mybusiness;

 

 private static List<Account> listAccounts() throws Exception {

   Mybusiness.Accounts.List listAccounts = mybusiness.accounts().list();

   // If you get a request validation error you can inject the following header into any call as
   // shown below to get a more descriptive error and then it will throw trying to digest that
   // richer message.
   // This is a bug in the client library generator that will be fixed in the future.
   listAccounts.getRequestHeaders().set("X-GOOG-API-FORMAT-VERSION", 2);

   ListAccountsResponse response = listAccounts.execute();

 

   List<Account> accounts = response.getAccounts();

   for (Account account : accounts) {

     System.out.println(account.toPrettyString());

   }

   return response.getAccounts();

 }

 

 /** Authorizes the installed application to access user's protected data. */

 private static Credential authorize() throws Exception {

   // load client secrets

   InputStream secrets = Test.class.getResourceAsStream("/client_secrets.json");

   if (secrets == null) {

     System.out.println(

         "Enter Client ID and Secret from Google API Console "

             + "into src/main/resources/client_secrets.json");

     System.exit(1);

   }

   GoogleClientSecrets clientSecrets =

       GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(secrets));

   if (clientSecrets.getDetails().getClientId().startsWith("Enter")

       || clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {

     System.out.println(

         "Enter Client ID and Secret from Google API Console "

             + "into src/main/resources/client_secrets.json");

     System.exit(1);

   }

   // set up authorization code flow

   GoogleAuthorizationCodeFlow flow =

       new GoogleAuthorizationCodeFlow.Builder(

               httpTransport,

               JSON_FACTORY,

               clientSecrets,

               Collections.singleton("https://www.googleapis.com/auth/plus.business.manage"))

           .setDataStoreFactory(dataStoreFactory)

           .setAccessType("offline")

           .setApprovalPrompt("force")

           .build();

 

   // authorize

   return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");

   // authorize using a specific port number

   //    return new AuthorizationCodeInstalledApp(flow, new

   // LocalServerReceiver.Builder().setPort(8888).build()).authorize("user");

 }

 

 public static void main(String[] args) throws Exception {

   httpTransport = GoogleNetHttpTransport.newTrustedTransport();

   dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);

   Credential credential = authorize();

   mybusiness =

       new Mybusiness.Builder(httpTransport, JSON_FACTORY, credential)

           .setApplicationName(APPLICATION_NAME)

           .build();

 

   List<Account> accounts = listAccounts();

 }

 

If you need specific features of a service account, a one-time user consent is required for a service account to be able to access the Google My Business data on behalf of a particular end user. The end users will have to log in with their Google Accounts to manually authorize the application using OAuth 2.0 authentication and authorization. They can perform this process during OAuth 2.0 installed applications flow, OAuth 2.0 web server applications flow or using OAuth 2.0 Playground. This process needs to be done only once. When you prepare to make authorized API calls using the service account, you specify the user to impersonate by specifying the email address of the user account for access to their Google My Business data. If the end users later want to revoke the application’s access to their Google My Business data, they can remove the authorized app from the Apps connected to your account page of their accounts.

 

Please follow the code snippet below for using a service account with the Java client library:

 /**

  * Authorizes the installed application to access user's protected data using a service account.

  */

 private static Credential authorize() throws Exception {

   GoogleCredential credential =

       new GoogleCredential.Builder()

           .setTransport(httpTransport)

           .setJsonFactory(JSON_FACTORY)

           .setServiceAccountId(

               "****@developer.gserviceaccount.com")

           .setServiceAccountScopes(

               Collections.singleton("https://www.googleapis.com/auth/plus.business.manage"))

           .setServiceAccountPrivateKeyFromP12File(new File("key.p12"))

           // Set the user you are impersonating. This should be a valid login email

           // for your Google My Business account you are making calls to.

           .setServiceAccountUser("user@yourdomain.com")

           .build();

   credential.refreshToken();

   return credential;

 }

 

Thanks,

Terry

401 Unauthorized when connecting

[ Edited ]
Visitor ✭ ✭ ✭
# 4
Visitor ✭ ✭ ✭

Hi Terry

 

Thanks for your reply; and thanks for the sample code.

 

I am using the Java client already, but I've tried your OAuth example from above and I still get the same 401 error. This is what I get:

 

Exception in thread "main" com.google.api.client.auth.oauth2.TokenResponseException: 401 Unauthorized

at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)

at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)

at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)

at com.google.api.client.auth.oauth2.Credential.executeRefreshToken(Credential.java:572)

at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)

at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:217)

at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859)

at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)

at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)

at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)

at uk.co.spar.googleapi.ListAccountsDemo.listAccounts(ListAccountsDemo.java:47)

at uk.co.spar.googleapi.ListAccountsDemo.main(ListAccountsDemo.java:88)

 

Any idea what's wrong?  The client_secrets.json that I'm using is downloaded from the "Download JSON" button on the OAuth key, and looks like this:

 

{

  "installed": {

    "client_id": "XXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com",

    "project_id": "< Text has been removed to protect private information >",

    "auth_uri": "https://accounts.google.com/o/oauth2/auth",

   "token_uri": "https://accounts.google.com/o/oauth2/token",

   "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",

   "client_secret": "XXXXXXXXXXXXXXXXXXXX",

   "redirect_uris": [

     "urn:ietf:wg:oauth:2.0:oob",

     "http://localhost"

   ]

 }

}

 

 

 

 

Re: 401 Unauthorized when connecting

Google Employee
# 5
Google Employee

Hi @SPAR D,

 

The content of the client_secrets.json file you posted seems to be correct. Did you click “Allow” on the consent screen in a browser window that your Java application should’ve opened to manually authorize the application for access to the Google My Business data in your logged-in Google Account?

 

Thanks,

Terry

401 Unauthorized when connecting

Visitor ✭ ✭ ✭
# 6
Visitor ✭ ✭ ✭

Hi Terry

 

I've just used a brand new OAuth ID and rerun it - the same error occurs, but there is no consent screen opening up.

 

From the OAuth docs, it seems that every new request must be authorised interactively by a user and the authorization token cannot be persisted(certainly not across server restarts).  Is this true?

 

We have 2,600 stores that are updated by a large number of people (and external processes) and obviously we cannot give the username and password out so that everybody can authorise the API interactively, so this is not practical.  I would therefore expect to be able to use a Service Account, does Google My Business API support Service Accounts?  (and in which case please can you provide an example using the client API?)

 

Regards

John

 

Re: 401 Unauthorized when connecting

Google Employee
# 7
Google Employee

Hi @SPAR D,

 

I’ve already explained and provided code snippets for how to use an OAuth 2.0 client ID and persist the refresh token, as well as how to use a service account, for making requests via the Google My Business API with the Java client library in my previous post in this thread.

 

I suggest you download the v3 of the Java sample app & the v3.1 of Java client library, and use Gradle to set up the app with the build.gradle file I previously posted in this thread to manage the dependencies of your project simply. Please note that you may want to download a Gradle plugin for the Eclipse IDE. Why are you not able to get to the consent screen in a browser window and “Allow” the set of resources and operations set by the scope parameter that an access token permits? Can you tell me whether the platform you are building this Java application on supports access to web browsers? Are you logged in with a Google Account in a web browser? Can you try using an OAuth 2.0 client ID for a Web application and set a redirect URI to http://localhost/Callback and let me know what happens? Can you provide some screenshots from your Eclipse IDE and open browser windows for this matter?

 

An access token has a limited lifetime. Once the access token expires, your application should use the refresh token to obtain a new one. Your application should store the refresh token for future use and use the access token to access the Google My Business API. Therefore, your access token and refresh token are saved in the StoredCredential file via implementation of Data store in the “.store/mybusiness_sample” directory under your home directory if you use my code snippet to work with the Java client library for an OAuth 2.0 client ID application. You can obtain different refresh tokens for different logged in Google Accounts to access to their respective Google My Business data. I suggest you check out this Accepted Solution for using a single set of OAuth 2.0 credentials for separate Google Accounts. Keep in mind that you can also save the refresh tokens in other persistent data storage such as a database so that you can access your clients’ Google My Business data using the appropriate refresh tokens conveniently across multiple servers. This process requires human interaction to authorize your app during OAuth 2.0 flow only once for each Google Account that you need to access the Google My Business data from.

 

If you want to build a service account application, you still have to request user consent involving human interaction for each Google Account that you need to access the Google My Business data from and manually authorize your app during OAuth 2.0 flow at least once prior to authenticating with the public/private key pair. You can request user consent using OAuth 2.0 installed applications flow, OAuth 2.0 web server applications flow or via OAuth 2.0 Playground. However, you don’t have to save your retrieved refresh tokens for a service account application. Instead, you specify the user to impersonate by specifying the email address of the user account for access to their Google My Business data when you prepare to make authorized API calls. This is because a service account is an account that belongs to your application instead of an individual end user with a Google Account. Please check out this Accepted Solution for requesting user consent for a service account application.

 

In addition, you should check out the best practices for using Business Accounts with Google My Business locations in the FAQ for sharing access to a large set of locations with your clients between different Google Accounts.

 

Thanks,

Terry

401 Unauthorized when connecting

[ Edited ]
Visitor ✭ ✭ ✭
# 8
Visitor ✭ ✭ ✭

Hi Terry

 

This morning I have (a) downloaded the v3 sample java app you linked to (b) added a gradle plugin to eclipse, (c) used the client_secrets.json from Download JSON that I previously showed you, and (d) used eclipse to compile and run the sample application.

 

It did not pop up a browser window and it did not work, producing this error:

 

Exception in thread "main" com.google.api.client.auth.oauth2.TokenResponseException: 401 Unauthorized

at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)

at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)

at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)

at com.google.api.client.auth.oauth2.Credential.executeRefreshToken(Credential.java:570)

at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)

at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:217)

at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859)

at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)

at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)

at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)

at com.google.sample.MyBusinessClient.listAccounts(MyBusinessClient.java:61)

at com.google.sample.MyBusinessClient.main(MyBusinessClient.java:311)

 

I am using OSX 10.12 and JDK 1.8.0_101-b13.

 

Terry, I've tried three sample apps now - one from your website, one that you pasted in, and one from a complete download and they all fail with the same error.  In all fairness, I think that you have not tried these tests on OS X or there is some problem with my account as it is setup at Google.  You've seen my client_secrets.json and that is the only part of the example app which is customised by me, everything else is exactly as it was when downloaded from your link.

 

Please note that in all three sample apps, the client application authenticates just fine, it is only a problem when calling the `listAccounts` API.

 

 

 

In response to your questions:

Why are you not able to get to the consent screen in a browser window and “Allow” the set of resources and operations set by the scope parameter that an access token permits? 

I don't know - why is your sample app not doing it?

 

Can you tell me whether the platform you are building this Java application on supports access to web browsers? 

Yes - it's OSX 10.12, all updates applied, no security restrictions or outbound firewall, and JDK 1.8.0

 

Are you logged in with a Google Account in a web browser? 

Yes, on Safari.

 

Can you try using an OAuth 2.0 client ID for a Web application and set a redirect URI to http://localhost/Callback and let me know what happens? 

Exactly the same; here's the new client_secrets.json:

 

{

  "web": {

  "client_id": "30580719584-XXXXXXXXXXXXXXXX.apps.googleusercontent.com",

  "project_id": "< Text has been removed to protect private information >",

  "auth_uri": "https://accounts.google.com/o/oauth2/auth",

  "token_uri": "https://accounts.google.com/o/oauth2/token",

  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",

  "client_secret": "XXXXXXXXXXXXXXXX",

  "redirect_uris": [

    "https://developers.google.com/oauthplayground",

    "http://localhost/Callback"

  ]

}

}

 

Can you provide some screenshots from your Eclipse IDE and open browser windows for this matter?

Yes - < Text has been removed to protect private information >

 

I am willing to provide the log in details for the account to you privately if that would help - I can always reset the password once we've fixed it.

 

Regards

John

 

Re: 401 Unauthorized when connecting

[ Edited ]
Google Employee
# 9
Google Employee

Hi @SPAR D,

 

Are you able to list all accounts via the OAuth 2.0 Playground by following the Make a simple HTTP request guide?

 

Your problem might be platform-specific since the instructions we provide on the Google Developers site assume a Linux/Unix environment such as Ubuntu and your development is in a Unix environment on Mac OS X.

 

Please follow the steps below in a Unix environment on the Mac OS X platform and report back to me with the result including screenshots:

  1. Download v3 of the Java sample app.
  2. Extract the Java sample app and place the “google-my-business-api-sample” folder under your Eclipse Workspace.
  3. Import the Java sample app under your Workspace directory as a Gradle project into Eclipse.
  4. Place v3.1 of the Java client library in the "libs" directory under your project root directory and replace the line compile name: 'google-api-services-mybusiness-v3-java-rev20160505-1' with compile name: 'google-api-services-mybusiness-v3p1-java-rev20160926-1' in the build.gradle file.
  5. Execute the program and print the path of your output folder by inserting the line of code in bold in the below Java code snippet to the MyBusinessClient.java file in the Java sample app:

    /**

     * Authorizes the installed application to access user's protected data.

     */

    private static Credential authorize() throws Exception {

      System.out.println(MyBusinessClient.class.getResource("/").getPath());

      // load client secrets

      InputStream secrets = MyBusinessClient.class.getResourceAsStream("/client_secrets.json");

      if (secrets == null) {

        System.out.println("Enter Client ID and Secret from https://code.google.com/apis/console/?api=plus "

    + "into google-my-business-api-sample/src/main/resources/client_secrets.json");

        System.exit(1);

      }

  6. Download your client_secrets.json file from the Credentials page of the Google API Console and place it in the output folder indicated by the path printed above (e.g. Users/[username]/Documents/workspace/google-my-business-api-sample/bin/). Please attach screenshots of Eclipse IDE and the directory where you place your client_secrets.json file.
  7. Execute your program and request user consent during OAuth 2.0 installed application flow. Please attach screenshots of Eclipse IDE and web browser if you fail to perform this step.
  8. Delete the StoredCredential file located at /Users/[username]/.store/mybusiness_sample/ and run the program again if you get the 401 Unauthorized error.

 

I do see some API activities in your account from our internal system.

 

Thanks,

Terry

401 Unauthorized when connecting

[ Edited ]
Visitor ✭ ✭ ✭
# 10
Visitor ✭ ✭ ✭

Hi Terry

 

Are you able to list all accounts via the OAuth 2.0 Playground by following the Make a simple HTTP request guide?

Yes, same as last week, with Firefox.  I've just done it again to confirm

 

Steps 5 & 6

The client_secrets.json is loaded in the right directory, if it had not been then your sample application would not be able to start - it would have reported the error from line 282 "Enter Client ID and Secret from ...".  However I have included a screenshot where I list the contents of the directory and the contents of the file in the bin output directory.

 

 

Step 7

No, it does not pop up anything to ask for user consent.  It goes straight to the 401 exception, same as before.

 

All pictures are in < Text has been removed to protect private information >

 

Regards

John