Adding specific certificate to HttpClient in .NET 6
For the last few days, I was dealing with an issue that wouldn't let me rest. My job requires me to use smartcard to authorize access to some of the internal services. That's not a problem when I use a browser like Chrome or Firefox, but becomes an issue when I want to use these services through their API to automate something really boring.
Of course, the smartcard itself only serves the purpose of authorizing usage of the certificate that's already installed off of it in my personal certificate store on Windows, but I still have to somehow add it to my request.
Required steps, then:
- Access the certificate store
- Find my certificate
- Add it to the HttpClient
- Successfully perform a request
Seems simple enough, so let's get to it. First, I have to access my personal certificate store:
var store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
These two lines first create an object to access a personal store of a current user, and then open it in ReadOnly mode. We don't need the right to change anything, so ReadOnly will suffice.
Now, let's find our certificate. In my example, the easiest way is to use the IssuerName, because there is only one with this specific name. In yours, you might want to find another property that suits you better:
var certificate = store.Certificates.First(cert => cert.IssuerName.Name == "ISSUER_NAME");
This line finds the first certificate with IssuerName that fits our requirements. Now that we have it, let's add it to the client.
In order to do that, we first have to create an HttpClientHandler(), which will then be used to create an HttpClient() object.
var clientHandler = new HttpClientHandler();
clientHandler.ClientCertificates.Add(certificate);
var client = new HttpClient(clientHandler);
As you can see, between creating a Handler and using it to create a Client, we added the certificate to it. Now we don't have to worry about it anymore, because the Client will use it by default.
The rest of the work is to perform a request in a standard manner:
client.BaseAddress = new Uri("https://service.service");
var result = await client.GetAsync("/endpoint");
This request will use our added certificate to authorize itself with a service, and everything should work just fine. Problem is solved, and now I can automate my really boring tasks - and so can you ;)