To me Azure Active Directory Authentication has always been a little confusing. Even though there are good code samples and good documentation around how to get it done, it has been a little confusing to understand how all the pieces fit together. This time the task I had to do was even more difficult. Firstly, I wanted to create a web API that can be authenticated by multiple tenants and not just one and secondly, I could not use OWIN and set it up easily as shown in the samples. I will explain the reason behind the second requirement shortly. Being able to achieve this has made a lot of things clear to me. So I thought better to jot it down. If you are aware of Azure AD app registrations and the code to authenticate web API and are just looking for a way to make it work multi-tenant without having to register an app in each tenant’s directory, I recommend you jump straight to the section, Making it work for multiple tenants. Others, read on.
Register an Azure AD application
In order to be able to authenticate your API with Azure AD, you need to create an application in the active directory which would have all the required permissions to do the job. If you don’t have access to the Azure AD of your tenant, contact your administrator.
- Sign in to Azure portal and click on Azure Active Directory in the side pane
- Go to App registrations and and click on New app registration
- Give an intuitive name for your app. In the sign on URL, you can put the URL of the Home page of the Web API that you are trying to secure.
- After the app is created, select it from the list of apps and go to the properties of the app. The app id URL will be already filled with https://<your-tenant-name.onmicrosoft.com>/GUID. You can change this if you need. Note down the ObjectId, AppId (aka ClientId in some tutorials or code samples) and the APP ID url.
and you are done. You can go in Required Permissions option to check what permissions does your app have. By default the app will be given the permission to sign in and read user profile. If you want your Web API to have any of the other permissions you can select them here. While logging in user will be shown a consent where he will see all the permissions given to this app.
As I mentioned, as shown in most of the tutorials on this topic, I could not just add a OWIN startup class and wire-up the AD authentication. Reason being, the application I was working on already had some authentication mechanism set up. I did not want to touch that but I wanted the API controller I was bout to write to be authenticated using AD authentication. So I wrote an authentication filter attribute for Web API. I could put that on any API controller or even a single API. Here is a code of the filter:
Configuration values must be set as follows :
key="ida:Audience" value="APP ID URL of the Web API app registered in AD"
Note that in the code, even though we have assigned the audience and the issuer (tenant which is identifying the JWT token) we have set ValidateAudience and ValidateIssuer to false. The reason behind this is, we want to allow any tenant user to be able to access this API. If we set ValidateIssuer to true, the validation mechanism would not allow tokens sent by other tenants and if we set ValidateAudience to be true then it would not allow any app other than this app to consume this API.
After this you test you API using some web API tester. Remember to add a bearer JWT token as a Authorization header while you make a request to your Web API and you are done. You can test the GET APIs in the browser. In order to that you can go to the Sign-On URL you put in step 2 which would prompt user login and then access the GET API.You can also use Chrome extension Postman to test your API, which has a nice feature of letting you login and get the token which can be added to the header. Otherwise you can write your own client app and test it out your self.
Client – The API consumer
Once the web API is ready, you might want to build a client app which would consume this API. To do this you would have to register one more app in the Azure AD – a native app. The procedure is almost the same.
- While creating you need to select “Native app”.
- In the RedirectURL, put the URL of the client app.
- If at all you write 2 Client applications that consume the same API, let’s say one in Csharp hosted at csharpapp.com and one in Angular hosted at angularapp.com, then you must add both these of urls in the Redirect URI’s list.
- One more important thing to do is to add clientId of the Client app to “KnownClientApplications” of the API app. To do this go to the API app, click on “manifest” in the top bar and then update the following entries:
"Client ID of the client app"
- Here is the code to call the API.
Config values :
key="ida:ClientId" value="Client ID of the client app"
key="ida:RedirectUri" value="Home page URL of the client web app"
key="apiAppResourceId" value="APP ID URL of the web api app in Azure AD"
key="apiBaseAddress" value="Base address of you web API"
- Now browse/ run your client app, it will show a login window. Login with with your tenant’s credentials and you are in!
Making it work for multiple tenants
This is the tricky thing. If you refer the Microsoft documentation around building a multi-tenant web API authenticated by Azure AD, you will be able to get almost all the above steps. They have even said that this will work for any other tenant. If at all at this point you try to login with credentials of some other tenant, you will see this error:
Sorry for the bad resolution of the image. It says that “Application with identifier <ClientId of your native client azure AD app>” does not exist in the directory “<the tenant identifier where you are trying to login>”. This means that you need to register the apps in the directory of this tenant as well which would have new clientIds. If you are building a SaaS application and you want to make it work across all the tenants then you don’t want to go to each tenant’s azure portal and create two apps and maintain all those clientIds and pick up the right one when user from that tenant tries to log in. Too much work! If this is not a new application and you are just enabling AD authentication on an app that already is in production, like I was trying to do, this is simply not an option.
They do have a way to avoid this, but it is no where mentioned in the documentation. I was scratching my head over this and trying a few things my self, when I stumbled upon this setting in manifest of the client app in Azure AD :
Flipped “availableToOtherTenants” to true and then opened my client application. Tried logging in with the credentials of a tenant where no apps were registered, and I got the consent screen. Something like this:
So I had registered both web api app and native client app in the directory of tenant “xshweta” (for example), on xrahul , I did not create any app, I just went to my app and logged in with credentials of tenant xrahul and it worked.
If you have access, you can go to the Azure Active Directory of this tenant in azure portal then go to the “Enterprise applications => All applications”, there you will see an app with the same name as your native client app. Open it up and check the app Id (clientId) it is the same as the app you registered. This app serves as an identifier for the app installed in the parent tenant.
Now your app will work across all the tenants. 🙂
Had I had read the “Modern Authentication with Azure Active Directory for Web Applications” penned by Vittorio Bertocci earlier I would have saved a lot of my time. I tried to look for the solution in the documentation which I could not find. I recommend you give it a read for thorough understanding on this subject.
Hope this helps the people who are looking for a quick solution to their problem.
Until next time.