I'm working with the Azure Graph API, and I notice that I can't read the directories that have signed up via the consent framework.
Everything works for user-level permissions. That is, with
private async Task<string> AcquireGraphApiTokenAsync(string objectId, AuthenticationContext authContext)
{
var result = await authContext.AcquireTokenSilentAsync(
GraphUrl, _clientCredential, new UserIdentifier(objectId, UserIdentifierType.UniqueId));
return result.AccessToken;
}
I can read client data as follows:
var authority = string.Format(CultureInfo.InvariantCulture, AadInstance, tenantId);
var authContext = new AuthenticationContext(authority, new TokenDbCache(userObjectId));
var graphServiceRoot = GraphUrl + '/' + tenantId;
var graphClient = new ActiveDirectoryClient(new Uri(graphServiceRoot), async () => await AcquireGraphApiTokenAsync(userObjectId, authContext));
try
{
var adUser = await graphClient.Me.ExecuteAsync();
...
}
Sometimes, however, I want to run a similar process in a daemon, and this is where I fall into trouble. In this case, I need to use my application identity:
private void AuditDirectories(ClientCredential clientCredential, IEnumerable<AzureActiveDirectory> directories)
{
foreach (var directory in directories)
{
var authContext = new AuthenticationContext(string.Format(CultureInfo.InvariantCulture, AadInstance, directory.Domain));
var result = authContext.AcquireToken(GraphUrl, clientCredential);
var graphServiceRoot = string.Format("{0}/{1}", GraphUrl, directory.TenantId);
var graphClient = new ActiveDirectoryClient(new Uri(graphServiceRoot), () => Task.FromResult(result.AccessToken));
foreach (var user in _userQuery.Office365Users(directory))
{
CheckThatAccountExistsAndIsEnabled(graphClient, user);
}
}
}
The incoming clientCredential
argument is obtained from the Client ID and Client Secret of my multi-tenant app.
My app has the delegated permissions "Read Directory Data" and "Enable sign-on and read user's profiles". It has the application permissions "Read Directory Data" and "Read and Write Directory Data", although I don't really need the latter. However, this does not allow me to query the Graph API. All user queries, such as
graphClient.Users.Where(u => u.DisplayName == userName).ExecuteAsync().Result.CurrentPage.FirstOrDefault()
throw the error "Insufficient privileges to complete the operation".
It looks like delegated access with a user identity is working without any problems, but access with application identity is failing, despite the fact that I have set the application permissions at the app level.