'Accessing users account with service account

We need to use an API to verify if a certain user exists as managed account (it means, that belongs to our Google Domain organization).

GSuite adminSDK performs that operation, however, it requires OAuth2 authentication, authorized by an authenticated user - https://developers.google.com/admin-sdk/reports/v1/guides/authorizing .

My question is, if there any way to use that API with service account, or any other methos to retrieve this information with service account, since it would be used in a Server-2-Server scenario.

Thanks, Vasco



Solution 1:[1]

As you may know, Service Accounts don't belong to an individual end user, but to an application. An administrator of a G Suite domain, though, can authorize the Service Account to access user data, that is, to impersonate users in the domain. This is called domain-wide delegation.

To achieve this, go to the Admin console and follow the steps specified here.

Reference:

Solution 2:[2]

Since this is completely not obvious - the docs "hint" at this, but don't spell it out and I had trouble finding any specific examples that worked. They all kept returning this error:

Google.GoogleApiException: 'Google.Apis.Requests.RequestError
Not Authorized to access this resource/api [403]
Errors [
    Message[Not Authorized to access this resource/api] Location[ - ] Reason[forbidden] Domain[global]
]

The basic issue that the service account MUST impersonate another user. It's mentioned in this link at the bottom, highlighted in blue:

https://developers.google.com/admin-sdk/directory/v1/guides/delegation

Only users with access to the Admin APIs can access the Admin SDK Directory API, therefore your service account needs to impersonate one of those users to access the Admin SDK Directory API. Additionally, the user must have logged in at least once and accepted the Google Workspace Terms of Service.

But it just wasn't clicking as to how I was supposed to do that - was this some setting hiding in one of the admin consoles? No - you pass this as part of your initial connection.

So just to put the instructions in one place and hopefully save someone else the same headache, these were the steps:

Then I created a .NET Core console app and installed these NuGet packages:

  • Google.Apis
  • Google.Apis.Auth
  • Google.Apis.Admin.Directory.directory_v1

Here's an ugly proof of concept with everything working:

using System;
using System.IO;
using System.Net;

using Google.Apis.Admin.Directory.directory_v1;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;

namespace GoogleDirectoryTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var dirService = GetDirectoryService(@"C:\tmp\google-cred-sample-12345abdef.json", "[email protected]", "My App Name");
            var list = dirService.Users.List();
            list.Domain = "mydomainhere.com";
            var users = list.Execute();

            foreach (var user in users.UsersValue)
            {
                Console.WriteLine($"{user.Name.FullName}");
            }

            Console.ReadKey();
    }

    static DirectoryService GetDirectoryService(string keyfilepath, string impersonateAccount, string appName)
    {            
        using (var stream = new FileStream(keyfilepath, FileMode.Open, FileAccess.Read))
        {
            var credentials = GoogleCredential.FromStream(stream).CreateWithUser(impersonateAccount);
            if (credentials.IsCreateScopedRequired)
                credentials = credentials.CreateScoped(new[] { DirectoryService.Scope.AdminDirectoryUserReadonly });

            var service = new DirectoryService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credentials,
                ApplicationName = appName,
            });
            return service;
        }
    }

Hopefully this saves someone else some headaches.

Solution 3:[3]

A service account is a special kind of account used by an application, rather than a person.

You can use a service account to access data or perform actions by the robot account itself, or to access data on behalf of Google Workspace or Cloud Identity users.

Prerequisites:

  • A Google Cloud Platform project

    With the Admin SDK API enabled service account with domain-wide delegation.
  • A Google Workspace domain.

    With account in that domain with administrator privileges.
  • Visual Studio 2013 or later

Step 1: Set up the Google Cloud Platform project

  • Create Google Cloud project

    A Google Cloud project is required to use Google Workspace APIs and build Google Workspace add-ons or apps. If you don't already have a Google Cloud project, refer to: How to create a Google Cloud project

  • Enable Google Workspace APIs

    Before using Google APIs, you need to enable them in a Google Cloud project.

    To Enable Google Workspace APIs refer to: How to Enable Google Workspace APIs

    For this example you are enabling the the Admin SDK Directory API with the data scope /auth/admin.directory.user.readonly.

  • Create Service Account with domain-wide delegation

    To create service account refer to: How to create service account?

    In the Domain wide delegation pane, select Manage Domain Wide Delegation.

  • Download Service Account private key (p12 format)

    Download p12 file contains the private key for your Service Account.

Step 2: Set up the Google Workspace

  • Enable API access in the Google Workspace domain with

    To enable API access in Google Workspace domain, refer to: how to enable API access

  • Delegating domain-wide authority to the service account

    To call APIs on behalf of users in a Google Workspace organization, your service account needs to be granted domain-wide delegation of authority in the Google Workspace Admin console by a super administrator account

    To delegating domain-wide authority in Google Workspace domain, refer to: How to Delegating domain-wide authority to the service account

Step 3: Prepare Visual Stodio project -

  • Create a new Visual C# Console Application (.NET Framework) project in Visual Studio.

  • Open the NuGet Package Manager Console, select the package source nuget.org, and run the following commands:

    • Install-Package Google.Apis.Auth

    • Install-Package Google.Apis.Admin.Directory.directory_v1

Step 4: Add code

Full example at GitHub

List top 10 users alias from Google Workspace Domain

  /// <summary>
  /// Example how to list all users from google workspace domain, using a service account (user impersonation).
  /// </summary>
  internal class Program {
    static void Main(string[] args) {
      // Scope for only retrieving users or user aliases.
      string[] _scopes = {
        "https://www.googleapis.com/auth/admin.directory.user.readonly"
      };

      var _paramters = new SACInitializeParameters(
        // The service account ID (typically an e-mail address like: *@*iam.gserviceaccount.com)
        serviceAccountId: "[Service Account ID]",
        // The full path; name of a certificate file
        x509CertificateFilePath: "[X509 Certificate File]",
        // The email address of the user you trying to impersonate
        impersonateEmail: "[User Email]",
        // The scopes which indicate API access your application is requesting
        scopes: _scopes);


      using (var directoryService = DirectoryServiceFactory.CreateDirectoryService(_paramters)) {
        // Retrieves a paginated list of either deleted users or all users in a domain.
        var request = directoryService.Users.List();
        // The unique ID for the customer's Google Workspace account
        // the `my_customer` alias represent current identety account's
        request.Customer = "my_customer";
        request.MaxResults = 10;
        var response = request.Execute();

        foreach (var user in response.UsersValue) {
          System.Console.WriteLine($"{user.Name.FullName}, {user.PrimaryEmail}, {user.Id}");
        }
      }
    }
  }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Paul Mrozowski
Solution 3 Ilan Laloum