IIS Client Certificate Authentication (mTLS): Require, Map, and Debug 403.7 / 403.16 Errors

Client certificate authentication (mutual TLS) is the strongest access control IIS offers without a VPN, but it fails in confusing ways: a 403.16, a 403.7, or a browser that silently ignores your prompt. This guide covers configuring IIS to require client certificates, mapping certificates to Windows identities, and the certificate-trust chain problems that cause most failures.

How IIS client certificate auth actually works

During the TLS handshake, the server requests a certificate from the client. IIS then applies one of four SSL settings: Ignore, Accept, Require, or Require with a mapping. “Require” validates the certificate against trusted roots; “Require with mapping” additionally ties the certificate to a Windows account or uses a custom rule.

SSL client cert modeBehaviourUse case
IgnoreClient certs are ignored entirelyPublic sites
AcceptRequests one, validates if presentOptional/soft rollout
RequireRejects handshake or returns 403 if absent/invalidLocked-down internal apps
Require + mappingMaps cert to a Windows user (Many-to-One or One-to-One)Per-user authorization without AD password

Step 1: require client certificates at the site level

# Requires WebAdministration module, elevated shell
Import-Module WebAdministration

# Require a client certificate on the default site
Set-WebConfigurationProperty -PSPath 'IIS:\Sites\Default Web Site' `
  -Filter 'system.webServer/security/access' -Name 'sslFlags' `
  -Value 'Ssl, SslRequireCert'

# Or accept but do not require (useful during rollout)
Set-WebConfigurationProperty -PSPath 'IIS:\Sites\Default Web Site' `
  -Filter 'system.webServer/security/access' -Name 'sslFlags' `
  -Value 'Ssl, SslNegotiateCert'

# Verify
Get-WebConfigurationProperty -PSPath 'IIS:\Sites\Default Web Site' `
  -Filter 'system.webServer/security/access' -Name 'sslFlags'
  • Ssl — require SSL for this site.
  • SslNegotiateCert — ask the client for a certificate (Accept).
  • SslRequireCert — demand a valid client certificate (Require).
  • SslMapCert — use the configured mapping (One-to-One or Many-to-One) to log the user on as a Windows identity.

Step 2: make the issuing CA trusted by the server

The number one reason “Require” fails is that the server does not trust the CA that signed the client certificate. Client certs from an internal PKI must have their root and any intermediate CAs imported into the machine’s Trusted Root and Intermediate stores.

# Import a root CA into the machine store (replace path)
Import-Certificate -FilePath "C:\PKI\root-ca.cer" `
  -CertStoreLocation "Cert:\LocalMachine\Root"
Import-Certificate -FilePath "C:\PKI\intermediate-ca.cer" `
  -CertStoreLocation "Cert:\LocalMachine\CA"

# List trusted roots and confirm yours is present
Get-ChildItem Cert:\LocalMachine\Root | Where-Object Subject -match 'Contoso'

Step 3: map a certificate to a Windows identity

Mapping lets IIS log the request in as a real Windows user, so NTFS ACLs and User.Identity.Name work as usual. A Many-to-One mapping applies one rule (for example, match the Subject’s CN) to many certificates; One-to-One maps an exact cert to a specific account.

# One-to-one mapping: exact certificate thumbprint to a Windows account
$site = "IIS:\Sites\Default Web Site"
$hash = (Get-PfxCertificate "C:\certs\client.pfx").Thumbprint
New-WebConfigurationProperty -PSPath $site `
  -Filter "system.webServer/security/authentication/iisClientCertificateMappingAuthentication" `
  -Name "." -Value @{enabled='true';oneToOneCertificateMappingsEnabled='true'}
New-Item -Path "$site/iisClientCertificateMappingAuthentication/oneToOneMappings" `
  -Value @{certificate=[System.Convert]::ToBase64String(
      (Get-PfxCertificate "C:\certs\client.cer").RawData);
    userName='CONTOSO\svc_webclient'; password='P@ssw0rd!'} -Force

If you prefer mapping by Subject rather than by exact certificate — useful when certificates are renewed regularly — use Many-to-One with a rule like MatchAll and an expression extracting the CN. Enable the IIS Client Certificate Mapping Authentication role feature first, or these cmdlets fail with “configuration section not recognized”.

Diagnosing the classic errors

ErrorMeaningFix
403.7Client certificate required but not presentedBrowser has no cert installed, or you chose the wrong one
403.16Client certificate untrusted or invalidImport the signing CA chain into the machine store
403.13Client certificate revokedCheck CRL/OCSP reachability from the server
403.17Certificate expiredRenew the client cert
No prompt at allTLS renegotiation disabled or wrong cipherConfirm the site is HTTPS-only and uses TLS 1.2+

Two subtleties cause most support tickets. First, certificate selection is client-side — Chrome and Edge use the Windows store, Firefox historically used its own, so the same user can fail in one browser and succeed in another. Second, revoked-certificate checking requires the server to reach the CRL distribution point, which a firewalled VPS often cannot. If the CDP is unreachable and iisClientCertificateMappingAuthentication is strict, valid certs get rejected — publish the CRL somewhere reachable or relax revocation checking deliberately.

Hardening and operational notes

Client certificates move the authentication burden to the TLS layer, which is a strong control, but the operational work is in certificate lifecycle rather than configuration. Plan for renewal, revocation, and distribution before you enforce “Require”, otherwise a single expired certificate locks a user out with a 403.17 and no helpful log line.

  • Keep “Accept” first. Roll out with SslNegotiateCert, collect telemetry on which certificates are presented, then switch to Require. Flipping straight to Require on a live site locks out every client without a cert.
  • Short validity, automated renewal. Prefer 90-day client certificates renewed automatically by the PKI or an ACME client over multi-year certs that nobody tracks.
  • Publish the CRL somewhere reachable. A VPS that cannot reach the CA’s CRL distribution point will treat valid certificates as unverifiable.
  • Log the subject. Enable IIS logging of the client certificate subject so failed authentications are traceable to a specific certificate, not just a source IP.

Testing without a browser in the way

# Test mTLS from the command line (curl 8+ on the server or a workstation)
curl -v --cert client.pem --key client.key https://internal.example.com/ -o NUL

# Or with a PFX
curl --cert client.pfx:password https://internal.example.com/ -I

When curl reports a handshake failure, run it with -v and read the certificate request and verify lines — they tell you instantly whether the server asked for a cert and whether the chain validated. If client certificates are only one part of a broader lockdown, pair them with the rest of the baseline is covered in our server hardening guide, and size the instance so revocation and OCSP lookups do not compete with your app for bandwidth — see our Windows VPS comparison.

Leave a Comment