Implement certificate authentication in ASP.NET Core for an Azure B2C API connector

This article shows how an ASP.NET Core API can be setup to require certificates for authentication. The API is used to implement an Azure B2C API connector service. The API connector client uses a certificate to request profile data from the Azure App Service API implementation, which is validated using the certificate thumbprint.


Blogs in this series

Add extra claims to an Azure B2C user flow using API connectors and ASP.NET Core

Setup Azure App Service

An Azure App Service was created which uses .NET and 64 bit configurations. The Azure App Service is configured to require incoming client certificates and will forward this to the application. By configuring this, any valid certificate will work. The certificate still needs to be validated inside the application. You need to check that the correct client certificate is being used.

Implement the API with certificate authentication for deployment

The AddAuthentication sets the default scheme to CertificateAuthentication. The AddCertificate method adds the required configuration to validate the client certificates used with each request. We use a self signed certificate for the authentication. If a valid certificate is used, the MyCertificateValidationService is used to validate that it is also the correct certificate.

var builder = WebApplication.CreateBuilder(args);



.AddCertificate(options =>
options.AllowedCertificateTypes = CertificateTypes.SelfSigned;

options.Events = new CertificateAuthenticationEvents
OnCertificateValidated = context =>
var validationService = context.HttpContext.RequestServices.GetService<MyCertificateValidationService>();

if (validationService != null && validationService.ValidateCertificate(context.ClientCertificate))
var claims = new[]
new Claim(ClaimTypes.NameIdentifier, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer),
new Claim(ClaimTypes.Name, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer)

context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
context.Fail(“invalid cert”);

return Task.CompletedTask;

builder.Host.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration
//[email protected]”../certauth.txt”,
[email protected]”D:homeLogFilesApplication{Environment.UserDomainName}.txt”,
fileSizeLimitBytes: 1_000_000,
rollOnFileSizeLimit: true,
shared: true,
flushToDiskInterval: TimeSpan.FromSeconds(1)));

The middleware services are setup so that in development no authentication is used and the requests are validated using basic authentication. If the environment in not development, certificate authentication is used and all API calls require authorization.

var app = builder.Build();

if (app.Environment.IsDevelopment())


if (!app.Environment.IsDevelopment())


The MyCertificateValidationService validates the certificate. This checks if the certificate used has the correct thumbprint and is the same as the certificate used in the client application, in these case the Azure B2C API connector.

public class MyCertificateValidationService
private readonly ILogger<MyCertificateValidationService> _logger;

public MyCertificateValidationService(ILogger<MyCertificateValidationService> logger)
_logger = logger;

public bool ValidateCertificate(X509Certificate2 clientCertificate)
return CheckIfThumbprintIsValid(clientCertificate);

private bool CheckIfThumbprintIsValid(X509Certificate2 clientCertificate)
var listOfValidThumbprints = new List<string>
// add thumbprints of your allowed clients

if (listOfValidThumbprints.Contains(clientCertificate.Thumbprint))
_logger.LogInformation($”Custom auth-success for certificate {clientCertificate.FriendlyName} {clientCertificate.Thumbprint}”);

return true;

_logger.LogWarning($”auth failed for certificate {clientCertificate.FriendlyName} {clientCertificate.Thumbprint}”);

return false;

Setup Azure B2C API connector with certification authentication

The Azure B2C API connector is setup to use a certificate. You can create the certificate anyway you want. I used the CertificateManager Nuget package to create a RSA 512 certificate with a 3072 key size. The thumbprint from this certificate needs to be validated in the ASP.NET Core API application.

The Azure B2C API connector is added to the Azure B2C user flow. The use flow requires all the custom claims to be defined and the values can be set in the API Connector service. See the first post in this blog group for details.

Creating an RSA 512 with a 3072 size key

You can create certificates using .NET Core using the CertificateManager Nuget package which provides some helper methods for creating the X509 certificates as required.

class Program
static CreateCertificates _cc;
static void Main(string[] args)
var builder = new ConfigurationBuilder()
var configuration = builder.Build();

var sp = new ServiceCollection()

_cc = sp.GetService<CreateCertificates>();

var rsaCert = CreateRsaCertificateSha512KeySize2048(“localhost”, 10);

string password = configuration[“certificateSecret”];
var iec = sp.GetService<ImportExportCertificate>();

var rsaCertPfxBytes = iec.ExportSelfSignedCertificatePfx(password, rsaCert);
File.WriteAllBytes(“cert_rsa512.pfx”, rsaCertPfxBytes);


public static X509Certificate2 CreateRsaCertificateSha512KeySize2048(string dnsName, int validityPeriodInYears)
var basicConstraints = new BasicConstraints
CertificateAuthority = false,
HasPathLengthConstraint = false,
PathLengthConstraint = 0,
Critical = false

var subjectAlternativeName = new SubjectAlternativeName
DnsName = new List<string>

var x509KeyUsageFlags = X509KeyUsageFlags.DigitalSignature;

// only if certification authentication is used
var enhancedKeyUsages = new OidCollection
// OidLookup.ServerAuthentication
// OidLookup.CodeSigning,
// OidLookup.SecureEmail,
// OidLookup.TimeStamping

var certificate = _cc.NewRsaSelfSignedCertificate(
new DistinguishedName { CommonName = dnsName },
new ValidityPeriod
ValidFrom = DateTimeOffset.UtcNow,
ValidTo = DateTimeOffset.UtcNow.AddYears(validityPeriodInYears)
new RsaConfiguration
KeySize = 3072,
HashAlgorithmName = HashAlgorithmName.SHA512

return certificate;

Running the applications

I setup two user flows for running and testing the applications. One is using ngrok and local development with basic authentication. The second is using certification authentication and the deployed Azure App service. I published the API to the App service and run the UI application. When the user signs in, the API connector is used to get the extra custom claims from the deployed API and is returned.


Leave a Reply

Your email address will not be published. Required fields are marked *