How to Secure Your Application

Barış Tutakli
16 min readOct 23, 2023

Hi everyone,

The more developers expose APIs to the world, the more important it becomes to secure those APIs. If it’s a public API and it’s not properly secured, it can lead to catastrophic consequences because in this situation anyone can access the swagger or can make http calls to retrieve data from your data source. So, today’s topic is how to secure the Dotnet API via Azure AD B2C.

Note: I tried adding comments everywhere. Feel free to read comments😃

Prerequisites

  • Curiosity😃
  • Patience😅
## Table of Contents

1. **Introduction**
- Understanding Key Aspects

2. **Getting Started with Azure AD B2C**
- Creating a Source Application
- Exposing APIs for Swagger from the Source App

3. **Integrating Swagger with Your Application**
- Building an Application for Swagger
- Setting Up Redirect URLs

4. **Authorization Flows**
- Gathering Credentials
- Acquiring Tokens with Different Methods
- Client Credentials
- User Credentials

---------------------------- Part 2 ----------------------------

5. **Configure Startup.cs for JWT bearer based authentication**
- Validating Azure AD B2C Tokens
- Validating Azure AD Internal Tokens

6. **Multiple Token Validation**
- Combining Azure AD B2C and Azure AD Internal Tokens
- Extending Validation to Include Okta Tokens

7. **Enhancing Swagger Security with Azure AD B2C**
- Adding Azure AD B2C Authorization to Swagger
- Configuring Startup

