Reputation: 12651
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.
Upvotes: 1
Views: 623
Reputation: 12651
This seemed to start working for no reason. While I'm tempted to say it happened by magic, it is possible there is another explanation.
As vibronet explains, you need to add application permissions to the app. Once this is done, it will be necessary for the tenant administrators to sign up to the consent framework once again. I did this in a separate browser, as an administrator of the tenant whose directory the app was supposed to be reading. However, I did so within a couple of minutes of setting the application permissions. The app started working again a day later, when I went through the consent framework again.
If you run into a similar situation to the one I've described, and you need to change the application permissions drop-down, give it a few minutes to propagate before your tenants go through the consent framework. (I'm assuming you'll have at least one client tenant of which you're an administrator, so that you can test your app.)
Upvotes: 1
Reputation: 7394
I think the question is misleading in its current form. You can obtain tokens both as a user and as an application identity- and you can do both things using both AcquireToken
and AcquireTokenSilent
. Applications cans be configured in the directory to request different privileges depending on whether they access resources with their application identity or as delegated access with a user identity.
In your example you are obtaining tokens as a user in your AcquireTokenSilent
call and as an app in the AcquireToken
one, and the different privileges you configured in your app for the two cases lead to the difference in behavior you observed. However, that difference is dictated by the overloads you used, not by any inherent difference between AcquireTokenSilent
and AcquireToken
.
You can configure your app to have access to the Azure AD Graph API via the application permissions drop down (as opposed to the delegated ones) in the portal, however note that you will need to be a tenant admin to be able to do so.
Upvotes: 3