niko619
niko619

Reputation: 453

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:

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:""

Upvotes: 7

Views: 3955

Answers (3)

niko619
niko619

Reputation: 453

Ok I have solved the issue.

Adding the following scope via the security settings within the Google Portal has solved the issue. This is strange as their own example doesn't require this scope to be added ad their documentation doesn't say it's required for this method.

https://www.googleapis.com/auth/admin.directory.group

Upvotes: 1

Muammer
Muammer

Reputation: 404

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;
        }

    }

Upvotes: 4

John Hanley
John Hanley

Reputation: 81356

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

Upvotes: 6

Related Questions