Graph API Access Denied after giving all required permissions - azure-active-directory

I am using Graph API to consume some services (cloud meetings, OneDrive) on-behalf the users using Web API.
must services are working fine but some services are giving the error accessDenied even after I gave all required permissions
example: getting user's following items.

Finally, I found that the Graph Explorer is not giving full access, I just skipped it and I gave all the required permissions, I tried from my C# code it's working fine
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var items = await graphClient.Users["example#sample.test"].Drive.Items
.Request()
.GetAsync();
Update
there are some services I added the permission from PowerShell

Related

How to get the resourceId when granting an appRoleAssignment to a ServicePrincipal in Azure AD?

I am trying to Grant Admin Consent of a API in an Azure AD application through Graph API. I created the App, created its Client Secret, then created a Service Principal to which I want to add AppRoleAssignment.
The API call to do so requires three attributes in the body (Documentation)
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var appRoleAssignment = new AppRoleAssignment
{
PrincipalId = {Input the Service Principal Id},
ResourceId = {? Where to get this value?},
AppRoleId = {Input the App role of the API I added to my Azure AD App}
};
await graphClient.ServicePrincipals["{servicePrincipal-id}"].AppRoleAssignments
.Request()
.AddAsync(appRoleAssignment);
My question is where to get the ResourceId from? Knowing that this is different from one tenant to the other.
Please note that if I grant the admin consent manually, then run this API call
var appRoleAssignments = GraphAppClient.ServicePrincipals[servicePrincipalId].AppRoleAssignments.Request().GetAsync().Result;
Then revoke the consent, get the ResourceId from what the API returned, and then use it in the original call, the admin consent works fine.
The documentation for the appRoleAssignment resource type says the following about the resourceId property:
The unique identifier (id) for the resource service principal for which the assignment is made.
A good approach to find a service principal in a tenant is to search the servicePrincipals collection, filtering on the appId or servicePrincipalName properties.For example, to search for the Microsoft Graph service principal by its identifier URI:
GET https://graph.microsoft.com/v1.0/servicePrincipals
?$filter=servicePrincipalNames/any(n:n eq 'https://graph.microsoft.com')
Or to find it by its appId:
GET https://graph.microsoft.com/v1.0/servicePrincipals
?$filter=appId eq '00000003-0000-0000-c000-000000000000'
With the Microsoft Graph SDK for .NET, this would look something like this:
var r = await graphServiceClient.ServicePrincipals
.Request()
.Filter("appId eq '00000003-0000-0000-c000-000000000000'")
.GetAsync();
Using Microsoft Graph PowerShell, things look very similar:
$r = Get-MgServicePrincipal -Filter "appId eq '00000003-0000-0000-c000-000000000000'"
Using the Azure portal, each app under "Enterprise apps" corresponds to a service principal, and the "Properties" page shows its object ID.
(Once you have the service principal, you can use its appRoles collection to see the list of app roles it publishes, often useful to get the app role's id, which you'll need for the appRoleId property.)
I ended up figuring it out. The resourceId of every set of permission you are trying to add is the objectId of the app in Entreprise Applications. It sounds very confusing, but if you are trying to add Graph API permissions, you need to go to enterprise applications, find GraphAPI, and then find its ObjectId. That is your resourceId.

Can't call Graph API calendars from a daemon application

