Failed to acquire ms graph token - c#

I have problem while trying to acquire the ms graph access token without a user.
I login from code using the quickstart provided settings
IConfidentialClientApplication app;
app = ConfidentialClientApplicationBuilder.Create("<application client ID>")
.WithClientSecret("<application secret>")
.WithAuthority(new Uri("https://login.microsoftonline.com/<tenant ID>"))
.Build();
var result = await app.AcquireTokenForClient(new List<string>() { "https://graph.microsoft.com/.default" })
.ExecuteAsync();
HttpClient sender = new HttpClient();
sender.DefaultRequestHeaders.Add(
"Authorization",
String.Format("Bearer " + result.AccessToken)
);
HttpResponseMessage meResult = await sender.GetAsync("https://graph.microsoft.com/v1.0/users/<email adress>/photo/$value");
string context =await meResult.Content.ReadAsStringAsync();
Console.WriteLine("WAAA");
Basically the problem is that I can aquire a token before creating the HTTP client, but when I would like to use it to get the user photo the response is 401 :(
With the message: 401 - Unauthorized: Access is denied due to invalid credentials The Azure application has these permissions granted to them.
Can anybody spot what am I missing?

Which permission do you have on your Azure portal? I guess you have now Delegated permission only.
You should have User.Read.All Application permission and afterwords need to add Grant admin consent. It should be like below:
You can get details here in our offical document
Permission:
Once you set the permission you can get below output:
Output:
Postman Test Result:
Azure profile Pciture:
Note: Your context required Application permission but seems you have Delegated Permission only.
Hope that would help.

Related

Authenticate an EWS application by using OAuth is not working

I am changing my existing c#-app from basic authentication to OAuth Authenticate.
I'm using the code example from Microsoft learn page:
// Using Microsoft.Identity.Client 4.22.0
var cca = ConfidentialClientApplicationBuilder
.Create(ConfigurationManager.AppSettings["appId"])
.WithClientSecret(ConfigurationManager.AppSettings["clientSecret"])
.WithTenantId(ConfigurationManager.AppSettings["tenantId"])
.Build();
// The permission scope required for EWS access
var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
//Make the token request
var authResult = await cca.AcquireTokenForClient(ewsScopes).ExecuteAsync();
On the Azure Active directory in App-Registration with the rigths Mail.* ( see attached image
)
[App rigths]
when I try to get the token with AcquireTokenForClient I get this error:
A configuration issue is preventing authentication - check the error message from the server for details. You can modify the configuration in the application registration portal...
ErrorCode: "invalid_client"
HResult: -2146233088*
Thanks for help
Dani
The only permission that is valid for EWS when using the client credentials flow is full_access_as_app
The Mail. permissions are all for the Graph which supports a much more restrictive permission model that EWS does not. I would suggest you read https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth you has the information you need to modify the manifest directly to add the correct permissions

Microsoft graph - Insufficient privileges when trying to get user info

I'm trying to get user information from Active Directory (email, phone number and assigned groups) using Microsoft graph and implicit flow in angular + asp.net web api application after user logges into the system.
Now we've set up some privileges for the application registered in Azure AD and all the code seems to be working fine using below set up.
The problem is those permissions seem high just for reading profile info and groups of a single user.
According to microsoft documentation delegated User.Read should be enough - link but after changing to below setup and removing User.Read.All for application
below error is thrown:
{
"StatusCode":500,
"Message":"Code: Authorization_RequestDenied Message: Insufficient privileges to complete the operation.
Inner error: AdditionalData: date: x request-id: x client-request-id: x ClientRequestId: x "
}
The error is thrown when calling Users from graphClient:
GraphServiceClient graphClient = GetClient();
return await graphClient.Users[userObjectId].Request()
.GetAsync();
private GraphServiceClient GetClient()
{
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create(ADClientId)
.WithTenantId(TenantId)
.WithClientSecret(ApplicationSecret)
.Build();
ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
return graphClient;
}
Now I'm not sure how to limit those privileges. Whether there is something incorrect with the flow, the C# code or maybe the privileges are incorrect.
Any help would be greatly appreciated.
Regards.
User.Read Delegated permission allows users to sign-in to the app, and allows the app to read the profile of signed-in users. It also allows the app to read basic company information of signed-in users.
So you can only get https://graph.microsoft.com/v1.0/me or https://graph.microsoft.com/v1.0/user/{userObjectId of the signed-in user} with this permission.
If you want to get other user's information, please use User.ReadBasic.All or User.Read.All Delegated permission (based on your needs). Please note you need to add Delegated permission rather than Application permission.
Reference here.

How to retrieve an MS Graph access token for a .NET Core Web API without user sign in

UPDATE (solution): I ended up simply extracting the token from the request that my frontend is sending with:
private async Task<string> GetApplicationAccessToken()
{
var token = this.Request
.Headers["Authorization"]
.First()
.Substring("Bearer ".Length);
var assertion = new UserAssertion(token, _ASSERTION_TYPE);
var authResult= await this._app.AcquireTokenOnBehalfOf(new []{""}, assertion)
.ExecuteAsync();
return authResult.AccessToken;
}
ORIGINAL:
I want to funnel data from the MS Graph API (Azure AD endpoint) through my backend (.NET Core Web API) back to my Angular App, that requests the data.
I am running into the problem that I am unable to get an Access token in my backend Web API.
I have Implemented a graph service according to this sample where user consent is prompted through a static html page that is being hosted on the web API. But I want to access MS Graph without explicit user consent.
I have looked for ways to get an access token for my web API without user consent, but not found anything helpful. Only stuff that confuses me. I have also supplied the App registration in Azure AD with application permissions and supplied my web API with sufficient information to the Azure app.
I am still not sure how to exactly adapt the sample code to work with my scenario where user consent is not required / an token already present in the request that my Angular app makes to my web API.
I am getting a userId (objectId.tenantId) in my GraphAuthProvider class when I am trying to call GetAccountAsync(). Yet I still don't receive a token from that call and don't get any error hints, just null.
public async Task<string> GetUserAccessTokenAsync(string userId)
{
var account = await _app.GetAccountAsync(userId);
if (account == null)
{
throw new ServiceException(new Error
{
Code = "TokenNotFound",
Message = "User not found in token cache. Maybe the server was restarted."
});
}
My appsettings.json
"AzureAd": {
"CallbackPath": "/signin-oidc",
"BaseUrl": "https://localhost:63208",
"ClientId": "[redacted]",
"TenantId": "[redacted]",
"ClientSecret": "[redacted]", // This sample uses a password (secret) to authenticate. Production apps should use a certificate.
"Scopes": "user.read profile",
"GraphResourceId": "https://graph.microsoft.com/",
"GraphScopes": "User.Read.All Groups.Read.All"
}
Can you point me in the right direction as to how to call the MS Graph API from my backend by using the application permissions?
Client credential flow using directly http post
In you web api , you can directly create http request to authenticate using client credential flow and retire Microsoft Graph's access token :
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=535fb089-9ff3-47b6-9bfb-4f1264799865
&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default
&client_secret=qWgdYAmab0YSkuL1qKv5bPX
&grant_type=client_credentials
Before that , you'd better admin consent the app permissions , see the detail steps in this article .
Client credential flow using MSAL.NET
If using the MSAL.NET , you can use below code sample for client credential flow :
// Even if this is a console application here, a daemon application is a confidential client application
IConfidentialClientApplication app;
#if !VariationWithCertificateCredentials
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithTenantId("{tenantID}")
.WithClientSecret(config.ClientSecret)
.Build();
#else
// Building the client credentials from a certificate
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithTenantId("{tenantID}")
.WithCertificate(certificate)
.Build();
#endif
// With client credentials flows the scopes is ALWAYS of the shape "resource/.default", as the
// application permissions need to be set statically (in the portal or by PowerShell), and then granted by
// a tenant administrator
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = null;
try
{
result = await app.AcquireTokenForClient(scopes)
.ExecuteAsync();
}
catch(MsalServiceException ex)
{
// Case when ex.Message contains:
// AADSTS70011 Invalid scope. The scope has to be of the form "https://resourceUrl/.default"
// Mitigation: change the scope to be as expected
}
You can refer to this article and code sample on Github.
Client credential flow using Microsoft Graph .NET authentication library
From document : https://github.com/microsoftgraph/msgraph-sdk-dotnet-auth
You can use Client credential provider :
// Create a client application.
IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithTenantId(tenantID)
.WithClientSecret(clientSecret)
.Build();
// Create an authentication provider.
ClientCredentialProvider authenticationProvider = new ClientCredentialProvider(confidentialClientApplication);
// Configure GraphServiceClient with provider.
GraphServiceClient graphServiceClient = new GraphServiceClient(authenticationProvider);
Or directly use MSAL.NET to authenticate using client credential flow and build the Microsoft Graph client like reply from #Philippe Signoret shows .

Azure Graph API : Error 403 Forbidden with Azure AD B2C

I have an Azure AD B2C. Since Azure Active Directory has been migrated to new portal, I have a problem to read and write tenant users data with the Azure Graph API. Before, I had an application which was created from the old portal and which doesn't work now.
So, I created a new application from the new portal, as following :
Open "Azure Active Directory" tab
Open "App registrations"
Click "New application registration"
"Properties" tab with :
Name : GraphApi
App ID URI : https://myTenant.onmicrosoft.com/graphapi
Home page URL : https://graph.windows.net/winbizdev.onmicrosoft.com
"Reply URLs" tab with :
https:// graph.windows.net/winbizdev.onmicrosoft.com
"Required permissions" tab with :
Windows Azure Active Directory -> Check 3 elements which don't require admin
"Keys" tab with :
CLIENT_SECRET which never expires
Here is now my C# code to access user data from Azure Graph API :
_authContext = new AuthenticationContext("https://login.microsoftonline.com/myTenant.onmicrosoft.com");
_credential = new ClientCredential("<Application Client Guid>", "<Client secret which I created in "Keys" tab");
var result = await _authContext.AcquireTokenAsync("https://graph.windows.net/", _credential);
var http = new HttpClient();
var graphUrl = "https://graph.windows.net/myTenant.onmicrosoft.com/users/<My User Guid>?api-version=1.6";
var request = new HttpRequestMessage(new HttpMethod("GET"), graphUrl);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
var response = await http.SendAsync(request);
return response;
And I always obtain a 403 error Forbidden. The version of the assembly "Microsoft.IdentityModel.Clients.ActiveDirectory" is 3.13.8.99.
So, what is wrong in my configuration? What I have to do to read and write user tenant users data again with Azure Graph API?
Thanks for your help!
Alex
You are acquiring acess token using client credential flow . That means you need add related Application Permissions in Required permissions blade .
All application permissions of azure ad graph api need admin consent . Please click Grant Permissions button(login with admin's account) after adding application permissions .

Microsoft Graph Api token invalid or not authorized?

I'm trying to read the user's data from Azure Active Directory via Microsofts' Graph API. Using the Graph Explorer I'm able to get all users but using a stand alone application I end up with an "unauthorized" response after receiving a token. I'm clearly missing some steps but it isn't obvious to me what steps that would be. Any insight would be appreciated
The code below is based off a MSFT sample:
// config values
// authority = "https://login.microsoftonline.com/{ TENANT ID }/oauth2/"
// resource uri = "https:// APP NAME .azurewebsites.net";
// graph uri = https://graph.windows.net/TENANT ID/ also tried https://graph.windows.net/v1.0/
// short form
public async void GetUsers( ADConfiguration config )
{
_authContext = new AuthenticationContext(config.GetAuthority());
_clientCredential = new ClientCredential(config.ClientId, config.ClientSecret);
AuthenticationResult result = null;
// obtain the token, this part is still successful
result = await _authContext.AcquireTokenAsync(config.ResourceUri, _clientCredential );
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
string address = config.GetGraphiUri() + "users?api-version=1.6";
// this response is always unauthorized
HttpResponseMessage response = await _httpClient.GetAsync(address);
}
In addition to answer your new problem . From you code , you are acquiring token using client credential flow. In the client credentials flow, permissions are granted directly to the application itself.
Since you are using Azure AD Graph API , you need to add application permission :
In the Azure portal, choose your application, click on Settings
In the Settings menu, choose the Required permissions section ,select Windows Azure Active Directory(Azure ad graph api) , add related application permissions your app requires .
Inside your app's blade, hit Grant Permissions to do admin consent with your admin's credential .
Your config values seem off:
Authority should be: https://login.microsoftonline.com/{TENANT ID}.
It seems to me that you are trying to use Azure AD Graph API, not Microsoft Graph API.
In that case:
Resource URI should be: https://graph.windows.net/. (MS Graph API is https://graph.microsoft.com/)

Categories

Resources