How to configure MSAL to support AAD, Angular 7+, Azure Funcs - azure-active-directory

I would like to understand how to configure MSAL and related artifacts to facilitate the following configuration.
Frontend Angular 7+ website/app published to Azure Storage account and served as a static website.
Backend Azure Functions API project for performing CRUD operations on a Cosmos-DB database
Both the Angular website frontend and the Azure Functions API backend should be restricted to individuals within our Azure Active Directory.
I attempted to learn how to configure MSAL for my intended use-case by studying this demonstration project: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/README.md. Unfortunately, that project refers to an API backend site that is no longer operational. And the backend bits are not included in the repository.
The demonstration project msal-microsoft-authentication-library-for-js\lib\msal-angular\samples\MSALAngularDemoApp doesn't work as published. Log-in attempts fail. Once encounters Uncaught (in promise): AADSTS650052: The app needs access to a service (\"api://a88bb933-319c-41b5-9f04-eff36d985612\") that your organization \"<MY-ORG>\" has not subscribed to or enabled.
With my current configuration, in the browser I'm encountering request cancellation when MSAL attempts to make a requests of the following form:
https://login.microsoftonline.com/67ba7efb-e8.....52-1f993843c3a0/oauth2/authorize?response_type=code+id_token&redirect_uri=https%3A%2F%2Fte.....nfuncs.azurewebsites.net%2F.auth%2Flogin%2Faad%2Fcallback&client_id=61601ca6-104.....524550f6ec&scope=openid+profile+email&response_mode=form_post&nonce=62877cb9e.....245f7f613_2019.....72304&state=redir%3D%252Fapi%252Fpeople%253Fcode%253DqJH4Bs%252F.....ameK%252FPh5S5Th%252FXttS.....D%253D%2526name-starts-with%253Dji
So I'm clearly doing at least one thing wrong. Following is a summary of my configuration. However, rather than attempting to debug my configuration, it might prove easier (more efficient) to describe all steps required to establish a working configuration.
Azure Function App
Platform features
Authentication / Authorization
App Service Authentication: On
Action to take when request is not authenticated
Log in with Azure Active Directory
Authentication Providers
Azure Active Directory Configured (Express: Existing App)
Advanced Settings Token Store
ALLOWED EXTERNAL REDIRECT URLS
Link to static website of storage container where Angular site is deployed
E.g., https://<storagecontainer>.z5.web.core.windows.net/
CORS
ALLOWED ORIGINS
https://<storagecontainer>.z5.web.core.windows.net/
http://localhost:4200
Function Signatures
`public static async Task<IActionResult> Function1([HttpTrigger(AuthorizationLevel.Function, "get", "post", "options", Route = null)] HttpRequest httpRequest, ILogger log) {`

Related

If possible, how to register front-end and back-end in a single application in Azure AD?

I have an application stack with a React SPA frontend and an Asp.net core web-api backend. Both resources had been successfully registered in AzureAD each with its own app and the authentication and authorization processes are working fine. However, would it be possible to use the same registration for both the front and backend in AD?
When using the AD Application ID from the backend in React:
auth: {
clientId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
authority: "https://login.microsoftonline.com/<tenantId>",
redirectUri: "http://localhost:3000"
}
I get the following error:
ServerError: invalid_request: AADSTS90009: Application 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'(api://xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) is requesting a token for itself. This scenario is supported only if resource is specified using the GUID based App Identifier.
I am using the MSAL library for the frontend.
Both the applications (front end and back end) need to be registered for sure in Azure AD.
As you are using client id of backend which is api to be secured , the Error is occurring.
Update client-id, tenant-id, redirect URI of front end application not backend api in configuration file based on application registration in Azure AD.
Then make sure to expose an API and grant admin consent to the API with required permissions.
Yes, this is possible. Your provider configuration looks correct, so check to make you app registration is setup properly. You will need the following things:
An SPA platform configuration with a redirect URI of http://localhost:3000
Add a scope (under 'Expose an API') and make sure your Application ID URI is created
Use the new scope in your MSAL authentication template

How to authenticate .net core web APIs using Azure AD by using office365

I have .net core 3.1 web api application deployed to Azure App Service. I want to set the authentication for APIs using Azure Active Directory with users logging through their office 365 account.
The architecture is like - I have my office 365 account ready with me. I request for a token to Azure AD. With the JWT, I get from azure AD, I should be able to call all the API endpoints in my web api application deployed in App Service.
Can you please explain what all configuration needs to be done in azure portal and code changes in startup.cs file.
Please refer to Quickstart: Protect an ASP.NET Core web API with Microsoft identity platform.
The Microsoft.AspNetCore.Authentication middleware uses a Startup
class that's executed when the hosting process initializes. In its
ConfigureServices method, the AddMicrosoftIdentityWebApi extension
method provided by Microsoft.Identity.Web is called.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration, "AzureAd");
}
You can protect a controller or controller methods using the
[Authorize] attribute.
namespace webapi.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
Deploying to Azure app service doesn't require more different configurations. Just modify the real API endpoint while calling it.
You can see more details from Scenario: Protected web API.
If you want to call the API from a web app, you could refer to Scenario: A web app that calls web APIs.
Remember that you need to register two Azure AD apps, one is for client app (front) and the other is for API app (backend). In the API app, you need to expose API. Then you need to configure the client app. Add the permission (scope) which is exposed by API app to the client app. These are all mentioned in the links above.
UPDATE:
I assume that you have created the two Azure AD apps on Azure portal and have configured the permissions between them. (if you haven't, please refer to Register the service app (TodoListAPI) and Register the client app (TodoListSPA))
Then you could test your API in Postman like this:
In the second screenshot:
Auth URL: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
Access Token URL: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Client id and client secret are from the Azure AD app which represents the client app (TodoListSPA).
Scope is the app id uri which is exposed by the Azure AD app which represents the service app (TodoListAPI).

Azure Application Proxy - Single Page Application - CORS issue

Components:
HTML, Bootstrap, AJAX Single Page Application (SPA) --> Deployed on-premise on tomcat 1
Azure Application Proxy 1 fronting SPA with pre-authentication as passthrough
REST API (API) --> Deployed on-premise on tomcat 2
Azure Application Proxy 2 fronting API with pre-authentication as Azure Active Directory
Microsoft MSAL Javascript library: https://github.com/AzureAD/microsoft-authentication-library-for-js
Flow:
User accesses SPA using Application Proxy 1 external URL eg. https://appProxy1.com/spa
The SPA has a sign-in button, when clicked invokes the Microsoft js MSAL library.
The user is presented a pop-up and upon entering credentials, is authenticated against Azure AD and an OAuth token is fetched.
Once authenticated successfully, the user is allowed to perform search on the SPA.
When the user searches, the SPA invokes the REST API using the application proxy 2 url eg. https://appProxy2.com/rest/.search
The REST call is blocked by browser due to CORS. It seems that Application Proxy/Azure AD is not allowing cross origin calls.
Note:
CORS has been enabled in the REST API code and SPA is able to invoke the REST API if Application Proxy 2 pre-authentication mode is set as passthrough.
I have gone through https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/application-proxy-understand-cors-issues. This workaround is possible if HTML application and REST service are deployed on the same application server.
Question:
Is there any option to enable/configure CORS on Application Proxy.
Currently there is no way to configure/enable the CORS on Application Proxy.
There a user voice request for CORS App Proxy. Please feel free to up vote this user voice request.

How to configure a WebApp & WebApi with different AAD App IDs?

I currently have two app services
Web App (Asp.net core 2 w/ front end in react)
Web Api (Asp.net core 2)
Note: Both are configured with different Azure active directory app id.
user signs into Web App and retrieves a token for it's own appId/ClientId/ClientSecret stored in tokencache.
from the WebApp, the user wants to talk to a WebAPI but needs to get a token since it's protected with AAD as well but it's a different app id/client id/client secret.
Problem:
When I try to do a AcquireTokenSilentAsync() for the web api, I get an error throwing that I the token is not in the cache?
It also seems that with depending if your using AAD v2.0 or v1.0 will determine if the web app and web api can have different app ids. So it seems like i would have to use AAD v1.0. With Asp.net core 2, it's not clear to me what OpenIdConnect is using or configured to use under the covers.
Question:
It's not clear to me why the acquire token silent async didn't work and failed. Does that only look for the token in the cache; otherwise it fails?
Is it possible to configure the token from web app to have permission to access web api resources. I notice that in the azure portal, you can selected resources like microsoft graph, but I don't know how you would associate a custom API. In my case, I want to get it running on my local machine before I move it all to azure.
If the web app token does not have permission to access the web api, do i need to do another login authentication with the user even thou both are within the same tenant?
Any Advice appreciated,
Derek
Yes, AcquireTokenSilentAsync will look into the cache, and see if it can find tokens. If it does, it will check to see if the access token is still valid and return that back. If the token is expired, it will use the refresh token to fetch a new access token and return that back. When this call fails, it's an indicator you need to perform an AcquireTokenAsync (which will likely show UI in the case silent already failed).
Yes, you can associate a web app to get tokens for your own custom web API. I'd recommend using Azure AD v1.0 (register the app in the Azure portal, ADAL library). You'll need to register the two apps (web app and the api), both will be type web app/api. In the API, you can register an App ID URI which will act as the resource identifier for this API. In your web app, you'll want to go into the Required Permissions, and add the Web API you have registered as a permission. Then in your web app, you'll need to use the ADAL library (alongside an OpenID OWIN middleware) to acquire a token for the resource as specified by the App ID URI field. Here's a code sample that implements the exact scenario you're describing (Web App/API in ASP.NET Core).

Azure AD implementation for SPA / WebAPI application having both on the port/HostEnv.?

I am trying to implement Azure AD authentication in a SPA application.
I am using an OWIN Startup.cs file in the WEB API and ADAL.js file in the angularjs front end application. (as per most of the tutorials suggestion)
My application does not have WebAPI and UI hosted in different domains/port. Basically, the WebAPI is referenced in the UI application project. (So no need for enabling CORS).
Now I have registered the applications on the Azure AD separately.
i.e. ClientApp -> Reply URL: http://localhost:90/ and
WebAPI -> APPID SignOn URL: http://localhost:90/Api/V1/
I have configured the ADAL.js and also getting the login page when trying to access the application from the UI. Also, I am able to retrieve the id.token generated after logging through the URL redirection. Also have decorated the web api controllers with the [Authorize] attribute.
My main concern here is that, if I try to call the WebAPI directly using tools like postman, I am getting access denied/Unauthroized Access (401). Can someone pls explain how can I test on my local env. with this scenario?
My sample request is: http://localhost:93/Api/V1/User/Preference (GET)
I am adding the token in the Authroization property of the Headers in the web api call.
Also a side note, I don't think I require OWIN/Startup.cs file for securing the WebAPI. The way I tried is that I got the token value send through the headers and got the AudienceID using JwtSecurityToken and parsing the contents of the Authroization property. Is this approach right as per security or I should stick to the OWIN implementation.
All of the ADAL JS tutorials have the backend API and the UX hosted on the same domain and port, with no need for CORS. See for example https://azure.microsoft.com/en-us/resources/samples/active-directory-javascript-singlepageapp-dotnet-webapi/. Those samples demonstrate that you need only ONE Azure AD registration, as the JS layer is in effect the exact same app as the web API.
We do have some samples demonstrating how to call an external API as well, and those do require CORS- but only for the extra API. The logic for calling the app backend remains the same (just one Azure AD app registration, no need for CORS).Postman doesn't offer any opportunity to pop out UX, hence one strategy you can follow is to obtain the tokens you need beforehand.
The use of OWIN allows you to centralize the auth setup; if you add auth in the controller, you'll need to repeat that logic for every new controller you add. Also, maintaining the code will be harder as you might use API surface that requires code changes when you update the assemblies, while that's less likely to happen if you use the standard middleware setup

Resources