Accessing MS Graph from API on behalf of user currently signed in to separate web client - azure

I am developing an API(ASP.NET Core) which is accessed via separately hosted web client(React), both hosted on azure as app services.
Client app must have auth based on azure Ad(single tenant, preferably secured by azure auth based on aad).
When the user signs in to client the API must have access to MS Graph on behalf of user. Obviously both resources must be secured, I have tried using azure auth based on AAD on both app services, but I couldn't get a token to MsGraph in this approach with the token obtained from auth to ADD on API side.
Question is, how to avoid passing token to MsGraph with token for azure aad auth from client, and obtain token for msGraph based only on token from aad auth while having only one place for users to sign in and keep both app services secured?
I am using nugget for MsGraph on Api side to interact with MsGraph. I haven't found any sample that refers this specific case.

Scenario: Your application's Web API (protected by Azure AD) receives auth token from a client application (React) and needs to call a downstream Web API (Microsoft Graph) on behalf of the signed-in User.
Conceptual Documentation on Microsoft Docs: Your scenario exactly matches the OAuth 2.0 on-behalf-of flow as explained on Microsoft Docs for Azure AD here Service-to-service calls that use delegated user identity in the On-Behalf-Of flow
Code Samples:
Service to service calls on behalf of the user (From Azure-Samples on GitHub)
Calling a downstream web API from a web API on behalf of user (From Azure-Samples on GitHub)
Using Azure AD On-Behalf-Of flow in an ASP.NET Core 2.0 API (Not directly Microsoft samples, but from Joonas W's blog, who is an MVP)
Important Code
This is how you use the already passed in token to acquire a new token, with which to call the Microsoft Graph API, from your Web API, on behalf of the user.
Preparing the User Assertion:
ClientCredential clientCred = new ClientCredential(clientId, appKey);
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
string userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
string userAccessToken = bootstrapContext.Token;
UserAssertion userAssertion = new UserAssertion(userAccessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
Acquiring a token for Microsoft Graph:
result = await authContext.AcquireTokenAsync(graphResourceId, clientCred, userAssertion);

I ended up with using only Azure Ad + auth validation by code(no azure auth).
The API uses OBO flow, the client app uses implicit flow.
Basically two separate app registrations on aad, the client which has access_as_user permision to the api, and the other one for api which has permissions for MsGraph. You configure it in App registrations(preview)/API permissions. (For detailed guide follow examples below, start with the api)
For Web client I also used scopes: 'access_as_user', 'offline_access', 'openid' in the request for the token, added true for "oauth2AllowImplicitFlow" in manifest and redirect to the yourdomainname.azurewebsites.com, the rest of configuration similarly to the native client in example below.
Useful resources:
API:
https://github.com/Azure-Samples/active-directory-dotnet-native-aspnetcore-v2
https://learn.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-on-behalf-of-flow
(I recommend testing with native client first to check if its set up correctly,
configuration of API will remain the same for separate web client)
Web client:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-implicit-grant-flow
This is solution which suits me at the moment, it might be possible to tailor it better.

Related

Azure AD B2C - Using access token returned from sign in flow to secure the rest web API

I am using Azure B2C in my react SPA to sign in the user with external identity providers e.g. Google and Facebook. I have some .net core web API that needs to be called by signed-in users only. I have followed Azure documents for my scenario. As per the docs, I need to register another AD B2C application for web API security and my client app needs to acquire the token with the scope defined in the server-side AD app and pass that token while calling the web API.
Why can't I use the same access token received from azure AD B2C as part of the sign-in flow to pass it to my web API and validate it on the server side to secure the Web API? In that case, I don't need to create another server-side AD application for securing the API.
You can, but it’s simply against the protocol spec. Each client needs to be registered and have a unique client Id/AppId.
Plus if you do it with one App Registration, your logs would never differentiate access to your front end vs access to your api.

Which application requires to enable Azure AD based authentication, Client APP or API?

I have two projects in a solution. One is .net core 3.0 based Web API. Next is Angular 9 SPA. I've been asked to setup Azure AD based authentication. So I enabled that in API.
But I am seriously confused where it actually requires to enable? Client App or API? or Both?
Since your client needs to call the API, it needs to authenticate to it.
And since the API requires AAD tokens, your client will need to acquire one.
So you need to implement Azure AD authentication in your client application and in the API.
The client's job is to authenticate the user with Azure AD and acquire an access token for the API.
It then adds that token as a header on each request:
Authorization: Bearer token-goes-here
The API then validates that token on each request.

How to access Azure B2C openId protected API by multiple client Application

I secure my nodeJs API with Azure B2C. I have two web application which accesses my API.
the two Web application has its own application Id in Azure B2C. Also, those can generate access_token with B2C.
But when I validate those access_token in my API I have to put application id of the web application witch generate the access_token as an audience.
But the audience does not support array. I can only put one application id.
How do I solve this?
If I secure an API with B2C I only can make requests from one web application?
The audience (aud) claim for an access token identifies the intended recipient (i.e. the API application) of the access token.
At a high-level, you must:
Register the API application in order for any client application to acquire an access token for use with the API application.
Grant access by one or more client applications to the API application.
Configure the application identifier for the API application as the expected audience for the API middleware.
The Azure AD B2C: Requesting access tokens article describes how a client application can acquire an access token for use with an API application.

MobileServiceClient InvokeApiAsync gets 401 while try to access asp.net core web api

I have a Xamarin Forms app that intereacts with a Asp.net Core Web api hosted on Azure App Service with client authentication flow with Azure B2C authentication.
The app can login succesfully to the Azure with the LoginAsyc (I get the idtoken) but when I try to invoke a service that requires authorization using the MobileServiceClient I get a 401. The api is called using the InvokeApiAsync.
If I invoke a an api method that does not require authorization it works fine.
I opened the Azure logs, and only see 401 error.
Any idea how to call this secure action method from Xamarin using the MobileServiceClient.
Please help
David
The app can login succesfully to the Azure with the LoginAsyc (I get the idtoken) but when I try to invoke a service that requires authorization using the MobileServiceClient I get a 401. The api is called using the InvokeApiAsync.
According to your description, I assumed that you are using App Service Authentication / Authorization. For Client-managed authentication, you directly contact the AAD identity provider and retrieve the id_token or access_token. At this time, you could just access the authorized endpoint as follows:
https://{your-app-name}.azurewebsites.net/api/values
Authorization: Bearer {aad id_token or access_token}
Note: When constructing the MobileServiceClient, you could pass your custom DelegatingHandler to append the bearer token before sending request(s) to your Azure backend.
I just created a single Native app in my B2C tenant and use MSAL to retrieve the id_token or access_token as follows:
var authority = "https://login.microsoftonline.com/tfp/{Tenant}/{Policy}";
PublicClientApplication IdentityClientApp = new PublicClientApplication("{native-app-id}", authority);
IdentityClientApp.RedirectUri = $"msal{native-app-id}://auth";
var scopes = new string[] {
//"https://bruceb2c.onmicrosoft.com/EasyAuthB2CApp/user.read"
""
};
var result=await IdentityClientApp.AcquireTokenAsync(scopes);
Note: I just created a single native app, the parameter scopes in AcquireTokenAsync method does not support the clientId, so I just pass the empty scopes, at this point, you would not receive the access_token, you just need to use the id_token as the bearer token to access your Web API. For the Web API web app, I used the native app to configure my AD authentication on Azure Portal.
Moreover, you could create a native aad app for your mobile client and a WebAPI aad app for your azure web app. At this time, you could specify the valid scopes for your native aad app to access the WebAPI app. Then, you would retrieve the access_token, at this time you need to set the WebAPI app id as the Client ID or add it to the ALLOWED TOKEN AUDIENCES list on Azure Portal.
In summary, you need to make sure the aud property in the id_token or access_token matches your Azure Active Directory Authentication Settings on Azure Portal. Note: You could use https://jwt.io/ to decode the token and check the related properties.
Moreover, for client flow authentication using LoginAsync, you need to pass the access_token to log in with your web app, then you would retrieve the authenticationToken. And the mobile client library would add the authenticationToken as the x-zumo-auth header to the subsequent requests (e.g. using MobileServiceClient.InvokeApiAsync).
Additionally, here are some tutorials, you could refer to them:
App Service Auth and Azure AD B2C
Integrate Azure AD B2C into a Xamarin forms app using MSAL
Azure AD B2C: Requesting access tokens
ASP.NET Core 2.0 web API with Azure AD B2C using JWT Bearer middleware

Hot to get an Azure AD Id_token over an Azure Mobile App?

I'm trying to get an Id_token over Azure Mobile App but I'm receiving an mobileServiceAuthenticationToken.
The mobileServiceAuthenticationToken is received by my iOS-App with the following implementation: Integrate Azure AD into an iOS app
I need the Id_token (with algorithm RS256) because my backend-service (java spring-boot) needs to validate this token, which is not possible with the mobileServiceAuthenticationToken. mobileServiceAuthenticationToken is based on algorithm HS256 (which needs a client secret) and does not allow requesting the Azure AD for getting user informations over the Microsoft Graph Api.
Here is a link to microsoft reference for further informations: Azure AD token reference
The id_token is not able to call the Microsoft Graph REST. To call Microsoft Graph REST, we need to acquire the corresponding access_token for it which's aud claim is https://graph.microsoft.com.
There are two kinds of flows for mobile authentication, client-flow and server-flow. Both of them should work in your scenario, however the progress is a little different.
Client flow:
For this flow, you can get the id_token and access_token for Microsoft Graph from Azure Active Directory first using ADAL SDK. Then you can exchange the id_token with EasyAuth for the authentication token and login your mobile app.
Server flow:You can config the mobile app to acquire the access_token for Microsoft Graph. Then you can implement an proxy in the mobile back-end. After that you can only need to call the mobile back-end both your owner service and Microsoft Graph.
Here are some helpful articles about this topic:
How to: Authenticate users with the Active Directory Authentication Library
App Service Auth and the Azure AD Graph API

Resources