8. **Additional Resources**
- [HowToSecureAPI.Demo](https://github.com/baristutakli/HowToSecureAPI.Demo)

* * *

Note: As this article covers many topics at the same time, feel free to skip the sections you don’t need😃

General overview about key aspects

The initial step in securing an application (Web API, React App, Angular App, etc.) involves verifying the identity of a user, device, or application. This is essential because it allows us to identify those who are using our applications and making requests to our application endpoints.

User can be authenticated through methods such as ‘username and password’ or Multi-Factor Authentication (MFA), while applications can be authenticated via ‘API Keys,’ ‘Client Credentials,’ and similar mechanisms.

The following step is to determine what actions the authenticated user or application is permitted to take within the API. This is called Authorizing sources (Authorization).

#authentication #authorization

Keywords and their meanings and use cases:

JWT (JSON Web Tokens)

As securely transmitting data between different applications is crucial, Json web token allows different parties to communicate each other by storing information securely about a user, an application and etc. It’s like key which stores information about a user or application and which is provided after a user logs in or application calls token endpoint with client credentials or another way.

JWT is composed of the following parts:

  • Header(alg, type)
  • Payload(aud, iss, sub, email, expire time…)
  • Signature

Recommended sites to analyse JWT:

Getting Started with Azure AD B2C

In order to secure our application using Azure AD B2C, we need to register applications. Let’s continue by creating a source application. This source application’s primary purpose is to make the API accessible, enabling other applications to send requests to it. The responsibilities and abilities of this application may vary based on your team’s specific requirements.

Creating a source application in Azure AD B2C

  • Begin by accessing the Azure Portal.
  • In the search bar, enter “Azure AD B2C” and select the Azure AD B2C service.
  • Find and click “App registrations” on the left side of the screen.
  • Click new registration
  • Provide a name for your application.
  • Select the supported account type.
  • Grant admin consent
  • Finally, complete the registration process.

Note: You can do the same by following the screenshot below

Now as we created a source application, the next step is to create an application for Swagger. You can follow the same steps to create swagger application. In the following section, we’re enabling other applications to make requests to our application by exposing an API.

Exposing APIs for Swagger from the Source App

  • Begin by accessing the Azure Portal.
  • In the search bar, enter “Azure AD B2C” and select the Azure AD B2C service.
  • Find and click “App registrations” on the left side of the screen.
  • Click on the source application(for me it is BarisTestApp)
  • Click on “Expose an API”
  • Set an Application ID URI
  • Click on “Add a scope
  • Fill out the scope name,display name and description
  • Add the scope

As you created a new scope, we need to add the intended permission in the Swagger application and grant admin consent. Then, the swagger application will be able to make requests to the source application with right scopes. If you want to get token with application credentials in further steps, you need to add app roles under “Manifest”.

Caution: If there is a responsible in your company, application client id, auth URL, token URLs and etc will be provided to you.

Set redirect URLs for Swagger app

By adding redirect URLs, Azure AD B2C can redirect the authenticated user to a specific Swagger application redirect URL once the user successfully signs in(in this case it is swagger application redirect url).

  • Begin by accessing the Azure Portal.
  • In the search bar, enter “Azure AD B2C” and select the Azure AD B2C service.
  • Find and click “App registrations” on the left side of the screen.
  • Click on the swagger application
  • Click on “Authentication
  • Click on “Add a platform
  • Select “Single-page application
  • Add the swagger redirect URL and save

Note: You can do the same by following the screenshots below

I added the following redirect URLs for different purposes:

**Swagger Redirect URL**
- https://localhost:5001/swagger/oauth2-redirect.html

**JWT Token Claims Viewer**
- https://jwt.ms

**Postman Redirect URL**
- https://oauth.pstmn.io/v1/callback

Authorization Flows

In this section, I’m going to explain the “Client Credentials” authorization flow and the “Authorization Code(PKCE)” flow to get token from Azure AD B2C.

Oauth 2.O Client Credentials

To acquire token with client credentials, you need to send the followings inside request body:

  1. Client ID
  2. Client Secret
  3. Scope
  4. Grant Type

You can fill in the fields as shown in the screenshot below:

Authorization Code (PKCE)

To acquire token with user credentials, you need the followings”:

  1. Client ID
  2. Client Secret
  3. Scope
  4. Grant Type
  5. Authorization URL
  6. Access Token URL

You can fill in the fields as shown in the screenshot below:

After filling in the fields and clicking the generate access token, you will be redirected to login page where you can type your username and password to get token.

Package References

Because of having legacy project, I wrote the following code in dotnet core 3.1. However, you can do similar things in other dotnet versions.

<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.32" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="3.1.32" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="4.0.0" />
<PackageReference Include="Microsoft.Identity.Web" Version="2.13.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.1.4" />

Note: In the code there are two different authorization handlers, feel free to write more handler and customize them for your project

How to Validate Azure AD B2C Token

#tokenvalidation #AzureADB2C #authentication

In this step, we are going to create a AzureB2CValidationConfig class which will be bound from the appsettings configuration. All you need is to fill in the values below then create the same config class under your project. you can look at the appsettings.Development.Json file via the Github Repository link at the end of the article.

public class AzureB2CValidationConfig
{
public string Authority { get; set; }
public List<string> AllowedAppIds { get; set; }
public string MetadataAddress { get; set; }
public List<string> ValidAudiences { get; set; }
public List<string> ValidIssuers { get; set; }
}

Fill in the values of the json below and add it to appsettings file.

  // Azure AD B2C Token Validation
// Use the following if you have an application registered Azure AD B2C
// the following config allow tou to validate Azure AD B2C token
"AzureB2CValidationConfig": {
"Authority": "",
"AllowedAppIds": [ "" ], // Allowed B2C app ids for auth handlers if you want to use it
"MetadataAddress": "",
"ValidAudiences": [ "" ],
"ValidIssuers": [ "" ]
}

The value inside the json file will be bound to the AzureB2CValidationConfig class via the following way:

// Azure AD B2C Validation Config
// If you have application registered in Azure AD B2C
var azureB2CValidationConfig = Configuration.GetSection("AzureB2CValidationConfig").Get<AzureB2CValidationConfig>();
services.AddSingleton(azureB2CValidationConfig);

Here is the extension method to enable you to add jwt authentication configurations. So, you can copy and past the class and call it in startup.

/// <summary>
/// Azure AD B2C
/// Add Authentication For Token Validation
/// </summary>
public static class AzureADB2CAddAuthenticationForTokenValidation
{
private const string AzureB2CAuthorizationServer = "AzureB2CAuthorizationServer";

/// <summary>
/// This extension class is created for validate Azure AD B2C token
/// </summary>
/// <param name="services"></param>
/// <param name="azureB2CValidationConfig"></param>
/// <returns></returns>
public static IServiceCollection AddAuthenticationForAzureADB2C(this IServiceCollection services, AzureB2CValidationConfig azureB2CValidationConfig)
{
var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(azureB2CValidationConfig.MetadataAddress, new OpenIdConnectConfigurationRetriever());

var openidconfig = configManager.GetConfigurationAsync().Result;

services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
// Azure AD B2C TOKEN VAlAIDATION
.AddJwtBearer(AzureB2CAuthorizationServer, options =>
{
options.Authority = azureB2CValidationConfig.Authority;
options.MetadataAddress = azureB2CValidationConfig.MetadataAddress;

options.RequireHttpsMetadata = false;
options.IncludeErrorDetails = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudiences = azureB2CValidationConfig.ValidAudiences,
ValidIssuers = azureB2CValidationConfig.ValidIssuers,
RequireExpirationTime = true,
ValidateLifetime = true,

ValidateIssuerSigningKey = true,
IssuerSigningKeys = openidconfig.SigningKeys,
};
});

return services;
}
}