I am new to the Graph API and would like to call my outlook calendars with the event schedules from a daemon application.
When I login to Microsoft account using the email I use to login to Azure I can see my calendar fine and I can also call the Web API using the Graph Explorer.
E.g. the Graph Explorer call:
https://graph.microsoft.com/v1.0/me/calendars
returns my calendar events fine when I am logged in with my Microsoft account.
Now, I would like to be able to access the same API using a service application i.e. without the user login prompt. So I went to the Azure portal, created and registered a new application, gave it Calendar.Read API permission with the administrator's consent and downloaded a quickstart daemon app which makes
await apiCaller.CallWebApiAndProcessResultASync($"{config.ApiUrl}v1.0/users", result.AccessToken, Display);
call which works i.e. it returns a user so that I can see that the
"userPrincipalName": "XYZ#<formattedemail>.onmicrosoft.com"
which is not what the Graph Explorer call returns. The Graph explorer call:
https://graph.microsoft.com/v1.0/users
and returns "userPrincipalName": "myactualemail"
So basically when I make the Graph Explorer call:
https://graph.microsoft.com/v1.0/me/calendars
it returns the calendars' result which is correct.
However, an equivalent daemon API call
await apiCaller.CallWebApiAndProcessResultASync($"{config.ApiUrl}v1.0/users/f5a1a942-f9e4-460b-9c6c-16f45045548f/calendars", result.AccessToken, Display);
returns:
Failed to call the web API: NotFound
Content: {"error":{"code":"ResourceNotFound","message":"Resource could not be discovered.","innerError":{"date":"2021-12-26T16:46:35","request-id":"67ef50e4-bec6-48ae-9e45-7765436d1345","client-request-id":"67ef50e4-bec6-48ae-9e45-7765436d1345"}}}
I suspect that the issue is in the userPrincipalName mismatch between the Graph Explorer and the daemon application, but I am failing to find a solution to this.
Also note that a normal ASP.NET Core sample which requires manual user login works ok. The issue is only with the daemon application.
There is no "me" in your case, so you need to use https://graph.microsoft.com/v1.0/users/user#domain.demo/calendars url.
When you used Graph Explorer to test the api, you've signed in the website, so /me/calendars contained in the request can know who is me and then return correct data to you.
Come back to your daemon app, we usually use client credential flow to gain the access token/credential to call the api in the daemon so that we don't need to let user sign in and then call the api, this flow makes the app itself can call microsoft graph api. But using this flow will lead to the issue that you can't use me any more because you never signed in yourself, so we should use /users/userPrincipalName/calendars instead.
Then come to the programming module, microsoft provides graph SDK for calling api, this is what you can also see in the api document. You can refer to this document to learn more details about how to use client credential flow with graph SDK. You can also copy my code below.
using Azure.Identity;
using Microsoft.Graph;
public IActionResult Privacy()
{
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "your_tenant_name.onmicrosoft.com";
var clientId = "azure_ad_app_client_id";
var clientSecret = "client_secret";
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var res = graphClient.Users["your_user_id_which_looks_like_xxxx-xxx-xxx-xxxx-xxxxxx"].Calendars.Request().GetAsync().Result;
return View();
}
By the way, if you're not familiar with the flows, you may take a look at my this answer.
I was able to kind of resolve this issue after chatting with the Azure tech guy. It turned out that my Azure account was considered a personal account. And the reason for this apparently was because I was using a personal #yahoo.com email to setup up the Azure account first place. Because of this they would apparently not allow me to purchase o365 and license it. So I had to create a new account with the amazon default domain for S3 - awsapps.com, which I took from my AWS S3 subscription. Then I had to run through a whole process of creating a new email in Azure from my existing S3 custom domain.
After the email was created I was able to purchase o365 basic license (trial version for now) and then login to Azure using a new email. o365 purchase gave me access to outlook and then recreating a new daemon application from the quickstart with the new credentials just worked.
I don't know if it makes sense what I had done as it sounds awfully convoluted. But it seems to work in the end.

Unable to fetch using RoleManagement API endpoints in azure graph-api

I'm trying to use the azure Graph API to fetch the users having a particular role. Code snippet below as how I generated the authToken
AuthenticationContext authenticationContext = new AuthenticationContext(_authString, false);
ClientCredential clientCred = new ClientCredential(_clientId, _clientSecret);
AuthenticationResult authenticationResult;
if (_authenticationResult == null || true == CanAcquireToken)
{
authenticationResult = authenticationContext.AcquireTokenAsync(_resAzureGraphAPI, clientCred).GetAwaiter().GetResult();
_authenticationResult = authenticationResult;
}
return _authenticationResult.AccessToken;
Snapshot of the list of permissions the Graph API has on my application:
GraphAPI permissions on application
I did my reading from https://learn.microsoft.com/en-us/graph/api/rbacapplication-list-roleassignments?view=graph-rest-beta&tabs=http to understand the API endpoint and the required set of permissions for the Graph API on the corresponding appRegistration.
I have provided the graph API with required permission set on the application which is under review.
However, the API request to
https://graph.microsoft.com/{{beta}}/roleManagement/directory/roleAssignments?$filter=roleDefinitionId eq '{{roleDefnId-Guid}}'
always keeps failing with the error details
Access token validation failure. Invalid audience
Note: The generated auth token is successfully fetching me info from "https://learn.microsoft.com/en-us/graph/api/approleassignment-get?view=graph-rest-beta&tabs=http" mentioned calls
The permission of your app is correct, Directory.ReadWrite.All application permission is enough. I also test your code, it works fine.
Make sure the _resAzureGraphAPI in your code is https://graph.microsoft.com (just confirm it again, I know if it is wrong, you will not be able to call the api in your Note). I can just reproduce your issue with a wrong one, e.g. https://graph.windows.net.
If the _resAzureGraphAPI is correct, decode your token in https://jwt.io/, see it is the same as below.

