Title: Can't list users with Google Directory API Admin SDK
Tags: c#;google-api;google-admin-sdk;google-api-dotnet-client
Question: I'm trying to use the AdminService to manage my domain's users and groups, but I'm stuck with a simple request to get all the users of my domain. There is the code in C#:
public Users GetAllUsers()
var provider = new AssertionFlowClient(
GoogleAuthenticationServer.Description,
new X509Certificate2(privateKeyPath, keyPassword, X509KeyStorageFlags.Exportable))
ServiceAccountId = serviceAccountEmail,
Scope = AdminService.Scopes.AdminDirectoryUser.GetStringValue()
};
var auth = new OAuth2Authenticator<AssertionFlowClient&gt;(provider, AssertionFlowClient.GetState);
m_serviceGroup = new AdminService(new BaseClientService.Initializer()
Authenticator = auth,
});
var request = m_serviceUser.Users.List();
request.Domain = m_domainName;
return request.Fetch();
I'm getting an exception when Fetch() that says:
Code: 403
Message: Not Authorized to access this resource/api
Error: {Message[Not Authorized to access this resource/api] Location[ - ] Reason[forbidden] Domain[global]}
I've followed the instructions here to have enabled API access, and also authorized my service account in domain control panel:
[Security]-&gt;[Advanced Setting]-&gt;[Authentication]-&gt;[Manage third party OAuth Client access]
with scopes:
https://www.googleapis.com/auth/admin.directory.group
https://www.googleapis.com/auth/admin.directory.user
Admin SDK Service is also enabled in API control panel.
I tried the code to use the DriveService and successfully listed/created/deleted files without any problem, so the authentication part of the code should be alright. I couldn't figure out what else needs to be configured or if there is any other problems with my code.
Thanks for any help.

Here is the accepted answer: As described on the page:
Manage API client access
Developers can register their web applications and other API clients with Google to enable access to
data in Google services like Calendar. You can authorize these
registered clients to access your user data without your users having to individually give consent or their passwords. Learn more
The service account needs to act on behave of a user, so when initializing the client the ServiceAccountUser needs to be assigned.
var provider = new AssertionFlowClient(
GoogleAuthenticationServer.Description,
new X509Certificate2(privateKeyPath, keyPassword, X509KeyStorageFlags.Exportable))
{
ServiceAccountId = serviceAccountEmail,
Scope = AdminService.Scopes.AdminDirectoryUser.GetStringValue(),
ServiceAccountUser = domainManangerEmail
};
Edit: AssertionFlowClient is deprecated, the following should work:
var cert = new X509Certificate2(privateKeyPath, keyPassword, X509KeyStorageFlags.Exportable);
var serverCredential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new []{DirectoryService.Scope.AdminDirectoryUser},
User = domainManagerAccountEmail
}.FromCertificate(cert));
var dirService = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = serverCredential
});
Comment for this answer: I was trying to list the devices, and was getting the same error. They don't explicitly say you need to set the admin email address in the ServiceAccountCredential. Setting an admin email, solved the problem. Thanks!
Comment for this answer: I did exactly as the above but got
`Error:"unauthorized_client", Description:"Unauthorized client or scope in request.", Uri:""`
instead.. any ideas
Comment for this answer: Later figured out that was the problem. Thanks alot
Comment for this answer: @Ody, have you enabled the API access and granted permissions to the account that you are using?
Comment for this answer: Am I crazy? AssertionFlowClient is not installed in any nuget installation of google API's I can find.
Comment for this answer: This doesn't work for me, when I add ServiceAccountUser (who is a domain super user) it then errors out with: Protocol Exception: Error occurred while sending a direct message or getting the response. The underlying oauth response is: 1f
"error" : "access_denied"
Comment for this answer: Found my answer... 2LO is required. https://developers.google.com/drive/delegation#delegate_domain-wide_authority_to_your_service_account

Here is another answer: This code works for me
static void GettingUsers()
String serviceAccountEmail = "wesley90@example.com";
var certificate = new X509Certificate2(@"xxxxx.p12", "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
Scopes = new[] { DirectoryService.Scope.AdminDirectoryUser},
User = "your USER",
}.FromCertificate(certificate));
var service = new DirectoryService(new BaseClientService.Initializer()
HttpClientInitializer = credential,
ApplicationName = "name of your app",
var listReq = service.Users.List();
listReq.Domain = "your domain";
Users allUsers = listReq.Execute();
int counter = 0;
foreach(User myUser in allUsers.UsersValue){
Console.WriteLine("*" + myUser.PrimaryEmail);
counter++;
Console.WriteLine(counter);
Console.ReadKey();
For more information, Please take a look in Directory API: Users list.
There are Limits and Quotas.

Here is another answer: We will need to give the service ID that we are using the super admin or the right privileges to get pass this error.
Hope this helps.
-Venu Murthy

Here is another answer: Work for me.
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 Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
class Program
static string[] Scopes = { DirectoryService.Scope.AdminDirectoryUserReadonly};
static string ApplicationName = "API G Suite implementation guid by amit";
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials1/admin-directory_v1-dotnet-quickstart.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
Console.WriteLine("Credential file saved to: " + credPath);
}
// Create Directory API service.
var service = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
////// Define parameters of request.
UsersResource.ListRequest request = service.Users.List();
request.Customer = "my_customer";
request.MaxResults = 10;
request.OrderBy = UsersResource.ListRequest.OrderByEnum.Email;
////// List users.
IList<User&gt; users = request.Execute().UsersValue;
Console.WriteLine("Users:");
if (users != null &amp;&amp; users.Count &gt; 0)
{
foreach (var userItem in users)
{
Console.WriteLine("{0} ({1})", userItem.PrimaryEmail,
userItem.Name.FullName);
}
}
else
{
Console.WriteLine("No users found.");
}
Console.Read();
}

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 4, 'CommentCount': 0, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2013:00:06/10/13', 'FavoriteCount': 4.0, 'PostTypeId': 1, 'Tags': '<c#><google-api><google-admin-sdk><google-api-dotnet-client>', 'Title': "Can't list users with Google Directory API Admin SDK", 'ViewCount': 10407, 'id': 17033593, 'user_AboutMe': '', 'user_AccountId': 2661162.0, 'user_DisplayName': 'zhywu', 'user_Reputation': 952.0, 'user_Views': 54.0, 'user_id': 2300810.0}}