How To Configure TLS Mutual Authentication for Azure App Service


You can restrict access to your Azure App Service app by enabling different types of authentication for it. One way to do so is to authenticate using a client certificate when the request is over TLS/SSL. This mechanism is called TLS mutual authentication or client certificate authentication and this article will detail how to set up your app to use client certificate authentication.

Note: If you access your site over HTTP and not HTTPS, you will not receive any client certificate. So if your application requires client certificates you should not allow requests to your application over HTTP.

Configure App Service for client certificate authentication

To set up your app to require client certificates, you need to add the clientCertEnabled site setting for your app and set it to true. This setting is also able to be configured in the Azure portal under the SSL certificates blade.

You can use the ARMClient tool to make it easy to craft the REST API call. After you sign in with the tool, you will need to issue the following command:

ARMClient PUT subscriptions/{Subscription Id}/resourcegroups/{Resource Group Name}/providers/Microsoft.Web/sites/{Website Name}?api-version=2015-04-01 @enableclientcert.json -verbose

replacing everything in {} with information for your app and creating a file called enableclientcert.json with the following JSON content:

    "location": "My App Location",
    "properties": {
        "clientCertEnabled": true

Make sure to change the value of "location" to wherever your app is located for example, North Central US or West US etc.

You can also use to flip the clientCertEnabled property to true.

Note: If you run ARMClient from Powershell, you will need to escape the @ symbol for the JSON file with a back tick `.

Accessing the client certificate from App Service

If you are using ASP.NET and configure your app to use client certificate authentication, the certificate will be available through the HttpRequest.ClientCertificate property. For other application stacks, the client cert will be available in your app through a base64 encoded value in the "X-ARR-ClientCert" request header. Your application can create a certificate from this value and then use it for authentication and authorization purposes in your application.

Special Considerations for Certificate Validation

The client certificate that is sent to the application does not go through any validation by the Azure App Service platform. Validating this certificate is the responsibility of the app. Here is sample ASP.NET code that validates certificate properties for authentication purposes.

using System;
using System.Collections.Specialized;
using System.Security.Cryptography.X509Certificates;
using System.Web;

namespace ClientCertificateUsageSample
    public partial class cert : System.Web.UI.Page
        public string certHeader = "";
        public string errorString = "";
        private X509Certificate2 certificate = null;
        public string certThumbprint = "";
        public string certSubject = "";
        public string certIssuer = "";
        public string certSignatureAlg = "";
        public string certIssueDate = "";
        public string certExpiryDate = "";
        public bool isValidCert = false;

        // Read the certificate from the header into an X509Certificate2 object
        // Display properties of the certificate on the page
        protected void Page_Load(object sender, EventArgs e)
            NameValueCollection headers = base.Request.Headers;
            certHeader = headers["X-ARR-ClientCert"];
            if (!String.IsNullOrEmpty(certHeader))
                    byte[] clientCertBytes = Convert.FromBase64String(certHeader);
                    certificate = new X509Certificate2(clientCertBytes);
                    certSubject = certificate.Subject;
                    certIssuer = certificate.Issuer;
                    certThumbprint = certificate.Thumbprint;
                    certSignatureAlg = certificate.SignatureAlgorithm.FriendlyName;
                    certIssueDate = certificate.NotBefore.ToShortDateString() + " " + certificate.NotBefore.ToShortTimeString();
                    certExpiryDate = certificate.NotAfter.ToShortDateString() + " " + certificate.NotAfter.ToShortTimeString();
                catch (Exception ex)
                    errorString = ex.ToString();
                    isValidCert = IsValidClientCertificate();
                    if (!isValidCert) Response.StatusCode = 403;
                    else Response.StatusCode = 200;
                certHeader = "";

        // This is a SAMPLE verification routine. Depending on your application logic and security requirements, 
        // you should modify this method
        private bool IsValidClientCertificate()
            // In this example we will only accept the certificate as a valid certificate if all the conditions below are met:
            // 1. The certificate is not expired and is active for the current time on server.
            // 2. The subject name of the certificate has the common name nildevecc
            // 3. The issuer name of the certificate has the common name nildevecc and organization name Microsoft Corp
            // 4. The thumbprint of the certificate is 30757A2E831977D8BD9C8496E4C99AB26CB9622B
            // This example does NOT test that this certificate is chained to a Trusted Root Authority (or revoked) on the server 
            // and it allows for self signed certificates

            if (certificate == null || !String.IsNullOrEmpty(errorString)) return false;

            // 1. Check time validity of certificate
            if (DateTime.Compare(DateTime.Now, certificate.NotBefore) < 0 || DateTime.Compare(DateTime.Now, certificate.NotAfter) > 0) return false;

            // 2. Check subject name of certificate
            bool foundSubject = false;
            string[] certSubjectData = certificate.Subject.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string s in certSubjectData)
                if (String.Compare(s.Trim(), "CN=nildevecc") == 0)
                    foundSubject = true;
            if (!foundSubject) return false;

            // 3. Check issuer name of certificate
            bool foundIssuerCN = false, foundIssuerO = false;
            string[] certIssuerData = certificate.Issuer.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string s in certIssuerData)
                if (String.Compare(s.Trim(), "CN=nildevecc") == 0)
                    foundIssuerCN = true;
                    if (foundIssuerO) break;

                if (String.Compare(s.Trim(), "O=Microsoft Corp") == 0)
                    foundIssuerO = true;
                    if (foundIssuerCN) break;

            if (!foundIssuerCN || !foundIssuerO) return false;

            // 4. Check thumprint of certificate
            if (String.Compare(certificate.Thumbprint.Trim().ToUpper(), "30757A2E831977D8BD9C8496E4C99AB26CB9622B") != 0) return false;

            // If you also want to test if the certificate chains to a Trusted Root Authority you can uncomment the code below
            //X509Chain certChain = new X509Chain();
            //bool isValidCertChain = true;
            //foreach (X509ChainElement chElement in certChain.ChainElements)
            //    if (!chElement.Certificate.Verify())
            //    {
            //        isValidCertChain = false;
            //        break;
            //    }
            //if (!isValidCertChain) return false;

            return true;