In my earlier post about the problem with ACS I promised to blog about how to configure Microsoft Azure Active Directory (MaaD) to support a client app calling a Web API using a client secret (as opposed to presenting an authentication dialogue to an interactive user).
To get started (and save me a lot of typing) I suggest you get started by reading Johan Danforth’s great blog post on how to do this for an interactive login as this is where I started)
If you follow the instructions carefully you will have a Web API published and registered with AD and you will have updated the application’s manifest file in AD to allow you to configure permissions to it in other applications in the directory)
You will also have a client app, also configured in AD (as a ‘native application’) in which you have configured permission to access the Web API and the relevant call to issue the request to AD to get the token and to the Web API bearing that token.
Crucially – you will have written very little code to do this. AD, the ADAL Nuget Package and the OWIN library (on the server side) will have done all the heavy lifting for you.
What I wanted to do is to remove the interactive user from the equation – in my scenario a user uses a web app, which in turn uses my Web API, but this is not a delegation scenario, the web app can call the web api on its own right.
To achieve this, I needed to make two changes from Johan’s example –
Firstly I needed to register my web app as a client app which isn’t a native client as a native client app in AD does not have configuration for client secret. so I’ve added a new app to my directory, made sure to select the ‘web application and/or web api application’ for the type and configured a name, APP ID and (in my case a mock) sign-on url.
I had also set the permission from my web client application to the web-api, in the same way that I did earlier for my native client.
And finally – I added a new key by selecting a duration and copied the secret (important: the key cannot be accessed after its creation, make sure to copy it)
With the AD configuration done I make the relevant changes to the client code to use the client secret rather than the interactive sign on
The original code includes the following line -
var ar1 = ac.AcquireToken(“https://. . . WEB Api APP ID URI. . .”,
"e9b5d821-. . .Native Client’s Client Id",
new Uri("http:// . . Native Client’s APP ID URI"));
so support authenticating using client secret, this needed to change to
ClientCredential cc = new ClientCredential("e9b5d821-Web Client Client ID",
"Qxc49i. . .client secret generated in AD portal");
var ar1 = ac.AcquireToken(“https://. . . WEB Api APP ID URI. . .”, cc);
and with this done (the rest of the code remains unchanged), when I now run the client, rather than being prompt to authenticate the call to the web api is made and authentication is done using the client secret.
In closing, for completeness, the interaction really translates to two web requests – the first is to AD to retrieve the access token, and in my case this looks like this –
POST https://login.windows.net/[1db093b3-…AD tenant ID]/oauth2/token HTTP/1.1
grant_type=client_credentials&client_id=[e9b5d821-…client app client id]&client_secret=[Qxc49iXn…client secret]&resource=[https%3A%2F%2F…..protected resource app ID]
This request, if successful, returns a JSON response which includes a JWT token from AD that can be used in subsequent requests to the application. That subsequent requests looks like this (token trimmed for readability) –
GET http://localhost/WebApplication1/api/Values HTTP/1.1
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJh……..
Finally – whilst I was experimenting with this I encountered a few errors that are worth noting here –
The one I was most confused by was
"AADSTS90014: The request body must contain the following parameter: ‘client_secret or client_assertion’."
In my case this happened when I tried to request a token from AD through my client app when it was still coded for interactive user sign-on. when the AD application used was native, using the interactive logon code worked fine, as soon as I tried to use a web api AD application without changing the code to use client_secret I got the error above.-
Final thought – ACS is slowly being embedded in AD but for the time being I find the experience a little bit fiddly and short of documentation (in particular the Manifest file manipulation) and lack of flexibility
The integration above currently only works with JWT tokens and client secret authentication (SWT is not supported I believe as is certificate based authentication) but this will be corrected over time, I’m sure.
[cross posted on the Solidsoft blog]