Wednesday, December 21, 2016

Swagger : Using Swagger for Implicit Grant on Azure AD

Review my previous post - Swagger : Using Swagger for Implicit Grant on ADFS 4.0.

This builds on that.

Given that I couldn't get it working on ADFS, I thought I would try Azure AD (AAD).

One of the problems with AAD is that the web API calls are protected so if you want to use Swagger, authentication always fails.

I started with the OpenID Connect - web app. with web API sample. Follow the details to configure the web app. and the web API in AAD.

I'm running this on my PC.

This is a standard "adding items to a ToDo list" project.

Then I added swashbuckle etc. as per my post above.

As always, the gist is here.

Note that AAD needs the "resource" parameter, hence the extra line:

additionalQueryStringParams: new Dictionary() { { "resource", "https://azure-tenant.onmicrosoft.com/TodoListService" } }

Also, you do not need the clientSecret for implicit flow. This is because implicit flow is normally used for SPA and the secret key could be easily exposed in the JavaScript.

Looking at the ToDoListController:

if (ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/scope").Value != "user_impersonation")
            {
                throw new HttpResponseException(new HttpResponseMessage { StatusCode = HttpStatusCode.Unauthorized, ReasonPhrase = "The Scope claim does not contain 'user_impersonation' or scope claim not found" });
            }

            if (null != todo && !string.IsNullOrWhiteSpace(todo.Title))
            {
                todoBag.Add(new TodoItem { Title = todo.Title, Owner = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value });
            }

So we need a scope of  "user_impersonation" and we need a NameID claim.

We get the OAuth endpoints from the "View Endpoints" button in AAD. (Using the classic portal).


We need to add Swagger as an Azure AD application - the normal web site flow.

Ensure there is  "Reply URL" for:

  https://my pc/TodoListService/swagger/ui/o2c-html

We have to give this application permission to access the ToDoListService:


So what we are going to do is to use the same web API back-end but use Swagger as the web app.

Since there is a common back end, the ToDo list should reflect across both.

From the project, we add item "1234".


Now we try with Swagger.


and we get the 401.

So we click the red exclamation mark and we see:


Click "Authorize" and then authenticate with AAD.

Problem: we need to explicitly enable implicit flow. You do this via the manifest and then update:

"oauth2AllowImplicitFlow": true,

Now if we break-point at the NameID code and then check which attribute this matches in the token, we''ll see it matches the "sub":

...
"scp": "user_impersonation",
"sub": "nYa...Zow",
...

The OWIN classes must do this mapping internally viz. "sub" --> "NameID".


Now that we have authenticated, let's try again.


and we see that we get back the "1234" that we created with the web app.

Now we add a new item using the POST.

The object requires a "Title" and an "Owner" so we need to build one that looks like:

{
    "Title": "5678",
    "Owner": "nYa...Zow"
}

That returns OK and when we do another GET, we see:

[
  {
    "Title": "5678",
    "Owner": "nYa...Zow"
  },
  {
    "Title": "1234",
    "Owner": "nYa...Zow"
  }
]
 

Now go back to our web app.

so it all lines up.


Enjoy!



No comments: