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

Issues with using OAuth & Service Account - 401 and 404 error received

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

 

dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
credential = authorize();

private static Credential authorize() throws Exception {
                // Creates an InputStream to hold the client ID and secret.
                InputStream secrets = null;

                try {
                        secrets = Main.class.getResourceAsStream("/client_secrets.json");
                } catch (Exception e) {
                        logger.error("GoogleMyBusiness - error while reading the secrets stream " + e);
                }

                // Prompts the user if no credential is found.
                // TODO : Appropriate error handling
                if (secrets == null) {
                        if (logger.isDebugEnabled()){
                                logger.debug("Enter Client ID and Secret from Google API Console into WEB-INF/classes/client_secrets.json");
                        }
                        throw new Exception("Enter Client ID and Secret from Google API Console into WEB-INF/classes/client_secrets.json");
                }

                // Uses the InputStream to create an instance of GoogleClientSecrets.
                GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(secrets));

                // TODO : Appropriate error handling
                if (clientSecrets.getDetails().getClientId().startsWith("Enter") || clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
                        if (logger.isDebugEnabled()){
                                logger.debug("Enter Client ID and Secret from Google API Console into WEB-INF/classes/client_secrets.json");
                        }
                        throw new Exception("Enter Client ID and Secret from Google API Console into WEB-INF/classes/client_secrets.json");
                }

                // Sets up the authorization code flow.
                GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, JSON_FACTORY, clientSecrets, 
                                Collections.singleton("https://www.googleapis.com/auth/plus.business.manage")).setDataStoreFactory(dataStoreFactory).build();

                // Returns the credential.
                return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
        }

I have the exact same problem. The above code works well in my DEV environment. I get a google screen to enter the email which has the access to locations & then it redirects me back to http://localhost:SOME_PORT/ and I can view/update the locations.

 

Now we moved to QA. Firstly, the QA server is not accessible via internet and doesn't have direct internet connectivity and we have to go via the proxy. 

So I added the below code 

                        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(PROXY_IP, Integer.parseInt(PROXY_PORT)));
                        httpTransport = new NetHttpTransport.Builder().setProxy(proxy).build();

Now I get a message in the standard system out console of my JAVA application 

Please open the following URL in your browser:
  https://accounts.google.com/o/oauth2/auth?client_id=*****&redirect_uri=http://localhost:50835/Callback&response_type=code&scope=https://www.googleapis.com/auth/plus.business.manage

Now I'm not sure why there is a change in behaviour here. I even tried adding my QA host to OAuth client ID's Authorised redirect URIs , but no luck.

 

Nevertheless I tried to switch to Service Accounts now. And changed my code as 

                        credential = new GoogleCredential.Builder()
                                    .setTransport(httpTransport)
                                    .setJsonFactory(JSON_FACTORY)
                                    .setServiceAccountId(emailAddress)
                                    .setServiceAccountPrivateKeyFromP12File(new File("$FILE.p12"))
                                    .setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/plus.business.manage"))
                                    //.setServiceAccountUser("$USEREMAILADDRESS")
                                    .build();
                        credential.refreshToken();
                        
                    if (!credential.refreshToken()) {
                        System.out.println("NO REFRESH TOKEN **** \n\n ");
                        throw new RuntimeException("Failed OAuth to refresh the token");
                    } else {
                        System.out.println("YES REFRESH TOKEN **** \n\n ");
                    }

 

I tried both ways, using the setServiceAccountUser method and commenting out.

If I use setServiceAccountUser method above, I don't get the access token and 401 Unauthorized is displayed 

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.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:384)
        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:868)
        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.ee.maps.mybusiness.GoogleMyBusiness.listLocations(GoogleMyBusiness.java:192)

 If I comment out setServiceAccountUser method above, I DO get the access token, but 404 Not Found is displayed 

om.google.api.client.googleapis.json.GoogleJsonResponseException:  404 Not Found
{
  "code" : 404,
  "message" : "Requested entity was not found.",
  "status" : "NOT_FOUND"
}
        at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:146)
        at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
        at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:321)
        at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1065)
        at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnpars

 

I had thought it would be a real easy transition from DEV to QA & then to PROD, but now I'm struggling here in QA. 

Could you please help me with this? 

1 Expert replyverified_user

Re: Issues with OAuth & using Service Account - 401 and 404 error received

Google Employee
# 2
Google Employee

Hi @Liam P,

 

We are still trying to replicate the issue you reported and will follow up soon with a response. Thanks for your patience.

 

Thanks,

The Google My Business API Team

Issues with OAuth & using Service Account - 401 and 404 error received

Visitor ✭ ✭ ✭
# 3
Visitor ✭ ✭ ✭

Hi @Shalini S,

 

Thank you. I'm eagerly waiting

Issues with OAuth & using Service Account - 401 and 404 error received

Visitor ✭ ✭ ✭
# 4
Visitor ✭ ✭ ✭

Hi @Shalini S,

 

Imran is the developer who is working on this.

Re: Issues with using OAuth & Service Account - 401 and 404 error received

Google Employee
# 5
Google Employee

Hi @Liam P & @A K I,

 

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.
  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();
}

 

I hope this helps!

 

Thanks,

Shalini, Google My Business API team

Issues with using OAuth &amp; Service Account - 401 and 404 error received

[ Edited ]
Visitor ✭ ✭ ✭
# 6
Visitor ✭ ✭ ✭

Hi @Shalini S,

 

Thanks for the detailed response. However, I had already tried setting up the port & host as required. I tried with both the below statements.

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

 

LocalServerReceiver.Builder().setHost("HOSTNAME").build()).authorize("user");

 

And I also included https://maps-stg-admin.eead.eeint.co.uk/Callback in the authorized Redirect URI's, but it doesn't work.

 

I still see this in the System Out logs

 

Please open the following URL in your browser:
  https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force&client_id=119578...http://localhost:9505/Callback&response_type=code&scope=https://www.googleapis.com/auth/plus.business.manage

 

I'm failing to understand why this doesn't open up a new tab directly in our QA environment like it does in our DEV

Issues with using OAuth &amp; Service Account - 401 and 404 error received

[ Edited ]
Visitor ✭ ✭ ✭
# 7
Visitor ✭ ✭ ✭

Further to this, when I use

LocalServerReceiver.Builder().setHost("HOSTNAME").build()).authorize("user");

 

I get the below error

java.io.IOException: java.net.BindException: Cannot assign requested address
    at com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver.getRedirectUri(LocalServerReceiver.java:107)
    at com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp.authorize(AuthorizationCodeInstalledApp.java:71)