Let’s call it in startup.cs

// Uncomment the code below for Azure AD B2C Only
#region Token Validation for Azure AD B2C
// services.AddAuthenticationForAzureADB2C(azureB2CValidationConfig);
#endregion

As we added authentication, the next step securing endpoints using a specific policy. Let’s create a policy and add authorization to an endpoint based on a specific policy.

How to add authorization and policy which requires AddAuthenticationSchemes

// Add Authorization for endpoints 
services.AddAuthorization(options =>
{

// Uncomment the code below for Azure AD B2C Only
// Only Azure AD B2C apps allowed
// Don't forget to change required scopes for your own scopes
options.AddPolicy(ApiConstants.UserReadPolicyName, policyBuilder =>
policyBuilder
// uncomment the two line below if you want to add authorization handlers to your API
// You can find authorization handler via the github repository
.AddAuthenticationSchemes(AzureB2CAuthorizationServer)
// .AddRequirements(new AllowedApplicationsRequirement(azureB2CValidationConfig.AllowedAppIds))
// .AddRequirements(new B2CAppScopeRequirement(new List<string> { ApiConstants.UsersReadScope, ApiConstants.UsersManageScope }))
.Build());

});

As we configured startup, we can continue adding authorization to one of the endpoints to allow azure ad internal applicaitons to be able to make requests if they have enough permissions to call this endpoint.

/// <summary>
/// Azure AD B2C Policy
/// The prupose of this endpoint to show you how the policy works
/// </summary>
/// <returns></returns>
[HttpGet("/acceptB2CToken")]
[Authorize(ApiConstants.UserReadPolicyName)]
public IActionResult acceptB2CToken()
{
return Ok(Users);
}

Azure AD B2C Token Authentication and Swagger Authorization Branch Link

Now you can get a token from postman and send it to “acceptb2ctoken” to see whether your request reach to the endpoint or not :)

How to Validate Azure AD Token

#tokenvalidation #AzureAD #authentication

In this step we are going to create a AzureADValidationConfig class which will be bound from the appsettings configuration. All you need is to fill in the values below then create the same config class under your project. you can look at the appsettings.Development.Json file via the Github Repository link.

public class AzureADValidationConfig
{
public List<string> AllowedAppIds { get; set; }
public string MetadataAddress { get; set; }
public List<string> ValidAudiences { get; set; }
public List<string> ValidIssuers { get; set; }
}

Fill in the values of the json below with the data provided

// Azure AD Token Validation
// Use the following if you have an application registered Azure AD
// the following config allow tou to validate Azure AD token
"AzureADValidationConfig": {
"AllowedAppIds": [ "" ], // Allowed internal app ids
"MetadataAddress": "",
"ValidAudiences": [ "" ],
"ValidIssuers": [ "" ]
}

Add the following code to ConfigureServices method in Startup. The value inside the json file will be bound to the AzureADValidationConfig class via the following way:

// Azure AD Validation Config
// If you have application registered in Azure AD Internal
var azureADvalidationconfig = Configuration.GetSection("AzureADvalidationconfig").Get<AzureADValidationConfig>();
services.AddSingleton(azureADvalidationconfig);

Here is the extension method to enable you to add jwt authentication configurations. So, you can copy and past the class and call it in startup. Instead of getting signature using configuration manager, you can also try to store signig keys in secret file and read it from there.