Error AADSTS65001 but no consent prompt for just one user

I am writing a C# .NET app. It is connected to our service on Azure which is configured for using AAD. In turn, our service tries to make calls to Exchange via EWS.
This all worked fine for me until we recently deployed our service bits to a new Azure web app with new app registrations. They are all configured correctly and other developers on our team can authenticate with the service and use it as expected.
When I try to connect to the service, I get the following error:
AADSTS65001: The user or administrator has not consented to use the application with ID '61a8b794-7f67-4a01-9094-fcdd45693eaa'. Send an interactive authorization request for this user and resource.
Trace ID: ece7c5d0-2ecb-4096-a87a-2cd33271d65d
Correlation ID: 093b5935-3b06-4d76-91a9-6619bc179544
Timestamp: 2017-02-09 23:19:28Z
The consent prompt never appeared for me when trying to connect after deploying the new service.
I'm not sure what it is about my user account that causes this error to occur (it happens on multiple machines with my account) while others can connect successfully.
Here’s some of the code used to acquire the token in the service:
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
var upn = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn);
var email = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email);
var userName = upn != null ? upn.Value : email?.Value;
accessToken = bootstrapContext.Token;
ClientCredential clientCred = new ClientCredential("61a8b794-7f67-4a01-9094-fcdd45693eaa", appKey);
UserAssertion assertion = new UserAssertion(accessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/microsoft.onmicrosoft.com");
AuthResult = authContext.AcquireToken("https://outlook.office365.com", clientCred, assertion);
Any ideas why I wouldn't get the consent prompt, but other users on my team have?
Based on the description, you are developing multi-tier application using Azure AD.
Since you mentioned this issue was occurred after using the new app, did you config your new app as the knownClientApplications of your service app(61a8b794-7f67-4a01-9094-fcdd45693eaa)?
If yes, you should can give the consent for the service app when you sign-in your web app( refer here about multi-tier applications).
The problem why only you get this issue may others have given the consent to this app before.
Please let me know if it helps.

Access tenants Microsoft Graph from daemon app

I am developing a daemon app that interacts with Microsoft 365 Office Planner to manipulate Microsoft Graph tasks. When I call the Microsoft Graph API to get the tasks related to my tenant, I get an Unauthorized request exception.
I have registered my application in Azure Active Directory and also gave it permissions to use the Microsoft Graph.
I request an access token based on the process from here:
https://graph.microsoft.io/en-us/docs/authorization/app_only
I am able to get a token from the Azure Active Directory v2.0 endpoint.
The request code is the following:
new KeyValuePair<string, string>("grant_type", "client_credentials"),
new KeyValuePair<string, string>("client_id", "<clent id>"),
new KeyValuePair<string, string>("client_secret", "<client secret>"),
new KeyValuePair<string, string>("resource", #"https://graph.microsoft.com")
var content = new FormUrlEncodedContent(pairs);
var response = client.PostAsync("https://login.microsoftonline.com/<tenant id>/oauth2/token", content).Result;
When I use this access token to perform a request as follow:
client.DefaultRequestHeaders.Authorization= new AuthenticationHeaderValue("Bearer", token);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
var response = client.GetAsync(#"https://graph.microsoft.com/beta/tasks").Result;
I get a status code 401 Unauthorized with the following response message:
Unauthorized: Access is denied due to invalid credentials.
You do not have permission to view this directory or page using the credentials that you supplied.
Is there any authorization process I have not performed to grant access to my app. Please help!!!!
Thanks in advance!!
Based on the test, it seems that Microsoft Graph doesn't support to list tasks with app-only token. After I grant the Group.ReadAll app permission to the app, I got the error like below with the request:
GET:https://graph.microsoft.com/beta/tasks?$filter=createdBy+eq+'xx#xxxx.onmicrosoft.com'
However the request was called successfully with the delegate-token with same permission:
As a workaround, you may check whether the OAuth2 Code Grant flow is helpful for your scenario.
The other users have raised the feedback about listing the tasks using the app-only token, you can vote this feedback from here if you also want this feature.

Resources