Short answer

A browser can use a client certificate for mTLS if the certificate (with its private key) is installed in the operating system's or browser's certificate store. When a server requires a client certificate, the browser shows a prompt where the user picks which certificate to send. This gives strong, phishing-resistant authentication — but the installation friction and the prompt make it impractical for large, anonymous user bases. So it is used mostly internally and for high-assurance access.

The format: .p12 / PFX

For a browser to present a client certificate, it needs both the certificate and the private key. This is typically delivered as a PKCS#12 file (.p12 or .pfx), protected by a password. You build it from a separate key and certificate:

openssl pkcs12 -export \
  -inkey client.key \
  -in client.crt \
  -certfile ca.crt \
  -out client.p12 \
  -name "Alice - Internal Portal"

-certfile ca.crt includes the CA in the bundle so the chain travels with it. The user then imports the .p12 file into their certificate store (macOS Keychain, the Windows Certificate Store, or the browser's own setting).

What the user actually experiences

When the user visits an mTLS-protected page, this happens:

  1. The server sends a CertificateRequest as part of the handshake.
  2. The browser finds the installed certificates whose issuer matches the server's accepted CAs.
  3. If there is more than one, the browser shows a dialog for the user to choose a certificate.
  4. The browser sends the chosen certificate, and the server validates it.

If the user chooses wrong or has no matching certificate, the handshake fails — and the browser typically shows an unhelpful error page, not a login form. That is a large part of the UX problem.

The server configuration (briefly)

The server side is identical to any other mTLS — you require a client certificate validated against a CA. For browser access, though, you often set optional rather than on, so you can show a friendly error page in the application instead of a hard handshake rejection:

ssl_client_certificate /etc/ssl/portal/ca.crt;
ssl_verify_client      optional;

location /admin {
    if ($ssl_client_verify != SUCCESS) { return 403; }
    proxy_pass http://portal_backend;
}

The whole server-side setup is the same as in our mTLS guide.

The UX pitfalls

  • Installation is manual. Each user must import a .p12 with a password — hard to scale without device management (MDM).
  • The prompt confuses. Many users do not understand the certificate dialog and choose wrong or cancel.
  • Switching devices. The certificate lives on one machine; the user cannot log in from a new device without reinstalling it.
  • Renewal is invisible. When the certificate expires, access stops — often with no warning to the user.

When does it make sense?

Browser client certificates shine where security outweighs convenience and the user group is bounded and managed: internal admin portals, B2B extranets, government eID schemes, and machines under device management where the certificate can be deployed automatically. For large, open user bases, token- or passkey-based login is almost always a better route — compare with mTLS vs OAuth2.

When user access depends on a certificate

The subtle thing about browser mTLS is that user access now hinges on a certificate's expiry date. When a client certificate — or the CA that issued it — expires, users lose access all at once, and the error looks like any number of other things. CertControl monitors both server and client certificates as well as your internal CAs, tracks every expiry date and warns in good time, so a forgotten certificate does not lock your users out. Understand where it belongs in mTLS and Zero Trust.

Frequently asked questions

What is a .p12 file?

A PKCS#12 file that bundles a certificate together with its private key (and optionally the CA chain), protected by a password. It is the format browsers and operating systems import client certificates in.

Why does the browser show a dialog asking for a certificate?

Because the server has required a client certificate (sent a CertificateRequest), and the browser found one or more matching certificates in the store. The dialog lets the user choose which to send.

Can I use the same client certificate on multiple devices?

Technically yes, by importing the same .p12 on each device, but that spreads the private key and weakens security. Best practice is one certificate per device, often deployed via device management.

Are browser client certificates better than a login?

They are stronger against phishing and credential theft, but worse for UX and scaling. For a small, managed user group they can be better; for a large, open user base modern login (passkeys, OAuth) is usually more practical.

What happens when the client certificate expires?

The user loses access and the handshake fails — typically with no friendly explanation. So expiry on client certificates should be actively monitored, not discovered when a user is suddenly locked out.