5

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?

2 Answers 2

11

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);
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks. Awesome library!
If I have more than one URL, what is the configuration? For example, I apply it to web crawlers I visit exampledomain.com After logging in to the system, it redirects to another address like otherdomain.com (1) or 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 I think the first way I showed how to register it (globally) is the way to go.
I am not getting reference to add webRequestHandler, what should be done?
Looks like WebRequestHandler is available in .net Framework, any solution for .net core (.net 5)
|
0

For Flurl v4 you can do this by ConfigureInnerHandler:

FlurlHttp
    .ConfigureClientForUrl("myUrl")
    .ConfigureInnerHandler(handler =>
    {
        handler.ClientCertificateOptions = ClientCertificateOption.Manual;
        handler.ClientCertificates.Add(myCert);
    });

or for all clients:

FlurlHttp.Clients.WithDefaults(settings =>
    settings.ConfigureInnerHandler(handler =>
    {
        handler.ClientCertificateOptions = ClientCertificateOption.Manual;
        handler.ClientCertificates.Add(myCert);
    }));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.