Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Integrating with Google Admin SDK in C#

I'm currently trying to integrate with the Google Admin SDK via C# so we can manage users via our own system. However, when running the project I get the error: Unauthorized Client.

Things I have already done via a super admin account:

  • Setup Service Account
  • Enabled GSuite domain-wide delegation on service Account
  • Enabled API Access
  • Added the Service Accounts client ID to API Client Access with the scope (https://www.googleapis.com/auth/admin.directory.user)

Here's the code that i'm using.

ServiceAccountCredential credential = new ServiceAccountCredential(
                new ServiceAccountCredential.Initializer(_googleServiceSettings.Client_Email)
                {
                    ProjectId = _googleServiceSettings.Project_Id,
                    User = "[email protected]",
                    Scopes = new[] { DirectoryService.Scope.AdminDirectoryUser }
                }.FromPrivateKey(_googleServiceSettings.Private_Key));

            var service = new DirectoryService(new BaseClientService.Initializer
            {
                HttpClientInitializer = credential,
                ApplicationName = "Test API"
            });

            var request = service.Users.Get("[email protected]");
            var result = await request.ExecuteAsync();

The full error i'm getting is

An unhandled exception has occurred while executing the request. Google.Apis.Auth.OAuth2.Responses.TokenResponseException: Error:"unauthorized_client", Description:"Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested.", Uri:""

like image 701
niko619 Avatar asked May 01 '19 15:05

niko619


2 Answers

Example code that will print some information about a user.

The important item is the class Google.Apis.Admin.Directory.directory_v1.Data.User

Documentation link.

Your error is caused by not creating the credentials correctly. Usually, an issue with scopes when creating the credentials. I am assuming that you have Domain-Wide Delegation setup correctly for the service account.

I am also assuming that the user that you are impersonating is a G Suite Super Admin. If not, you will see a 403 error for service.Users.Get().

The file service_account.json is a normal JSON file that you downloaded from the Google Console (or created with gcloud).

The user [email protected] is the email address for the G Suite user for which information will be displayed.

The user [email protected] is the G Suite Super Admin.

using Google.Apis.Auth.OAuth2;
using Google.Apis.Admin.Directory.directory_v1;
using Google.Apis.Admin.Directory.directory_v1.Data;
using Google.Apis.Services;
using System;
using System.IO;

// dotnet add package Google.Apis.Admin.Directory.directory_v1
// Tested with version 1.39.0.1505

// Google.Apis.Admin.Directory.directory_v1.Data.User
// https://developers.google.com/resources/api-libraries/documentation/admin/directory_v1/csharp/latest/classGoogle_1_1Apis_1_1Admin_1_1Directory_1_1directory__v1_1_1Data_1_1User.html

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            // Service Account with Domain-Wide delegation
            var sa_file = "service_account.json";

            // G Suite User to impersonate
            var user_email = "[email protected]";

            // G Suite User to get information about
            var gs_email = "[email protected]";

            // Scopes
            var scopes = "https://www.googleapis.com/auth/admin.directory.user";

            var credential = GoogleCredential.FromFile(sa_file)
                        .CreateScoped(scopes)
                        .CreateWithUser(user_email);

            // Create Directory API service.
            var service = new DirectoryService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential
            });

            try {
                var request = service.Users.Get(gs_email);

                var result = request.Execute();

                Console.WriteLine("Full Name: {0}", result.Name.FullName);
                Console.WriteLine("Email:     {0}", result.PrimaryEmail);
                Console.WriteLine("ID:        {0}", result.Id);
                Console.WriteLine("Is Admin:  {0}", result.IsAdmin);
            } catch {
                Console.WriteLine("User not found.");
            }
        }
    }
}
like image 84
John Hanley Avatar answered Nov 07 '22 13:11

John Hanley


If you want to use the service account you can authenticate with below code.

String serviceAccountEmail = "yourserviceaccountmail";
public GmailService GetService(string user_email_address)
    {

        var certificate = new X509Certificate2(@"yourkeyfile.p12", 
"notasecret", X509KeyStorageFlags.Exportable);

        ServiceAccountCredential credential = new ServiceAccountCredential(
                   new ServiceAccountCredential.Initializer(serviceAccountEmail)
                   {

                       User = user_email_address,
                       Scopes = new[] { GmailService.Scope.MailGoogleCom }
                   }.FromCertificate(certificate));

        GmailService service = new GmailService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
            ApplicationName = AppName,
        });

        return service;
    }

You can list users using this service. Its work for me.

And you can list userlist with below code. ( with DirectoryService)

public Users GetDirService()//UserList with DirectoryService
    {
        string Admin_Email = "yoursuperadminemail";
        string domain = "yourdomain.com";
        try
        {
            var certificate = new X509Certificate2(@"yourkeyfile.p12", "notasecret", X509KeyStorageFlags.Exportable);

            ServiceAccountCredential credentialUsers = new ServiceAccountCredential(
            new ServiceAccountCredential.Initializer(serviceAccountEmail)
            {
                Scopes = new[] { DirectoryService.Scope.AdminDirectoryUser },
                User = Admin_Email,
            }.FromCertificate(certificate));

            var serviceUsers = new DirectoryService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credentialUsers,
                ApplicationName = AppName,
            });
            var listReq = serviceUsers.Users.List();
            listReq.Domain = domain;
            Users users = listReq.Execute();
            return users;
        }
        catch (Exception ex)
        {
            MessageBox.Show("your mail address must be super admin authorized.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
            return null;
        }

    }
like image 45
Muammer Avatar answered Nov 07 '22 13:11

Muammer