Using Swagger as a client for an ADFS protected API

Rory Braybrook
The new control plane
4 min readJul 29, 2019

I wrote a post recently about protecting an API with ADFS using the client credentials flow.

Note this is for Active Directory Federation Services (ADFS) 4.0 (Server 2016) and above.

This has a ToDoList API backend and a console application that acts as a client calling the API.

Then I was asked about using Swagger to test API’s protected by ADFS. Here Swagger acts as the client.

Maybe my Google foo was off but I couldn’t find a single article about this. There’s lots of questions and the usual amount of Internet rubbish but nothing that gave me any solid leads.

Hence this article …

I copied the above project and added Swashbuckle (Swagger for .NET).

This simply requires you to add the Nuget package:

Install-Package Swashbuckle -Version 5.6.0 (or whatever the latest is)

This adds a SwaggerConfig.cs.

The class “AssignOAuth2SecurityRequirements” needs to be added when you un-comment this line:

c.OperationFilter<AssignOAuth2SecurityRequirements>();

All the code can be found in the gist.

ADFS is configured in SwaggerConfig via:

c.OAuth2(“oauth2”)
.Description(“OAuth2 Implicit Grant”)
.Flow(“implicit”)
.AuthorizationUrl(“https://my-adfs/adfs/oauth2/authorize")
.TokenUrl(“https://my-adfs/adfs/oauth2/token")
.Scopes(scopes =>
{
scopes.Add(“email”, “Email details”);
});

I’ve just used one scope but you can add more.

The application group parameters are configured via:

c.EnableOAuth2Support(
clientId: “74a2038e-f26f-40c2-ad4d-a0224a048ddd”,
clientSecret: null,
realm: “test-realm”,
appName: “Swagger UI”,
additionalQueryStringParams: new Dictionary<string, string>() { { “resource”, “https://localhost:44321/” } }
);

The “resource” parameter is needed to ensure that the OAuth “aud” in the JWT is correct.

In the “client credentials” example above, change the “ValidAudience”:

app.UseActiveDirectoryFederationServicesBearerAuthentication(
new ActiveDirectoryFederationServicesBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters()
{
SaveSigninToken = true,
//ValidAudience = “https://localhost/ToDoListService”
ValidAudience = “https://localhost:44321/”
},

MetadataEndpoint = “https://my-adfs/FederationMetadata/2007-06/FederationMetadata.xml"
});

Looking at the Swagger documentation, it supports implicit flow. That implies a SPA and in terms of ADFS application groups, that implies a web browser accessing a web application.

This creates a native application and a web application.

For the native application, note that you need two “Redirect URI”. The clientID is copied to the configuration as above.

For the web application, the first identifier is done for you (it’s the clientID).

You need to add the second.

I have one custom claims rule:

c:[]
=> issue(claim = c);

i.e. issue everything.

“Email” is the only scope checked.

Run up the application:

Add “swagger” to the base URL in the browser:

https://localhost:44321/swagger/

You should see:

Click the “GET”.

Note the red exclamation mark.

This means authentication is required. Click it.

Click the “email” scope (remember we configured it in Swagger) and “Authorize”.

This takes us to the ADFS login screen:

Login and we see:

Note we now have a blue information icon.

So let’s POST a ToDo.

And now the GET.

And we can see that it worked!

The “Curl” command shows the JWT.

The JWT is:

Note the “scp” = “email” in the JWT.

All good!

--

--

Rory Braybrook
The new control plane

NZ Microsoft Identity dude and MVP. Azure AD/B2C/ADFS/Auth0/identityserver. StackOverflow: https://bit.ly/2XU4yvJ Presentations: http://bit.ly/334ZPt5