0
votes

How can I enable authentication with a multitenant AngularJS single page application calling a multitenant service Web API using Azure AD?

This is the high level flow I am trying to enable:

      Multi-tenant AngularJS application [ClientApp] -> Multi-tenant ASP.NET Web API [ServicesApp]

I have a multi-tenant AngularJS application which requires Azure AD login using ADAL for JS (OpenID Connect). That web application is registered as a multi-tenant application ClientApp in a developer Azure AD, which I'll call DevAAD. I consented to use this ClientApp application in another Azure AD, which I'll call Tenant1. Once a user from the Tenant1 directory logs into the web application with their credentials into the login.microsoftonline.com portal, they are able to access the web UI. However, the UI is unable to call Web APIs on behalf of the user using the OAuth 2.0 Implicit Flow. This is the error message I am seeing in the Javascript code:

AADSTS65001: The user or administrator has not consented to use the application with ID '<ClientApp_ClientID>'. Send an interactive authorization request for this user and resource.

There is another Azure AD multi-tenant app representing backend Web API services called ServicesApp that is registered in the same DevAAD directory as the ClientApp UI application. The client ID and app ID URI of ServicesApp are the valid audiences for those services. This ServicesApp application has been consented to in the same Tenant1 directory. When invoked from a native client application with permissions to ServicesApp, the services are authorizing users from the Tenant1 directory using the OWIN middleware provided in System.IdentityModel.Tokens.Jwt 4.0.0 and the [System.Web.Http.Authorize] attribute in the controller.

Configuration details:

ClientApp

Azure AD application manifest has availableToOtherTenants set to true and oauth2AllowImplicitFlow set to true. ClientApp has permissions to access ServiceApp Azure AD application.

The AngularJS application has the following configuration:

adalAuthenticationServiceProvider.init(
{
    tenant: 'common',
    clientId: <ClientApp_ClientID>,
    endpoints: { <ServiceEndpoint> : <ServiceApp_ClientID> }
}, $httpProvider);

ServiceApp

ValidateIssuer is set to false in TokenValidationParameters object in WindowsAzureActiveDirectoryBearerAuthenticationOptions configuration object passed to IAppBuilder.UseWindowsAzureActiveDirectoryBearerAuthentication() "

knownClientApplications" property in "ServiceApp" Azure AD manifest is set to ["<ClientApp_ClientID>"]

I have not been able to locate any examples of a multi-tenant web application calling multi-tenant Web APIs, specifically a single page application built with AngularJS. How can this be implemented with Azure AD?

1
You mention that you "consented to use the app". Does that mean you actually went through our consent framework? Does your Web API have any downstream APIs that it needs to access (like the Graph API)? Did you see those additional permissions in your consent screen?Shawn Tabrizi
Yes, I used the consent framework to give "Tenant1" access to the ClientApp and ServiceApp applications by building a URL of the form http://account.activedirectory.windowsazure.com/Consent.aspx?ClientID=clientId and logging in with a user from the "Tenant1" directory with global admin role. Then I clicked "Allow Access", and can see both the ClientApp and ServiceApp as applications in the "Tenant1" directory in the classic portal.Ryan Turner
Hi Ryan, that appears to be a legacy process, and I am not certain that you are even doing that correctly. See here Building the link that grants access for external users (Legacy). See my answer below to find a more updated way to generate a sign in url and have the user consent to the app.Shawn Tabrizi

1 Answers

0
votes

You should try generating a Authorization Code URL using the template described here.

You can also copy this and replace the values with your own:

https://login.microsoftonline.com/common/oauth2/authorize?client_id=<appid>&response_type=code&redirect_uri=<replyurl>&resource=<resource>&prompt=admin_consent

Note at the end of the url I added the query string: "prompt=admin_consent". This is something that only a company administrator can do, and it will consent to your app for the entire tenant, so that no one else needs to consent in the future. Note that you can change this to "prompt=consent" if you want to only consent at an individual user level, or remove it all together if you do not want to force a consent prompt.

Let me know if this helps!