1

I am an administrator of a Google Apps domain and am trying to write a program that will access the contacts of users on the domain (note that I'm not trying to get at the shared contacts, but the individual contacts for each user, so the shared contacts API won't help).

Initially I was using the "recommended" approach of three-legged auth (show a Web page, the user approves, use that token). That worked great, except if I tried any user other than myself I'd get a 403 forbidden error. So then I read that in this case I wanted two-legged auth, although it's deprecated.

Well, I've come up with this code but now I'm getting a 401/unauthorized credential. I'm not sure if the problem lies in my code or somewhere else (the way I registered the application or something) but I'm having a really hard time finding helpful documentation.

      public static Feed<Contact> MakeRequest(string userId, int numberToRetrieve = 9999)
        {
          var settings = new RequestSettings(Properties.Settings.Default.ApplicationName,
            Properties.Settings.Default.ApiKey, Properties.Settings.Default.ConsumerSecret,
            Properties.Settings.Default.GoogleUserName, Properties.Settings.Default.Domain);
          var cRequest = new ContactsRequest(settings);
          var query = new ContactsQuery(ContactsQuery.CreateContactsUri(userId));
          query.NumberToRetrieve = numberToRetrieve;
          return cRequest.Get(query);
        }
Casey
  • 3,307
  • 1
  • 26
  • 41

2 Answers2

1

With 3 legged OAuth, it only works if the user specifically authenticates via OAuth handshake. If you want to make call on behalf of all your users, you will need use service account for OAuth 2.0.

Check out the drive API code sample, it will give you some ideas how to start with OAuth 2.0 and service account.

https://developers.google.com/drive/service-accounts#use_service_accounts_as_application-owned_accounts

If you are using OAuth 1.0, then you will need use the special parameter xoauth_requestor_id. Here is more information about it:

https://developers.google.com/accounts/docs/OAuth#GoogleAppsOAuth

Emily
  • 1,464
  • 1
  • 9
  • 12
  • I'm having trouble actually following this guide. In particular, when I go to registered apps and select my application (in the cloud console), none of the information about certificates or service accounts is displayed. Instead I just see a section called "OAuth 2.0 Client ID." Am I doing something wrong? – Casey Nov 04 '13 at 21:46
  • I eventually managed to create one (I think) with the old console but I also don't see how to actually apply your example. This describes creating a DriveService and passing it a OAuth2Authenticator object. Well, fine, except ContactService doesn't have a constructor like that. How do I actually make any requests? – Casey Nov 06 '13 at 19:18
0

OK, I finally figured it out. I feel like this probably isn't the way it's supposed to work and I had to dig around the source code of ServiceAccountCredential, but it works. I actually have this split out a bit, but for the sake of clarity here it is altogether.

I also switched from Google.Apis.Authentication to Google.Apis.Auth.

    public static Feed<Contact> MakeRequest(string userId, int numberToRetrieve = 9999)
    {
        var serviceCredential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(ServiceEmail)
        {
            Scopes = new[] { @"https://www.google.com/m8/feeds/" },
            User = userId,
        }.FromCertificate(Certificate));

        var reqAccessTokenInfo = serviceCredential.GetType()
          .GetMethod("RequestAccessToken", BindingFlags.Instance | BindingFlags.NonPublic);
        var task = (Task<bool>) reqAccessTokenInfo.Invoke(serviceCredential, parameters: new object[] {new CancellationToken()});
        task.Wait();

        var settings = new RequestSettings(Properties.Settings.Default.ApplicationName, serviceCredential.Token.AccessToken);
        var cRequest = new ContactsRequest(settings);
        var query = new ContactsQuery(ContactsQuery.CreateContactsUri(userId)) { NumberToRetrieve = numberToRetrieve };

        return cRequest.Get<Contact>(query);
    }
Casey
  • 3,307
  • 1
  • 26
  • 41