Enabling SSL Client Certificates in ASP.NET Web API

You can get an excellent description of what client certificates are and how they work in this article – if you want to really understand this post take a minute to read it. In a nutshell, client certificates allows a web app to authenticate users by having the client provide a certificate before the HTTP connection is established (during the SSL Handshake). It’s an alternative to providing username/password. As the article explicitly mentions, client certificates have nothing to do with HTTPS certificates – that means you can have HTTPS communication without client certificates. However, you cannot have client certificates work without enabling HTTPS on your site.

ASP.NET Web API can take advantage of client certificates to authenticate clients as well. In this post, I’ll walk you through the steps of configuring client certificates in your IIS and test it on a Web API. Please notice that this steps should only be executed on a Development environment, as a production environment might require a more rigorous approach.

1. Let’s first create the necessary certificates (as explained here). To do this open the Visual Studio Developer Command Prompt and run the following command. Type the certificate password as prompted. This first command will create a ‘Root Certification Authority’ certificate. If you want more details, you can read about how these commands this MSDN article.

[code language=”powershell”]
makecert.exe -n "CN=Development CA" -r -sv DevelopmentCA.pvk DevelopmentCA.cer

2. Install the DevelopmentCA.cer certificate in your Trusted Root Certification Authorities for the Local Machine store using MMC (right-click over the Trusted Root Certification Authorities folder | All Tasks | Import).


Note: For production scenarios, this certificate will obviously not be valid. You will need to get an SSL certificate from a Certificate Authority (CA). Learn more about this here.

3. Now let’s create an SSL certificate in a .pfx format, signed by the CA created above, using the following 2 commands. The first command will create the certificate and the second one will convert the .pvk certificate containing the private key to .pfx. This certificate will be used as the SSL certificate.

[code language=”powershell”]
makecert -pe -n "CN=localhost" -a sha1 -sky exchange -eku
-ic DevelopmentCA.cer -iv developmentCA.pvk -sv SSLCert.pvk SSLCert.cer

pvk2pfx -pvk SSLCert.pvk -spc SSLCert.cer -pfx SSLCert.pfx -po 123456

4. Install the SSLCert.pfx certificate in the Personal store of Local Computer using MMC. Notice that the certificate shows it was issued by the Development CA.


5. Run this third command to create a private-key certificate signed by the CA certificate created above. The certificate will be automatically installed into the Personal store of  Current User, as shown in the figure below. Notice also that the Intended Purpose shows Client Authentication.

[code language=”powershell”]
makecert.exe -pe -ss My -sr CurrentUser -a sha1 -sky exchange -n "CN=ClientCertificatesTest"
-eku -sk SignedByCA -ic DevelopmentCA.cer -iv DevelopmentCA.pvk


6. Now let’s get into the code. A good place in ASP.NET Web API 2 to validate the client certificate is an ActionFilterAttribute, by calling GetClientCertificate on the request message (see some examples here). An action filter is an attribute that you can apply to a controller action — or an entire controller — that modifies the way in which the action is executed.

[code language=”csharp” highlight=”5″]
public override void OnActionExecuting(HttpActionContext actionContext)
var request = actionContext.Request;

if (!this.AuthorizeRequest(request.GetClientCertificate()))
throw new HttpResponseException(HttpStatusCode.Forbidden);

7. Use your local IIS to host your Web API code. Under the site configuration, open the site bindings and configure HTTPS using the SSL certificate created above. Select the ‘localhost’ certificate create in step 3.


8. Open the SSL Settings under your web site in IIS and select Accept. The options available are:

  • Ignore: Will not request any certificate (default)
  • Accept: IIS will accept a certificate from the client, but does not require one
  • Require: Require a client certificate – to enable this option, you must also select “Require SSL”


Changing this value will add the following section in the ApplicationHost.config (by default located under C:WindowsSystem32inetsrvconfig). The value SslNegotiateCert equals the Accept we’ve selected before.

[code language=”xml” highlight=”6″]

<location path="subscriptions">
<access sslFlags="SslNegotiateCert" />

Note: If you want to enable this from Web.config instead of using ApplicationHost.config, notice that the  <access> element is not allowed to be overridden from the Web.config by default. To enable overriding the value from Web.config you can change the overrideModeDefault value of the <access> section like this: <section name=”access” overrideModeDefault=”Deny” />. Please notice this is not recommended for production servers, as this would imply changing the behavior for the entire IIS server.

9. Now when browsing to the site using HTTPS in a browser like Internet Explorer you should get prompted for a client certificate. Select the ClientCertificatesTest client certificate you’ve created. As we’ve only selected ‘Accept’ in IIS SSL Settings, if you click Cancel, you should be able to browse to the site all the same, even if you didn’t provide a client certificate.

Also, notice that you are now shown an untrusted certificate warning because you’ve installed the Development CA cert as a Trusted Root Certification Authority.


Finally, if you want to know how to perform a request programmatically using client certificates, you can check this Gist.

Note: I’m actually not an expert in security, this post is mostly the results of a couple of battles, some of them won some of them lost – so feel free to provide feedback!


  • Artur says:

    Thank. Very interesting post for Developer’s which need work with certificate.

  • Sven says:


    do you know, if there is a setting, to only allow one special client certificate (e.g. in your case “WHERE Issuer=’DevelopmentCA'” ? I want to suppress the clientcertificate dialog, because our users choose always the wrong one ^^

  • Rajiv says:

    Thanks a lot buddy. Really helped me out

  • Mark says:

    If you’re encountering problems on Firefox (or other browsers), check this answer: http://stackoverflow.com/a/14351008

  • Akhilesh says:

    This Solution works on local machine only when we host application on server and configure SSL on server and accessing application from client machine having e to ken attached it does not promts for Certificate

  • Akhilesh says:

    Please help me to implement same in client server environment

  • Wally Highsmith says:

    Windows 2012 introduced stricter certificate store validations.
    According to KB 2795828: Lync Server 2013 Front-End service cannot start in Windows Server 2012,
    the Trusted Root Certification Authorities (i.e. Root) store can only have certificates that are self-signed.
    If that store contains non-self-signed certificates, client certificate authentication under IIS
    returns with a 403.16 error code.

    To solve the problem, you have to remove all non-self-signed certificates from the root store.
    This PowerShell command will identify non-self-signed certificates:

    Get-Childitem cert:\LocalMachine\root -Recurse |
    Where-Object {$_.Issuer -ne $_.Subject}

    These non-self-signed certificates can be moved into the Intermediate Certification Authorities (i.e. CA) store:

    For example:

    Get-Childitem cert:\LocalMachine\root -Recurse |
    Where-Object {$_.Issuer -ne $_.Subject} |
    Move-Item -Destination Cert:\LocalMachine\CA
    See: http://stackoverflow.com/questions/26247462/http-error-403-16-client-certificate-trust-issue

Leave a Reply