4

I am working with Flurl to hit an API that requires certificate-based authentication. I have seen from this SO post that adding a certificate to a WebRequestHandler and instructing an HttpClient to use this handler is easy.

However, it is not so clear for me using Flurl. I have tried the follwing three things.

Extending DefaultHttpFactory

I first suspected that I needed to create my own X509HttpFactory : DefaultHttpFactory which would create the handler and assign it to the HttpClient. However, in viewing the source, I notice that the constructor for CreateClient already expects a handler. Where does this handler come from?

Creating Client using DefaultHttpFactory

WebRequestHandler handler = new WebRequestHandler();
handler.ClientCertificates.Add(myX509Cert);
var clientFactory = new DefaultHttpClientFactory();
FlurlClient fc = clientFactory.CreateClient(url, handler);

This does not compile as HttpClient cannot be casted to FlurlClient

Use ConfigureHttpClient

var clientFactory = new DefaultHttpClientFactory();
FlurlClient fc = new Url("foobar.com").ConfigureHttpClient(client => client = clientFactory
  .CreateClient(url, handler));

This seems like the most viable option, but I'm unsure since the delegate is an Action with no return type.

The Question

What is the best/correct way to support client-side certificate authentication using Flurl?

Community
  • 1
  • 1
Brian
  • 7,098
  • 15
  • 56
  • 73

1 Answers1

10

You're close - a custom factory is definitely the way to go. But you want to override CreateMessageHandler rather than CreateClient:

public class X509HttpFactory : DefaultHttpClientFactory
{
    private readonly X509Certificate2 _cert;

    public X509HttpFactory(X509Certificate2 cert) {
        _cert = cert;
    }

    public override HttpMessageHandler CreateMessageHandler() {
        var handler = base.CreateMessageHandler();
        handler.ClientCertificates.Add(_cert);
        return handler;
    }
}

Then you can either register it globally (on app startup):

FlurlHttp.Configure(settings => {
    settings.HttpClientFactory = new X509HttpFactory(myCert);
});

Or for all calls to a particular host:

FlurlHttp.ConfigureClient(ROOT_URL, cli => {
    cli.Settings.HttpClientFactory = new X509HttpFactory(myCert);
});

Or for a new FlurlClient:

var cli = new FlurlClient(url)
    .Configure(settings => settings.HttpClientFactory = new X509HttpFactory(myCert));

Or an existing one:

cli.Settings.HttpClientFactory = new X509HttpFactory(myCert);
Todd Menier
  • 37,557
  • 17
  • 150
  • 173
  • 1
    Thanks. Awesome library! – Brian Dec 08 '16 at 18:07
  • If I have more than one URL, what is the configuration? For example, I apply it to web crawlers I visit http://exampledomain.com After logging in to the system, it redirects to another address like https://otherdomain.com (1) or https://anotherdomain.net (2) And I do on both of these domains, how to configure baseAddress Domain (1) and (2) are unknown, depending on their server navigation – mincasoft May 03 '20 at 09:07
  • @mincasoft I think the first way I showed how to register it (globally) is the way to go. – Todd Menier May 03 '20 at 14:19
  • I am not getting reference to add webRequestHandler, what should be done? – swathi Dec 11 '20 at 10:15
  • 1
    Looks like WebRequestHandler is available in .net Framework, any solution for .net core (.net 5) – Tomasz Rzepecki Apr 28 '21 at 13:08
  • handler doesnt show up ClientCertificates property. I'm using Flurl 4 in Xamarin. Is it removed? What is the way of certificate validation in Flurl pls help @ToddMenier – hashPJ May 02 '23 at 07:10