Graph API - Insufficient privileges to complete the operation - c#

When trying to access the Graph Service Client using I am receiving the error:
Code: Authorization_RequestDenied
Message: Insufficient privileges to complete the operation.
After researching this error the most common solution was to set the permissions for the API. This had already been done and has permissions to read basic/full profiles.
I've delete and re-added the APIs.
Below is the code in my AzureAuthenticationProvider class which inherits from IAuthenticationProvider:
public class AzureAuthenticationProvider : IAuthenticationProvider
{
private string _azureDomain = "myDevDom.onmicrosoft.com";
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
try
{
string clientId = "2b823c67-1b0d-4a10-a9e1-737142516f5q";
string clientSecret = "xxxxxx";
AuthenticationContext authContext = new AuthenticationContext("https://login.windows.net/" + _azureDomain + "/oauth2/token");
ClientCredential credentials = new ClientCredential(clientId, clientSecret);
AuthenticationResult authResult = await authContext.AcquireTokenAsync("https://graph.microsoft.com/", credentials);
request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
}
catch (Exception ex)
{
}
}
}
I've tried changing the client secret to an invalid Id and it threw an error, so the client key is correct. I've also tried to verify that the access token is valid by altering the access token, this also returns a error.
The above code seems to work fine.
Below is the code where I'm trying to access Azure AD:
public async Task<IGraphServiceUsersCollectionPage> GetUsersByLastName(string lastname)
{
GraphServiceClient graphClient = new GraphServiceClient(new AzureAuthenticationProvider());
string filter = String.Format("startswith(surname, '{0}')", lastname);
IGraphServiceUsersCollectionPage users = await graphClient.Users.Request().Filter(filter).GetAsync(); //Fails on this line
return users;
}

Please refer to below steps :
From your screenshot , seems you grant Read and write directory data application permission for Windows Azure Active Directory(azure ad graph api) . Since you are using microsoft graph (https://graph.microsoft.com/) , you need to grant application permission for Microsoft Graph :
Since you are admin in your AAD, You could grant permission for users in organization by click Grant permission button shown in above screenshot .
Then you could use your code (client credential flow to get the token) and query users information . If you check the claims in access token issued by azure ad , you could find Directory.Read.All permission in roles claim .

Make sure click "Grant Permissions" and than Yes for all users accounts.

In my case, delete user was not working. I took below steps & it started working for me.
Go to Azure Active Directory > Roles and administrators > Click on 'User administrator' > click on '+ Add assignment' to add your app. (i.e. console app using AAD Graph REST API to interact with Azure Active Directory).
Hope it helps someone.

For me the key to solve this problem was hint:
To use the Graph API with your B2C tenant, you will need to register a dedicated application by using the generic App Registrations menu (All Services and there it is by default not Favourite starred) in the Azure Portal, NOT Azure AD B2C's Applications menu. You can't reuse the already-existing B2C applications that you registered in the Azure AD B2C's Applications menu.
Find more on page AD B2C API access demo

In some cases the actual issue happens because we use "Application permissions" instead of "Delegated permissions". In my application, I have tried to list all the users with application permissions and it wasn't working. When I switched to a delegated permissions, it worked.
So, some quick check would be like this:
Check if you are using Microsoft Graph API or something else
Use Delegated permissions
Click Grant permissions button to propagate permissions :)
Hopefully, this would help someone.

Suppose you want to create group in azure active directory
i have to performer the following steps to solve this problem
AD > App Registered > your app
Select Required Permission
Click Add and select Microsoft Graph and add it
select Microsoft Graph
select Read and write all groups from delegated permission list
And save it
Select Windows Azure Active Directory and grant all application permission
Save it

Grant permissions by ticking 'Directory.Read.All/ Write' is not enough.
I run into the same issue. and solved by adding service principle to administrator role.
If you application is created recently, this can be done Azure AD Powershell.
$pricinple = Get-AzureADServicePrincipal || Where-Object {$_.DisplayName -eq 'youappname'}
$role = Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq 'Company Administrator'}
Add-AzureADDirectoryRoleMember -ObjectId $role.ObjectId -RefObjectId $pricinple.ObjectId
for detail, see https://learn.microsoft.com/en-us/powershell/module/Azuread/Add-AzureADDirectoryRoleMember?view=azureadps-2.0
If you application was created long time ago, you will need to use MSOnline.
see: https://learn.microsoft.com/en-us/powershell/module/msonline/Add-MsolRoleMember?view=azureadps-1.0

I am using Credentials flow
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
and my problem was setting Delegate Permissions instead of Application Permission.
I could not get a user because I wasn't using User.Read.All from Application Permissions
https://learn.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http
Application User.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All

I had to add all "groups" (ID, Access, SAML) into the token.
This can be configurated in the Azure Active Directory Token Configuration and checked via https://jwt.io/.