/// <summary>
/// Add Authentication For Azure AD Token Validation
/// </summary>
public static class AddAuthenticationForForAzureADInternalOnly
{
private const string InternalAzureAuthorizationServer = "InternalAzureAuthorizationServer";

/// <summary>
/// This extension class is created for validate Azure AD
/// </summary>
/// <param name="services"></param>
/// <param name="azureADvalidationconfig"></param>
/// <returns></returns>
public static IServiceCollection AddAuthenticationForAzureADInternal(this IServiceCollection services, AzureADValidationConfig azureADvalidationconfig)
{
var InternalADconfigManager = new ConfigurationManager<OpenIdConnectConfiguration>(azureADvalidationconfig.MetadataAddress, new OpenIdConnectConfigurationRetriever());

var InternalADopenidconfig = InternalADconfigManager.GetConfigurationAsync().Result;

services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
// Azure AD INTERNAL TOKEN VAlAIDATION
.AddJwtBearer(InternalAzureAuthorizationServer, options =>
{
options.MetadataAddress = azureADvalidationconfig.MetadataAddress;

options.RequireHttpsMetadata = false;
options.IncludeErrorDetails = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudiences = azureADvalidationconfig.ValidAudiences,

ValidateIssuer = true,
ValidIssuers = azureADvalidationconfig.ValidIssuers,

ValidateIssuerSigningKey = true,
IssuerSigningKeys = InternalADopenidconfig.SigningKeys,

ValidateLifetime = true,
ValidTypes = new List<string>() { "JWT" }

};
});

return services;
}
}

Let’s call it in startup.cs

// Uncomment the code below for Azure AD Only
#region Token Validation for Azure AD
// services.AddAuthenticationForAzureADInternal(azureADvalidationconfig);
#endregion

As we added authentication, the next step securing endpoints by a specific policy. Let’s create a policy and add authorization to an endpoint based on a specific policy.

How to add authorization and policy which requires AddAuthenticationSchemes

! Do not forget to change scopes with you app scopes

// Add Authorization for endpoints 
services.AddAuthorization(options =>
{
// Uncomment the code below for Azure AD Only
// Only Azure AD INTERNAL apps allowed
// Don't forget to change required scopes for your own scopes
options.AddPolicy(ApiConstants.InternalUserReadPolicyName, policyBuilder =>
policyBuilder
.AddAuthenticationSchemes(InternalAzureAuthorizationServer)
// uncomment the two line below if you want to add authorization handlers to your API
// You can find authorization handler via the github repository
// .AddRequirements(new AllowedApplicationsRequirement(azureADvalidationconfig.AllowedAppIds))
// .AddRequirements(new InternalAppScopeRequirement(new List<string> { ApiConstants.InternalUserReadScope }))
.Build());
});

As we configured startup, we can continue adding authorization to one of the endpoints to allow azure ad internal applicaitons to be able to make requests if they have enough permissions to call this endpoint.

Azure AD Token Authentication Branch link

Now you can get a token from postman and send it to “acceptinternaladtoken” to see whether your request reach to the endpoint or not :)

How to Validate Azure AD B2C and Azure Ad Internal Token

#tokenvalidation #AzureADB2C #AzureAD #authentication

In this step we are going to create a AzureADAndB2CValidationConfig class which will be bound from the appsettings configuration. All you need is to fill in the values below then create the same config class under your project. You can find appsettings.Development.Json file, “AzureADB2C” and “AzureAD” classes via the Github Repository link at the end of the article.

  /// <summary>
/// AZURE AD AND AZURE AD B2C
/// </summary>
public class AzureADAndB2CValidationConfig
{
public AzureADB2C AzureADB2C { get; set; }
public AzureAD AzureAD { get; set; }
public List<string> AllowedAppIds { get; set; }
}

Fill in the values of the json below with the data provided and add it to appsettings file.

  // Azure AD B2C and Azure AD  Token Validation
// the following config allow tou to validate Azure AD B2C, Azure AD token
"AzureADAndB2CValidationConfig": {
"AzureADB2C": {
"Authority": "",
"MetadataAddress": "",
"ValidAudiences": [ "" ],
"ValidIssuers": [ "" ]
},
"AzureAD": {
"MetadataAddress": "",
"ValidAudiences": [ "" ],
"ValidIssuers": [ "" ]
},
"AllowedAppIds": [ "" ]// internal app ids and B2C app ids
}

Add the following code to ConfigureServices method in Startup. The value inside the json file will be bound to the AzureADAndB2CValidationConfig class via the following way:

// Azure AD Internal and Azure AD B2C validation Config
// If you have application registered in Azure AD B2C and Azure AD Internal
var azureADAndB2CValidationConfig = Configuration.GetSection("AzureADAndB2CValidationConfig").Get<AzureADAndB2CValidationConfig>();
services.AddSingleton(azureADAndB2CValidationConfig);

Here is the extension method to enable you to add jwt authentication configurations. So, you can copy and past the class and call it in startup.

/// <summary>
/// Azure Ad and Azure AD B2C
/// Add Authentication For Azure AD Internal And Azure AD B2C Tokens
/// </summary>
public static class MultipleAddAuthenticationForAzureADInternalAndAzureADB2CTokens
{
private const string InternalAzureAuthorizationServer = "InternalAzureAuthorizationServer";
private const string AzureB2CAuthorizationServer = "AzureB2CAuthorizationServer";

/// <summary>
/// This extension class is created for validate Azure AD and Azure AD B2C tokens
/// </summary>
/// <param name="services"></param>
/// <param name="multipleValidationConfig"></param>
/// <returns></returns>
public static IServiceCollection AddAuthenticationForAzureADInternalAndAzureADB2C(this IServiceCollection services, AzureADAndB2CValidationConfig azureADAndB2CValidationConfig)
{
var InternalADconfigManager = new ConfigurationManager<OpenIdConnectConfiguration>(azureADAndB2CValidationConfig.AzureAD.MetadataAddress, new OpenIdConnectConfigurationRetriever());
var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(azureADAndB2CValidationConfig.AzureADB2C.MetadataAddress, new OpenIdConnectConfigurationRetriever());

var InternalADopenidconfig = InternalADconfigManager.GetConfigurationAsync().Result;
var openidconfig = configManager.GetConfigurationAsync().Result;

services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
// Azure AD INTERNAL TOKEN VAlAIDATION
.AddJwtBearer(InternalAzureAuthorizationServer, options =>
{
options.MetadataAddress = azureADAndB2CValidationConfig.AzureAD.MetadataAddress;

options.RequireHttpsMetadata = false;
options.IncludeErrorDetails = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudiences = azureADAndB2CValidationConfig.AzureAD.ValidAudiences,

ValidateIssuer = true,
ValidIssuers = azureADAndB2CValidationConfig.AzureAD.ValidIssuers,

ValidateIssuerSigningKey = true,
IssuerSigningKeys = InternalADopenidconfig.SigningKeys,

ValidateLifetime = true,
ValidTypes = new List<string>() { "JWT" }

};
})
// Azure AD B2C TOKEN VAlAIDATION
.AddJwtBearer(AzureB2CAuthorizationServer, options =>
{
options.Authority = azureADAndB2CValidationConfig.AzureADB2C.Authority;
options.MetadataAddress = azureADAndB2CValidationConfig.AzureADB2C.MetadataAddress;

options.RequireHttpsMetadata = false;
options.IncludeErrorDetails = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudiences = azureADAndB2CValidationConfig.AzureADB2C.ValidAudiences,
ValidIssuers = azureADAndB2CValidationConfig.AzureADB2C.ValidIssuers,
RequireExpirationTime = true,
ValidateLifetime = true,

ValidateIssuerSigningKey = true,
IssuerSigningKeys = openidconfig.SigningKeys,
};
});

return services;
}
}

Let’s call it in startup.cs

// Uncomment the code below for Azure AD and Azure AD B2C Token Validation
#region Multiple Token Validation for Azure AD and Azure AD B2C
services.AddAuthenticationForAzureADInternalAndAzureADB2C(azureADAndB2CValidationConfig);
#endregion

As we added authentication, the next step securing endpoints by a specific policy. Let’s create a policy and add authorization to an endpoint based on a specific policy.

How to add authorization and policy which requires AddAuthenticationSchemes

! Do not forget to change scopes with you app scopes

  // Add Authorization for endpoints 
