-->

Accessing Google Contacts Api via OAuth 2.0 and pr

2019-03-29 21:37发布

问题:

I am currently implementing access to Google Contacts via OAuth 2.0 and a so called Service Account. The service account is generated for an ordinary user like "My.Name@gmail.com".

The code to generate the OAuth 2.0 credentials is:

public static GoogleCredential getCredentials() throws GeneralSecurityException, IOException {
    GoogleCredential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
            .setJsonFactory(JSON_FACTORY)
            .setServiceAccountId(SingleUserCredentials.SERVICE_ACCOUNT_EMAIL)
            .setServiceAccountScopes("https://www.google.com/m8/feeds")
            .setServiceAccountPrivateKeyFromP12File(new File(SingleUserCredentials.SERVICE_ACCOUNT_PKCS12_FILE_PATH))
            .build();
    credential.refreshToken();
    return credential;
}

I am then trying to retrieve the contacts via:

    ContactsService myService = new ContactsService(
            "myApp");

    myService.setOAuth2Credentials(getCredentials());

    URL feedUrl = new URL("https://www.google.com/m8/feeds/contacts/default/full");
    Query myQuery = new Query(feedUrl);
    ContactFeed resultFeed = myService.query(myQuery, ContactFeed.class);
    // Print the results

    for (ContactEntry entry : resultFeed.getEntries()) {
        System.out.println(entry.getName().getFullName().getValue());
        System.out.println("Updated on: " + entry.getUpdated().toStringRfc822());
    }

The problem is that I do not get any a single contact from my account. The feed is always empty. There is no error. Nothing.

When accessing a Google Apps managed domain via the same approach it works nicely.

I am wondering if the Contacts Api supports OAuth 2.0 for ordinary (aka @gmail.com) accounts when using a p12 key file and a service account.

回答1:

I ran into that same problem myself.

I tried both the email address that I received when I setup the key and the email address of a domain administrator.

When I use the email from the key setup, I don't receive anything at all -- no warnings, no exceptions, and no data.

When I use the email address of a domain administrator, I receive an exception:

com.google.api.client.auth.oauth2.TokenResponseException: 400 OK
     [java] {
     [java]   "error" : "invalid_grant"
     [java] }
     [java] Feb 5, 2013 5:16:48 PM com.google.appengine.repackaged.org.apache.http.impl.client.DefaultRequestDirector handleResponse
     [java] WARNING: Authentication error: Unable to respond to any of these challenges: {}
     [java] Feb 5, 2013 5:16:48 PM com.google.apphosting.utils.jetty.JettyLogger warn
     [java] WARNING: /
     [java] java.lang.NullPointerException: No authentication header information

...

So, I figured that the domain administrator's email address wasn't what I needed.

Next, I Googled around for a while before finding this page:

http://javadoc.google-api-java-client.googlecode.com/hg/1.13.2-beta/com/google/api/client/googleapis/auth/oauth2/GoogleCredential.html

I saw in there getServiceAccountUser (). The description of the field was:

Returns the email address of the user the application is trying to impersonate in the service account flow or null for none or if not using the service account flow.

Sure enough, there's a corresponding setServiceAccountUser (String) which accepts the username (email address) of the user you're using the service account to impersonate.

I set that field to an appropriate value and I was able to proceed.

In retrospect, it all makes sense -- if I don't supply an account that I'm trying to work from, I can't pull down the contacts for that account.



回答2:

It is currently not possible to access Contacts using a service account as it is not supported in the Google APIs Console at Google APIs Console.

See also: Service Accounts

Second, it would only work with a Google managed domain because the Admin of the domain must grant access to the service account via the process below:

Delegate domain-wide authority to your service account

The service account that you created now needs to be granted access to the Google Apps domain’s user data that you want to access. The following tasks have to be performed by an administrator of the Google Apps domain:

  1. Go to your Google Apps domain’s control panel. The URL should look like: "www.google.com/a/cpanel/mydomain.com"

  2. Go to Advanced tools... > Manage third party OAuth Client access.

  3. In the Client name field enter the service account's Client ID.

  4. In the One or More API Scopes field enter the list of scopes that your application should be granted access to.

  5. Click the Authorize button.



回答3:

I've run across this very same error today but have given up on using Service Accounts for now, which I assume is not currently supported in the Contacts API. And so I am using Contacts API v3 with OAuth 1.0 and am getting the expected results.

 ContactsService contactsService = new ContactsService(APPLICATION_NAME);
 contactsService.setUserCredentials(CLIENT_USERNAME, CLIENT_SECRET);

 URL contactFeedURL = new URL("https://www.google.com/m8/feeds/contacts/default/full");
 Query contactFeedQuery = new Query(contactFeedURL);

 ContactFeed contactFeed = contactsService.getFeed(contactFeedQuery, ContactFeed.class);