you should give Directory.Read role to the service principal in the AD page, not the app register page.
by the way. I am use python sdk azure-graphrbac with serviceprincipal
from msrestazure.azure_active_directory import ServicePrincipalCredentials
credential = ServicePrincipalCredentials(ServicePrincipal_APP_ID,ServicePrincipal_SECRET_VALUE,tenant=ServicePrincipal_TENANT_ID,resource="https://graph.windows.net/")
self.client=GraphRbacManagementClient(credential,TENANT_ID,base_url)

Go to Azure Portal -> Active Directory -> App registrations -> Select Your Application -> API permissions
Now, Click on Add a permission and choose Microsoft Graph, select Application Permission and search for User.Read.All
Add these permissions to your application and it should work.

Related

Getting claims using MSAL

I am using Microsoft.Identity.Claim library to conenct to azure and authenticate user.
My first idea was to use AcquireTokenByIntegratedWindowsAuth method but that requires few days until network administrator people investigate how to enable single sign-in option and change that user are now "federated" and not "managed. So I now switched to AcquireTokenInteractive method because chances are that ure will be logged in, so he will just need to choose account from automatically opened browser and that's it. No big deal.
And this works:
string clientId = "xxx";
var tenantId = "yyy";
string[] scopes = new string[] { "User.Read", "User.ReadBasic.All"};
AuthenticationResult result;
var app = PublicClientApplicationBuilder.Create(clientId)
.WithRedirectUri("http://localhost")
.WithAuthority(AzureCloudInstance.AzurePublic, tenantId).Build();
try
{
result = await app.AcquireTokenInteractive(scopes)
.ExecuteAsync();
}
catch (MsalUiRequiredException) //see all possibl exceptions!
{
However, I don't receive claims inside token.
My idea is to send this token to server, then validate it, and if sucessfull create user in database and then use my own authenication mechanism I use for other users (that are not part of domain, completely separate user).
But I don't want all users from domain have access to this app.
So I would like to get claims, roles...
How to get claims, using this or any other lib given user email, or some other unique data?
Here I summarize all of the steps you may need to follow:
1. You need to register a app in azure ad for your service app, you can refer to this document
2. Then you need to register another app in ad as the client app, you can follow the steps in this document
3. After that, you need to do the steps in this document which I already provided in comments. Do it in the service app but not client app.
4. Then you can get the access token with your code and check the claim roles. Please note, do not add microsoft graph permissions into scopes in your code. You need to add api://<the client id of the registered app for service app>/.default into scopes.
5. Now you can find the claim roles in your access token.

Create a 'event as online meeting' or only the onlineMeeting using Microsoft Graph API

Any user who logged into our system (IdentityServer as Auth) under a specific tenant should be able to create an event as an online meeting (MS Teams).
We followed Build ASP.NET Core MVC apps with Microsoft Graph and Create and enable an event as an online meeting to create an application that authenticates an AD user of an organization and allow him to create an event as an online meeting.
We are able to implement it successfully and was able to create the event as an online meeting.
But the exact scenario here is any user who is authenticated in our web application (not a AD user) should be able create a MS Teams meeting event and share it with other participants who should be able to join the meeting.
I am not sure how to achieve this.
Edit
Or at least how do I create onlineMeeting ? I tried with Client credentials provider as below
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("<<App_Id>>")
.WithTenantId("<<Tenant_Id>>")
.WithClientSecret("<<Client_Secret>>")
.Build();
ClientCredentialProvider authenticationProvider = new ClientCredentialProvider(confidentialClientApplication);
GraphServiceClient graphClient = new GraphServiceClient(authenticationProvider);
var onlineMeeting = new OnlineMeeting
{
StartDateTime = DateTimeOffset.Parse("2020-01-15T21:30:34.2444915+05:30"),
EndDateTime = DateTimeOffset.Parse("2020-01-15T22:00:34.2464912+05:30"),
Subject = "User Token Meeting"
};
var meeting = graphClient.Me.OnlineMeetings
.Request()
.AddAsync(onlineMeeting).Result;
but it was throwing
Code: Forbidden
Inner error:
AdditionalData:
request-id: <<some_id>>
date: 2020-07-09T16:42:23
ClientRequestId: <<some_id>>
I been working on your question in few days, I was going to mention some of the suggestions comes with the other answer. But in addition, the main challenge here, the system need to know who is authorized to do what.
So IMO The Best choice to solve this is creating a guest login in AzureAD, than you can use that to create a Team Events. Further more you can added an extra step after guest user logon, so that guest should enter his/her name and use it as reference.
You will need to take these two steps.
Get the right token
Create an event (but change the url to
https://graph.microsoft.com/v1.0/users/the_user#domain.com/events)
The hard part is getting the right token, you have multiple options.
Use the client credentials flow this will force an admin from every new tenant to authorize your application for their organization. You can then use the tenant from the user info to request a token for that tenant and use the user id to create the right url to post to.
Make IdentityServer save the access token and allow you to access it. At coonfiguration level you have access to token callback and there you can also save the Azure AD access token. I think you can add it to a reference token, that way it isn't transmitted everytime but your web application is still able to access it.
Use the on-behalf-of flow, this would require you to pass the Azure AD access token token retrieved from azure AD by the IdentityServer to be passed to your application.
Just remove the identity server from the flow and have your web application logging straight with Azure AD. That way you'll have the right token available all the time.
Edit
After reading your editted question, what you want is a website where the user doesn't have to be an member of your Azure AD, just wants access to some new online meeting?
Best option is to created a shared mailbox, authorize an application (with Calendar.ReadWrite). Get a token with client credentials and call Create Event and then extract the meeting url from the event (that you'll get back when the posts completes succesfully.
To create an online meeting for the "Client Credentials" flow, I used the following:
var confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create("my-app-client-id")
.WithTenantId("my-aad-tenant-id")
.WithClientSecret("my-client-secret")
.Build();
var authProvider = new ClientCredentialProvider(confidentialClientApplication);
var graphClient = new GraphServiceClient(authProvider);
var meetingGuid = Guid.NewGuid();
var createMeetingResponse = await graphClient.Users["my-aad-user-object-id"].OnlineMeetings
.CreateOrGet(meetingGuid.ToString())
.Request()
.PostAsync();
The issue with your code is that referencing graphClient.Me causes the Graph requests to go to https://graph.microsoft.com/v1.0/me/onlineMeetings, which is not what you want in the "Client Credentials" flow. See this screenshot from the documentation found here: https://learn.microsoft.com/en-us/graph/api/onlinemeeting-createorget?view=graph-rest-1.0&tabs=csharp
I had to grant "application" permissions in Azure Portal to allow my app to access the online meetings API, and I had to create a client secret. I also had to follow this article to create a policy and grant it to specific users using Microsoft Teams PowerShell:
https://learn.microsoft.com/en-us/graph/cloud-communication-online-meeting-application-access-policy
For users not in your organization, you can invite them as a guest user to your tenant.
I had issues using the Microsoft Teams Powershell commands due to settings in Windows Remote Management, which I did something like this to work around:
https://lonesysadmin.net/2017/08/10/fix-winrm-client-issues/

How can I return user- specific information from MS Graph API?

I am trying to get a list of planner plans associated with a user. I can do this in Graph Explorer (logged in with my work Microsoft account) using the following API call:
https://graph.microsoft.com/v1.0/users/<my-email>/planner/plans
However, I need to use a token from my console app, as I need to run it as a scheduled task with no user intervention. From my app I get an access denied error:
401 - 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.
I can successfully call "generic" methods (such as https://graph.microsoft.com/v1.0/groups ) but not something specific to a user.
I am getting my token using:
context = new AuthenticationContext("https://login.microsoftonline.com/<my_tenant");
context.AcquireTokenAsync("https://graph.microsoft.com", new ClientCredential(clientId, appKey));
How can I give this token the necessary permissions to read stuff like planner? I've tried in the Azure Portal under the Azure AD blade:
According to your description, I assume you want to list the plans of a user.
Based on my test, we can use the follow simple code:
public PlanClientService()
{
_serviceClient = GraphSdkHelper.GetGraphServiceClient();
}
public async Task<IList<PlannerPlan>> PlannerPlansAsync()
{
var plans = await _serviceClient.Me.Planner.Plans.Request().GetAsync();
return plans;
}
We can refer to the simple code for more detail.
And according to the error description, you should add the Group.Read.All, Group.ReadWrite.All permission when you get the accesstoken.

Connection Issues when using AcquireTokenAsync() in Xamarin Forms Windows App with Azure AD B2C and custom policy

I am using MSAL to connect my Xamarin.Forms-Windows 8.1-App to Azure AD B2C with a custom SignInSignUp-policy (to login the user by using a custom E-Mail address and a password). The "normal" authentication against Azure AD (without custom policy) works fine, but when I use the policy, the message "We can't connect to the service you need right now. Check your network connection or try this again later." appears everytime after providing the credentials (directly within the dialog). Since the dialog does not finish correctly, I am not retrieving any exception or AuthenticationResult and so I am not able to determine the concrete issue (the internet connection itself is not the problem).
Note: I also tried this in a Xamarin.Forms-UWP-App which leads me to the same issue. Under iOS, it is working fine and the dialog finishes and closes correctly.
NuGet Versions:
MSAL (Microsoft.Identity.Client): 1.0.304142201-alpha
Xamarin.Forms: 2.3.2.118-pre1
Thats my code (simplified):
var clientId = "{My application's ClientId}";
var redirectUri = "urn:ietf:wg:oauth:2.0:oob";
var authority = "https://login.microsoftonline.com/{My Azure AD B2C}";
string[] scopes = { clientId };
var policy = "{My SignUpSignIn policy}";
var clientApplication = new PublicClientApplication (authority, clientId);
clientApplication.RedirectUri = redirectUri;
var result = await this.clientApplication.AcquireTokenAsync(scopes, string.Empty, UiOptions.SelectAccount, string.Empty, null, authority, policy);
Any ideas on this?
Thanks in advance!
Regards,
Marcel
I had the same issue. Turns out I forgot to properly set up my mobile app to allow loggin in via Active Directory
The steps I took that solved my problem were:
In Azure B2C Blade select Application and set the Reply URL to the address of the Azure Mobile Apps instance (e.g. https://myapp.azurewebsites.net), followed by /.auth/login/aad/callback
Make sure the policies used in the Azure Active Directory B2C tenant should be configured so that the Reply URL is set to the same as above
In the Azure Mobile or Services App go to settings-->authentication/autorization and make sure that a non authenticated request is set up to log in with AAD
in the same blade select the AAD provider, go to advanced and set up Client ID and Issuer URL, with the Client ID being the Application ID of the Azure Active Directory B2C tenant, and the Issuer Url being the Metadata Endpoint for the Azure Active Directory B2C policy
Once I did the above all worked flawlessly.
More detailed instructions can be found at https://developer.xamarin.com/guides/xamarin-forms/web-services/authentication/azure-ad-b2c-mobile-app/
Let me know if this helped...

Azure AD: user_interaction_required issue when authenticating a native application

I have Exchange Online from Office 365 with a mailbox and I need to access this mailbox with my console C# application that uses Managed EWS. The requirement is that the console application should use OAuth authentication to access the Exchange Online.
I have Azure AD set up, and created an application there, received clientid and redirect uri. I have given full permissions to the application - please have a look at the screenshot below:
I'm using Active Directory Authentication Library for .NET (latest version from NuGet) to issue a token, but having a problem to get it running...
My code is:
AuthenticationContext authenticationContext = new AuthenticationContext("https://login.windows.net/rsoftgroup.onmicrosoft.com", false);
AuthenticationResult authenticationResult = null;
try
{
var authenticationTask = authenticationContext.AcquireTokenAsync(
"outlook.office365.com",
"c4fa7d60-df1e-4664-a8f8-fb072d0bb287",
new Uri(redirectUri),
new PlatformParameters(PromptBehavior.Never)
);
authenticationTask.Wait();
authenticationResult = authenticationTask.Result;
exchangeService.Credentials = new OAuthCredentials(authenticationResult.AccessToken);
}
catch (AdalException)
{
// Exception occured on the authentication process.
}
I get AdalException with message: "user_interaction_required: One of two conditions was encountered: 1. The PromptBehavior.Never flag was passed, but the constraint could not be honored, because user interaction was required. 2. An error occurred during a silent web authentication that prevented the http authentication flow from completing in a short enough time frame"
Can somebody help me how to solve it?
I need the OAuth authentication to work without user interaction, as this will be a command line application...
Any suggestions highly appreciated.
Your application still needs to authenticate as some user, currently if you look at your code you don't authenticate because of PromptBehavior.Never and you don't specify any user-credentials and use the implicit auth flow eg http://www.cloudidentity.com/blog/2014/07/08/using-adal-net-to-authenticate-users-via-usernamepassword/
For a standard Console apps where you are going to authenticate (eg ask for credentials when the app is run) I would use out of band call urn:ietf:wg:oauth:2.0:oob (you then don't need a redirection endpoint) and set your code to prompt eg
AuthenticationContext ac = new AuthenticationContext("https://login.windows.net/Common");
var authenticationTask = ac.AcquireTokenAsync(
"https://graph.windows.net",
"5471030d-f311-4c5d-91ef-74ca885463a7",
new Uri("urn:ietf:wg:oauth:2.0:oob"),
new PlatformParameters(PromptBehavior.Always)
).Result;
Console.WriteLine(authenticationTask.AccessToken);
When you run the Console app windows and the ADAL library will handle the plumbing and show the correct authentication prompts and get the Token back and you get the benefits of reduce attack surface over prompting for the credentials yourself in your code (or as parameters etc)
As Venkat comments suggests if you don't need to use EWS (eg no existing code base investment etc) then using the REST endpoints maybe a better solution if your building a daemon type application as you can take advantage of this type of auth flow eg https://blogs.msdn.microsoft.com/exchangedev/2015/01/21/building-daemon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow/

Categories

Resources