Mutual TLS (aka Client Authentication) is a solution to this.
As for issuing certs I wouldn't do that. I would take self-signed certs from the client and pin them directly to principals (users) in some manner. I would have a lookup table indexed by both common name and certificate public key to do that. This makes potential problems like cert revocation (delete the row) and CA compromise (none involved) much easier.
Alternatively you could request CSRs from clients and sign them using a CA you trust (either a third party or your own in-house CA if your org has the expertise and resources to protect it properly).
Here is a good high-level description from The Code Project and they have .NET sample code demonstrating it:
Mutual SSL authentication or certificate based mutual authentication
refers to two parties authenticating each other through verifying the
provided digital certificate so that both parties are assured of the
others' identity. In technology terms, it refers to a client (web
browser or client application) authenticating themselves to a server
(website or server application) and that server also authenticating
itself to the client through verifying the public key
certificate/digital certificate issued by the trusted Certificate
Authorities (CAs). Because authentication relies on digital
certificates, certification authorities such as Verisign or Microsoft
Certificate Server are an important part of the mutual authentication
process. From a high-level point of view, the process of
authenticating and establishing an encrypted channel using
certificate-based mutual authentication involves the following steps:
- A client requests access to a protected resource.
- The server presents its certificate to the client.
- The client verifies the server’s certificate.
- If successful, the client sends its certificate to the server.
- The server verifies the client’s credentials.
- If successful, the server grants access to the protected resource requested by the client.