services.AddAuthorization(options =>
{

// Uncomment the code below for Azure AD and Azure AD B2C Token Validation
//Internal AD And B2C User Read Policy Name
// Azure AD B2C and Azure AD Token validation
// Don't forget to change required scopes for your own scopes
options.AddPolicy(ApiConstants.InternalAndB2CUserReadPolicyName, policyBuilder =>
policyBuilder
.AddAuthenticationSchemes(InternalAzureAuthorizationServer, AzureB2CAuthorizationServer)
// uncomment the two line below if you want to add authorization handlers to your API
// You can find authorization handler via the github repository
// .AddRequirements(new AllowedApplicationsRequirement(azureADAndB2CValidationConfig.AllowedAppIds))
// .AddRequirements(new B2CAndAzureADInternalScopeRequirement(new List<string> { ApiConstants.UsersReadScope, ApiConstants.UsersManageScope, ApiConstants.InternalUserReadScope }))
.Build());

});

As we configured startup, we can continue adding authorization to one of the endpoints to allow azure ad internal applicaitons to be able to make requests if they have enough permissions to call this endpoint.

/// <summary>
/// Azure AD INTERNAL And Azure AD B2C apps allowed
/// This is created to show you Azure AD INTERNAL And Azure AD B2C authorization flow, only internal ad and Azure AD B2C token will be validated and internal apps and Azure AD B2C apps will be able to make request
/// </summary>
/// <returns></returns>
[HttpGet("/acceptInternalADTokenAndB2CToken")]
[Authorize(ApiConstants.InternalAndB2CUserReadPolicyName)]
public IActionResult AcceptInternalADTokenAndB2CToken()
{
return Ok(Users);
}

Now you can get a token from postman and send it to “acceptInternalADTokenAndB2CToken” to see whether your request reach to the endpoint or not :) feel free to send Azure AD internal token and B2C token.

Azure AD Internal And Azure AD B2C Token Authentication and Swagger Authorization using B2C Branch Link

How to Validate Azure AD and Azure AD B2C and OKTA Token

#tokenvalidation ##AzureAD #AzureADB2C #OKTA #authentication

If you have tightly coupled applications and you really need Okta token validation too, you can use AddMultipleAuthentication extension method within MultipleAddAuthenticationForTokenValidationIncludingOkta class Then, follow similiar steps that you did above. Then, you’ll be able to validate and secure and endpoint.

However, please be aware that we do not recommend using this approach unless your applications are highly coupled. You can find the code sample in the HowToSecureAPI.Demo github repository. This Okta auth flow won’t work after deadline.

HowToSecureAPI.Demo Github Repository Link

Adding Azure AD B2C Authorization to your application swagger

#swagger #authorize

In this step we are going to create a AzureADB2CSwaggerConfig class which will be bound from the appsettings configuration. All you need is to fill in the values below then create the same config class under your project. you can look at the appsettings.Development.Json file via the Github Repository link at the end of the article.

public class AzureADB2CSwaggerConfig
{
public List<string> ApiServerUris { get; set; }
public string OAuthClientId { get; set; }
public string OAuthClientName { get; set; }
public string RedirectUri { get; set; }
public string AuthorizationUrl { get; set; }
public string TokenUrl { get; set; }
public Dictionary<string, string> OAuthScopesAndDescriptions { get; set; }

}

Fill in the values of the json below with the data provided and add it to appsettings file.

// Use this for swagger auhtorization
"AzureADB2CSwaggerConfig": {
"OAuthClientId": "", // Swagger app client id
"OAuthClientName": "Swagger app name", // Swagger app name
"RedirectUri": "",
"AuthorizationURL": "", // AuthorizationURL
"TokenURL": "", // TokenURL
// the scopes below for swagger authorize
"OAuthScopesAndDescriptions": {
"openid": "openid", // scope and description
"add scope 1 description here": "https://{your domain name}/{scope 1}", // b2c scope which looks like hyperlink
"add scope 2 description here": "https://{your domain name}/{scope 2}" // b2c scope which looks like hyperlink
},
"ApiServerUris": [
"https://localhost:5001/" // api server uri
]
}

Note: Don’t forget to add Swagger application scopes to the scope requirements while configuring policies.

Add the following code to ConfigureServices method in Startup. The value inside the json file will be bound to the AzureADB2CSwaggerConfig class via the following way:

// Azure AD B2C Swagger 
var azureADB2CSwaggerConfig = Configuration.GetSection("AzureADB2CSwaggerConfig").Get<AzureADB2CSwaggerConfig>();
services.AddSingleton(azureADB2CSwaggerConfig);

Here is the extension methods for swagger:

