Client certificate (mutual TLS, or mTLS) authentication is only rarely used for user-facing applications, because it complicates the authentication flow by taking credentials at two different layers: the application layer (passwords or similar conventional credentials) or the network layer (client certs are presented when the TLS handshake occurs, before the user sees any UI at all). Additionally, unless you are yourself a certificate authority (or at least operate one internally), there's the question of how you identify trusted client certificates. On the other hand, it's more secure than most credentials, and can be more convenient too.
All web server software worth running any production code on supports client certificates. It is then up to the application developer to retrieve the presented certificate from the user's connection (every server does this a different way), validate the certificate to ensure it's one that you trust (the server typically only verifies that the client holds the private key before completing the handshake, though some will also let you configure a CA cert the client certs need to have been issued from and validate those), locate the corresponding user identity, and set that identity as the authenticated user at the application layer (as if the user had logged in with a conventional credential). This isn't hard, exactly, but it's error-prone, and that's not something you want in authentication code.
For users who don't present a certificate, you want to fall back to standard authentication, of course. Alternatively, you can initially present a landing page that doesn't expect a client cert, and offer the user a choice to authenticate with a cert instead. Which approach is easiest will depend on your server software; some can only be configured for mTLS or not at a site-wide granularity but gracefully handle "the client was requested to supply a cert but didn't"; others treat the lack of an expected client cert as an error so you want to present the user with an option to use mTLS rather than expect it by default.
Note also that logging out from an mTLS session can be difficult to implement. The usual expectation is that if the client can present a client cert once, it can do it arbitrarily many times, so there isn't any reason to enable "log out" as an option other than by the client closing the connection. However, in some cases you might want to support the option of the client reverting to an unauthenticated state and offering the ability to log in (by any method) again. Sometimes the only way to do that is return an Unauthorized error to the client to tell it that the cert is not accepted (anymore).
These days, there are alternative ways to do public key authentication! Consider using FIDO2 authentication, specifically the "webauthn" protocol that all modern browsers implement. "Passkeys" are a general term for webauthn, generally with additional on-client authentication (e.g. requiring the user to authenticate locally to unlock the private key). I somewhat don't like the term "passkey" because it gets used in different ways and one of the more common meanings is "webauthn as sole factor, not even any option to use a second factor", but it's perhaps what your users are most likely to recognize. Some advantages of webauthn over mTLS:
- Webauthn is explicitly built around the assumption that the user creates a unique public/private key pair for each site. This improves privacy (the server can't tell where else you have accounts) and greatly limits the harm if some public key were to be cracked.
- Webauthn key generation and enrollment happens automatically within the client, avoiding the relatively involved process (generate key pair, generate CSR, submit CSR to CA, install returned cert from CA) generally involved in obtaining certificates from a CA.
- Because the user's key (for that site), or a thumbprint of it, is stored on the server, validation is trivial compared to a certificate. No need to check whether the certificate is signed by the right CA, or the chain of trust is valid, or the cert has the right metadata, or the cert's subject exists in the user table; you simply check whether the presented public key is known, and that's all you need. (One can of course do this with certs as well, simply pinning the public key for each user, but it's best to do that when you know the key pair was newly generated).
- While servers can never prove that clients are taking the expected security measures, the conventions around how to store and access FIDO2 private keys are stronger than for TLS client certificates. Typically, FIDO2 private keys are stored in hardware (either a trusted platform module [TPM]/secure enclave/other hardware security module [HSM] within the client device, or a removable hardware security module like a Yubikey or smart card, and non-exportable), while TLS certificates (and private keys) are often stored just as, or in, files on a file system that can be read and copied by anybody with access to the file. Sometimes a TLS private key isn't even encrypted (and even when it is, the encryption usually is a pretty weak password-based encryption).
- You avoid the complexity of accepting credentials at two different times and layers (handshake on the network vs. login form in the application); it's just another credential, like a password or access code or whatever, that is presented at login time. As with mTLS, though, you don't have to create UI for the actual authentication process; the browser handles that (asking the user which authenticator to use if they have multiple e.g. a Yubikey and a biometic-based one, authenticating the user if relevant, and actually carrying out the cryptographic operations and so on).