Enable Swagger to authenticate against Azure AD
Swashbuckle has brought swagger goodness to .Net web API applications. It is pretty cool to have the auto-generated swagger ui, swagger-json and other features light up with just a few clicks.
However as of now – the ‘Try It’ button on applications which are using any kind of authentication doesn’t work as expected, and usually requires some extra efforts / tweaks to enable any kind of authentication.
Let’s look at the steps we need to perform to enable swagger generated UI make authenticated calls to a Web API using Azure AD as the authentication mechanism.
Assuming that web API application is already integrated with an Azure Active Directory (AAD) application, and swashbuckler is already integrated. Users are able to open swagger UI and are getting a 401 on “Try it Out” button.
Following steps are targeted to help users enable swagger UI
First we need to create a new application in Azure AD console to enable swagger UI client integrate with web application. Following steps requires the use to have permissions to create a new application on Azure AD console
- From AD management portal, create a dedicated application on Azure AD which will be used by swagger UI client to authenticate against the web application.
- Select 'swagger' application in application list and go to configure section. Scroll down to 'permissions to other applications' and press 'Add application' button
- In appeared popup change filter setting 'SHOW' to 'All Apps' and press confirm on the right side. Search for your application from the search, select your desired web application and press confirm.
- Web Api application will now be visible to application list. On right side of added web Api find 'delegated permissions' dropdown and select 'Access {web api name}'
- Add reply URL - ' https://{your_swagger_url}/swagger/ui/o2c-html ' to reply URL list. This should be the URL of the application environment where we want to enable swagger. Alternatively, this can be a static dedicated common URL, which can be used as a kind of application realm.
- Click on the Manage manifest button in the command bar, and select Download manifest. Open the JSON application manifest file and set the “oauth2AllowImplicitFlow” value to “true”. By default, it is “false”.
- In the downloaded manifest json, search for "oauth2AllowImplicitFlow". It will be false, set it to true.
- Save the updated JSON file and upload it by clicking the Manage manifest button in the command bar, selecting Upload manifest, browsing to your updated manifest file and then selecting it. Once uploaded, this new application is now configured to use OAuth 2.0 Implicit Grant to authenticate users.
- Go to the 'keys' section and select required duration (currently available 1 or 2 years’ options) for new key. Create and save new Key.
- In the bottom, click on 'VIEW ENDPOINTS' button and copy OAuth 2.0 Authorization Endpoint
- On the web api application on azure portal and scroll to the 'permissions to other application' in. Ensure that 'Windows Azure Active Directory' has 'read directory data' permission checked in Application Permission dropdown and 'Read directory data' and 'Sign in and read user profile' permissions in 'Delegated Permissions' dropdown
Now that we’ve configured the AAD application for swagger, lets tweak the web application itself to enable using the azure ad client.
As mentioned above, assuming swashbuckler integration is alrea dy existing on the target web application. Go to source repository and make following changes
- Edit SwaggerConfig.cs file and search for OAuth configuration. It should be starting with 'c.OAuth2("oauth2") ... ' line
-
- Find 'AuthorizationUrl' method parameter and copy-paste value from OAuth 2.0 Authorization Endpoint from azure. This is the value we collected in previous step.
- Add new scope: .Scopes(scopes =>
{
scopes.Add("user_impersonation", "Access {app_name}");
});
This section should look like:
c.OAuth2("oauth2")
.Description("OAuth2 Implicit Grant")
.Flow("implicit")
.AuthorizationUrl(string.Format("https://login.microsoftonline.com/{0}/oauth2/authorize", swaggerAdTenant))
.Scopes(scopes =>
{
scopes.Add("user_impersonation", "Access " + swaggerAppName);
});
- Scroll down and enable an operation filter for OAuth2SecuritymentsFilter.
c.OperationFilter<AssignOAuth2SecurityRequirements>();
- Add code to the AssignOAuth2SecurityRequirements class as followed :
public class AssignOAuth2SecurityRequirements: IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
// Determine if the operation has the Authorize attribute
var authorizeAttributes = apiDescription
.ActionDescriptor.GetCustomAttributes<AuthorizeAttribute>();
if (!authorizeAttributes.Any())
return;
// Initialize the operation.security property
if (operation.security == null)
operation.security = new List<IDictionary<string, IEnumerable<string>>>();
// Add the appropriate security definition to the operation
var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
{
{ "oauth2", Enumerable.Empty<string>() }
};
operation.security.Add(oAuthRequirements);
}
}
- Scroll down to c.EnableOAuth2Support method. Method overload which we will use is now available as a part of Swashbuckle 5.0.3 version
We need to invoke and set method parameters:
-
- clientId: - CLIENT ID value from swagger application configuration on azure portal as “Client ID” method parameter
- clientSecret: - Generated key from Azure portal in the “Client Secret” method parameter
- realm:- One of the valid “Reply URL” we configured on the portal.
- appName:– Can be value of application name we created for swagger. ‘Swagger’
- scopeSeparator :– Can be the default value of ' ' (whitespace)
- additionalQueryStringParams :- This is a string dictionary wherein we pass “resource” as key and the “Token Validation Param Audience” as the value. This value is typically a configuration value on the AAD configuration on Web application. It is typically configured in the config file as “audience” and is used in server side code to validate the specific resource on the application. On server side, earlier it used to correspond to WindowsAzureActiveDirectoryBearerAuthenticationOptions.Audience Now, that property is deprecated and this corresponds to TokenValidationParameters.AllowedAudience
var stringDict = new Dictionary<string, string>();
stringDict.Add("resource", swaggerAdAudience);
Finally, ensure that the API methods in API controllers are decorated with [Authorize] tag.
Once we are done with above steps, we will be good to go! Let’s deploy the solution and open swagger-ui in browser
We’ll now see an authorization button on the API methods
Once we click on to enable the authentication, a popup will ask for the scopes to do the Azure AD authentication against. Not this scope will be same as we declared in the swagger config
Click on the scope and click authorize. Users will be redirected to corresponding Azure AD authentication flow, where-in user will need to sign-in to the azure active directory with the corresponding credentials.
Once signed-in, system will check if the current signed in users have access to the Azure AD application for the web api. If user is granted access, they will be redirected to the swagger ui for the web application in an authenticated context.
Now users can click the ‘Try It Out!’ link and will get the applicable behavior
Disclaimer: Majority of the above flow is derived from the discussion on GitHub @ https://github.com/domaindrivendev/Swashbuckle/issues/671 , particularly thanks to “Oleksandr-Tokmakov”’s comments.
I had added more content and additional steps based on my specific implementation. Hope this helps someone.
Comments
- Anonymous
August 05, 2016
Should also check for [Authorize] attribute on Controller, not just on the Action. var authorizeAttributes = apiDescription.GetControllerAndActionAttributes(); - Anonymous
September 26, 2016
The comment has been removed - Anonymous
November 12, 2016
How to enable this for Daemon flow? When I implement this, it asks for Email & Password. A Daemon flow (authentication between 2 apps) does not include users since it's just permissions between 2 apps not users. So Users are not involved in the flow. - Anonymous
December 16, 2016
Too complex - Anonymous
January 28, 2017
Hi All,I have followed exact same steps as mentioned, but upon clicking on the authorize button. i am redirected to a link that says " Sorry, but we're having trouble signing you in. We received a bad request. ". Can you please point me to what might be the issue here ? I have double checked all the mentioned steps and followed them correctly.