/// <summary>
/// Extension for swagger documentation
/// </summary>
public static class AzureADB2cSwaggerExtension
{
private static string SecurityDefinitionName = "oauth2";
/// <summary>
/// Add swagger gen configurations
/// </summary>
/// <param name="services"></param>
/// <param name="swaggerConfig"></param>
/// <returns></returns>
public static IServiceCollection SetupSwaggerDocumentation(this IServiceCollection services,
AzureADB2CSwaggerConfig swaggerConfig)
{

services.AddSwaggerGen(options =>
{
options.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
var provider = services.BuildServiceProvider().GetRequiredService<IApiVersionDescriptionProvider>();
foreach (var description in provider.ApiVersionDescriptions)
options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description));

//Locate the XML file being generated by ASP.NET...
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
//... and tell Swagger to use those XML comments.
options.IncludeXmlComments(xmlPath);

// remove obsolete actions from swagger
options.IgnoreObsoleteActions();

// set scopes in a well format that swagger expect.
var scope = new Dictionary<string, string>();

foreach (var rightName in swaggerConfig.OAuthScopesAndDescriptions)
{
scope.Add(rightName.Value, $"{rightName.Key}");
}

var flows = new OpenApiOAuthFlows
{
Implicit = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(swaggerConfig.AuthorizationUrl), // Azure AD B2C authorize endpoint
TokenUrl = new Uri(swaggerConfig.TokenUrl),// Azure AD B2C token endpoint
Scopes = scope
}
};

//First we define the security scheme
options.AddSecurityDefinition(SecurityDefinitionName, new OpenApiSecurityScheme
{
Type = SecuritySchemeType.OAuth2,
Flows = flows,
In = ParameterLocation.Header,
Name = "Authorization",
BearerFormat = "JWT",
Scheme = "bearer",
Description = "JWT Authorization header using the Bearer scheme."
});

// To make sure that the bearer token is send in authorization
options.AddSecurityRequirement(new OpenApiSecurityRequirement{
{
new OpenApiSecurityScheme{
Reference = new OpenApiReference{
Id = SecurityDefinitionName, //The name of the previously defined security scheme.
Type = ReferenceType.SecurityScheme
}
},new List<string>()
}
});

});

return services;
}

/// <summary>
/// Add use of swagger to IApplicationBuilder
/// </summary>
/// <param name="app"></param>
/// <param name="provider"></param>
/// <param name="graphSwaggerConfig"></param>
/// <returns></returns>
public static IApplicationBuilder UseSwaggerDocumentation(this IApplicationBuilder app,
IApiVersionDescriptionProvider provider, AzureADB2CSwaggerConfig graphSwaggerConfig)
{
app.UseSwagger(options =>
{
options.PreSerializeFilters.Add((swagger, httpReq) =>
{
swagger.Servers = graphSwaggerConfig.ApiServerUris.Select(uri => new OpenApiServer { Url = uri }).ToList();
});
});

app.UseSwaggerUI(options =>
{

options.DisplayOperationId();
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerEndpoint($"{description.GroupName}/swagger.json",
description.GroupName.ToUpperInvariant());
}

options.OAuthClientId(graphSwaggerConfig.OAuthClientId); // swagger application client id

options.OAuthAppName(graphSwaggerConfig.OAuthClientName); // swagger application name

options.OAuthUsePkce();

options.OAuth2RedirectUrl(graphSwaggerConfig.RedirectUri); // swagger application redirect url

});

return app;
}

/// <summary>
/// This section is used to give you general information about this Demo API.
/// </summary>
/// <param name="description"></param>
/// <returns></returns>
static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description)
{
var info = new OpenApiInfo
{
Version = "v1",
Title = "How To Secure API.Demo API Swagger Specification",
Description = "This demo API is created to show you how to secure your dotnet api using Azure AD B2C",
TermsOfService = new Uri("https://demoapi.com/terms"),// random url
Contact = new OpenApiContact
{
Name = "Baris Tutakli",
Email = "https://www.linkedin.com/in/baristutakli/",
// Url = new Uri("")
}
};

if (description.IsDeprecated)
{
info.Description += " This API version has been deprecated.";
}

return info;
}
}

You can find more details via the repository link: HowToSecureAPI.Demo Github Repository Link

Would you like to help me to better my articles?🙂 Do let me know your view on this 🙂 See you next time! Thank you for reading!

--

--