Problem calling Microsoft Graph from ASP.NET Grpc service - azure

I have two applications -
public client application (.NET Core console app), in which user gets Microsoft identity access token
web API, which tries to call Microsoft Graph on-behalf-of user, using that access token
When I call Microsoft Graph from web API, I get a MicrosoftIdentityWebChallengeUserException, which inner exception states:
"The user or administrator has not consented to use the application with ID <...> named <...>. Send an interactive authorization request for this user and resource."
I've tried:
to pre-authorize client application in service application using Expose an API tab in Azure Portal
to add client application ID in knownClientApplications array in Manifest tab
to include the scopes, needed for Microsoft Graph (e.g. "User.Read"), in the access token, obtained by the user
but it seems that this does not work and I still get the same exception.
The question is - can I somehow avoid this exceptional situation by getting all needed permissions in a user access token, before calling the GRPC service, or if not, that how do I need to handle this exception to propagate it back to the user.

Full details here. Keep following the Next Steps.
Basically, you'll need to:
Include the Microsoft.Identity.Web and Microsoft.Identity.Web.MicrosoftGraph NuGet packages in your API project.
Set up a Client Secret or a Certificate in the Azure App Registration. Include that in your appsettings.json file:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "{YOUR-DOMAIN-NAME-FROM-APP-REGISTRATION}",
"TenantId": "{YOUR-TENANT-ID-FROM-APP-REGISTRATION}",
"ClientId": "{YOUR-CLIENT-ID-FROM-APP-REGISTRATION}",
"Scopes": "{YOUR-API-ACCESS-SCOPE-FROM-APP-REGISTRATION}",
"CallbackPath": "/signin-oidc",
"ClientSecret": "{YOUR-CLIENT-SECRET-FROM-APP-REGISTRATION}"
}
Include the following section in your appsettings.json file:
"Graph": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": "User.Read"
}
Include the following code in your Project.cs file or Startup.cs file (depending on what version of .Net you're using):
Startup.cs:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration, Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(Configuration.GetSection("Graph"))
.AddInMemoryTokenCaches();
Project.cs:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(builder.Configuration.GetSection("Graph"))
.AddInMemoryTokenCaches();
From there, you just need to inject the GraphServiceClient into your controller or page constructor. The link above provides code for implementation in an ASP.NET API. I'm using this method in a Blazor Webassembly hosted app, so my implementation needs varied slightly from the instructions, but it's running/working as it should.

Related

Azure B2C Works On My Local Machine But Not On Azure

I have created a Blazor application that calls a Web API(.Net) and uses Azure AD B2C for authentication. This works fine on my local machine. I can authenticate via the login screen and call the relevant endpoint. Once I deploy the application to Azure I get this error on the browser:
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user
Failed to load resource: the server responded with a status of 401 (Unauthorized)
On the Blazor(UI) side I have this set up:
"AzureAd": {
"Authority": "https://CarehomeRoomBookingTest.b2clogin.com/CarehomeRoomBookingTest.onmicrosoft.com/B2C_1_SignUpIn",
"ClientId": "77##############################",
"ClientSecret": "99#########################",
"ValidateAuthority": false
}
On the Web API side I have this set up:
"AzureAdB2C": {
"Instance": "https://CarehomeRoomBookingTest.b2clogin.com",
"ClientId": "16#############################",
"Domain": "CarehomeRoomBookingTest.onmicrosoft.com",
"SignedOutCallbackPath": "/signout/B2C_1_susi_reset_v2",
"SignUpSignInPolicyId": "B2C_1_SignUpIn",
"TenantId": "38#############################"
}
Why would this be happening when the application is deployed and hosted on Azure?
Please check if any of below is your case:
1.See if scope for your API that Your front-end app needs to use is correct. This way it will get an access token which is meant for your API. Register a
scope for your API app registration through the Expose an API
section and use the scope in your front-end app.
and grant admin consent :
Your scopes will be present this way
Please make sure to include the scopes exposed in the portal for your backend api in the auth in your code
Also please check if you have given proper permissons or if use of
delegated permissions is the issue .See
getting-401-unauthorized-error-StackOverflow

Getting Azure Error: IDW10203: The 'scope' or 'scp' claim does not contain scopes 'access_as_machine' or was not found

I am trying to setup client credentials authentication for machines (original question:
Web API with Microsoft Identity Platform Authentication)
I am getting a valid token from https://login.microsoftonline.com/xxx/oauth2/v2.0/token.
However, I am receiving the following error when trying to call the secured action of my controller:
IDW10203: The 'scope' or 'scp' claim does not contain scopes 'access_as_machine' or was not found.
This is how my controller action looks like:
[Authorize]
[HttpGet("GetAsMachine")]
[RequiredScope("access_as_machine")]
public string GetAsMachine() => $"Machine {Assembly.GetExecutingAssembly().GetName().Version}";
In client credentials I had to set my scope to "api://xxx/.default".
When I try to set it to the actual scope, I am getting this error:
1002012: The provided value for scope api://xxx/access_as_machine is not valid. Client credential flows must have a scope value with /.default suffixed to the resource identifier (application ID URI).
Any idea what I am missing here?
Please notice one thing, when you want to use client credential flow, that means the token will contain roles claim but not the scp claim for delegate access token(generated by auth code flow/ropc flow..).
Then when you want to authenticate token generated by client credential flow, you may follow this document.
In brief, for example, I created a new .net 5 MVC project, and add configurations in appsettigns.json:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "clientid_which_have_api_permission",
"Domain": "tenantname.onmicrosoft.com",
"TenantId": "common",
"Audience": "clientid_of_the_app_exposed_api"//e.g: api://client_id
}
Then in Startup.cs, add services.AddMicrosoftIdentityWebApiAuthentication(Configuration, "AzureAd"); in ConfigureServices method and add app.UseAuthentication(); in Configure method.
Then in my controller, I add an action like this:
[Authorize(Roles = "Tiny.TestRead")]
public string getData() {
//HttpContext.ValidateAppRole("Tiny.TestRead");
return "success";
}
Then I think you can notice I used Tiny.TestRead as target role name. This is defined in Azure ad and it requires you to expose an api with a role. And don't forget to add api permission.
In my test, I only create 1 azure ad app, this app exposed an api(role type) then I add this api permission to itself. So I generate access token like this:

Allowing public access to only 1 endpoint of Azure Application

I'm building a small Azure Serverless Application with 3 distinct functions triggered by 3 different HTTP events. I set the "Authorization Level" to "Anonymous" for each of the functions. Then I set up the Authentication (on the application level) to link to my Azure Active Directory. Although it took me some time to figure out that part, in the end it appears to work like a charm. The issue is that right now I'm required to pass the bearer token for each and every one of these functions, whereas I need one of them to be publicly accessible.
Is there any way to do that that does not require me to split that one function into a separate Azure Application?
I think URL authorization rules should help here.
For your scenario, Enable the Authentication/Authorization and allow anonymous access in the portal. Next, you'll want to create an authorization.json file in the root of your site and define two routes:
Disable anonymous access at the root.
Enable anonymous access for the anonymous function URL.
authorization.json
{
"routes": [{
"path_prefix": "/",
"policies": { "unauthenticated_action": "RedirectToLoginPage" }
},{
"path_prefix": "/api/HttpTrigger1",
"policies": { "unauthenticated_action": "AllowAnonymous" }
}]
}
NOTE: Make sure to Stop/Start Function App after enabling the Authentication/Authorization and adding the authorization.json file at wwwroot folder.
Not sure how you implemented the app level security but in a regular OWIN or CORE app, the token handler will just pass the request as unauthenticated to the controller method if it does not find a valid token in the Authorization header (no header or token invalid). It's up to the method then to decide whether to handle the request or reject as unauthorized. Can you change your token verifier accordingly? (In fact, if your API can receive tokens issued by different issuers - AAD, B2C, Ping - you can configure several token handlers, each will try to va

Azure AD Authentication in dotnet core 2 API and daemon application

I'm struggling to determine the best route to authenticate using Azure Active Directory for my dotnet core web API.
Here is the situation:
An application created in Azure Active Directory that the Web API authenticates users. It has multiple application roles associated with it.
A daemon application that needs to authenticate to the Web API.
What is the best solution to solve the authentication situation? It's difficult to find clear documentation on how to actually solve this.
Thank you for your advice and help!
Your daemon app will need to use application permissions (app roles with member type = Application) to call the API.
You can see how to define those here: https://joonasw.net/view/defining-permissions-and-roles-in-aad.
For example, this is how one looks like in the manifest:
{
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"displayName": "Read all todo items",
"id": "f8d39977-e31e-460b-b92c-9bef51d14f98",
"isEnabled": true,
"description": "Allow the application to read all todo items as itself.",
"value": "Todo.Read.All"
}
]
}
Then you assign the app permission to your daemon app.
After that it's a simple matter of authenticating with client credentials from the daemon app.
With ADAL.NET for example, you would acquire a token with ClientCredential + the resource URI of the API.
You can find the URI from your API's app registration (Properties blade, App ID URI).
You can then attach the resulting access token to HTTP requests and the API can find from the appid claim who the calling app is, and from the roles claim what app permissions they have.

Azure AD remove permissions for registered app

I am using Azure AD to secure my service to service calls. (Each service having an application identity in Azure AD).
Example: Application A wants to access Application B.
I noticed that when requesting an accesstoken from Application A using Client Credential Flow (with Certificate), an accesstoken is issued without having me to explicitly set the permissions to access Application B.
This seems odd to me because the token returned has its audience set to Application B even thought I haven't explicitly given it access.
If I understand correctly, all registered app have access to each other by default?
Is there a way in Azure AD to explicitly require permissions to be set in order for application to access each other?
Below is a screenshot of Application A required permissions. As you can see, Application B is not listed here.
In the following screenshot, I assigned TodoListService (aka Application B) to the required permissions of Application A
I noticed that when requesting an accesstoken from Application A using Client Credential Flow (with Certificate), an accesstoken is issued without having me to explicitly set the permissions to access Application B.
Yeah, that one can be a bit surprising and I'm not sure why that is the case either.
What you need to do is define application permissions on the API, and then assign it on the client.
Then you need to check the caller has the required app permission in the token.
I have an article on this topic: Defining permission scopes and roles offered by an app in Azure AD.
To define an app permission on the API, you'll have to edit its manifest in Azure AD, and add an app role with member type of Application, something like:
{
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"displayName": "Read all todo items",
"id": "f8d39977-e31e-460b-b92c-9bef51d14f98",
"isEnabled": true,
"description": "Allow the application to read all todo items as itself.",
"value": "Todo.Read.All"
}
]
}
IIRC you have to generate a GUID for the id.
After defining this permission on the API, go to your client app, and add the app permission in the Required permissions.
Then you should press Grant permissions to grant the app permission.
Now then when the client acquires a token with client credentials, the token will contain:
{
"roles": [
"Todo.Read.All"
]
}
So you'll have to check that that is present.

Resources