Skip to content

Interception of HTTP requests in ksqlDB.RestApi.Client DotNet Authentication

Tomas Fabian edited this page Jun 18, 2023 · 7 revisions

By intercepting HTTP requests, you gain the ability to inspect the data being sent between the client and the server. This can be useful for debugging, logging, or security checks.

ksqlDB.RestApi.Client v >= 2.0.0

Starting from version 2.0.0, you have the capability to register custom message handlers in the following way:

internal class DebugHandler : System.Net.Http.DelegatingHandler
{
  protected override Task<System.Net.Http.HttpResponseMessage> SendAsync(
    System.Net.Http.HttpRequestMessage request, CancellationToken cancellationToken)
  {
    System.Diagnostics.Debug.WriteLine($"Process request: {request.RequestUri}");

    return base.SendAsync(request, cancellationToken);
  }
}

public static void Configure(this IServiceCollection services, string ksqlDbUrl)
{
  services.AddDbContext<IKSqlDBContext, KSqlDBContext>(c =>
  {
    c.UseKSqlDb(ksqlDbUrl);

    c.ReplaceHttpClient<IHttpClientFactory, ksqlDB.RestApi.Client.KSql.RestApi.Http.HttpClientFactory>(_ => { })
      .AddHttpMessageHandler(_ => new DebugHandler());
  });
}

The System.Net.Http.DelegatingHandler class is a fundamental component of the System.Net.Http namespace in .NET. It serves as a base class for creating custom message handlers that can intercept and modify HTTP requests and responses in the .NET HttpClient pipeline.

ksqlDB.RestApi.Client v < 2.0.0

You can use the built in SetBasicAuthCredentials method for Basic http authentication (v2.0.0):

string userName = "fred";
string password = "letmein";

var options = new KSqlDbContextOptionsBuilder().UseKSqlDb(@"http:\\localhost:8088")
  .SetBasicAuthCredentials(userName, password)
  .Options;

await using var context = new KSqlDBContext(options);

To enable alternative methods for HTTP authentication, you can override the DelegatingHandler.SendAsync method as shown below and provide through the constructor of the HTTP client:

internal class BearerAuthHandler : DelegatingHandler
{
  public BearerAuthHandler()
  {
    InnerHandler = new HttpClientHandler();
  }
	
  protected override Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
  {
    var token = "xoidiag"; //CreateToken();

    request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);

    return base.SendAsync(request, cancellationToken);
  }
}

internal class HttpClientFactoryWithBearerAuth : IHttpClientFactory
{
  private readonly Uri uri;

  public HttpClientFactoryWithBearerAuth(Uri uri)
  {
    this.uri = uri ?? throw new ArgumentNullException(nameof(uri));
  }

  public HttpClient CreateClient()
  {
    return new HttpClient(new BearerAuthHandler())
    {
      BaseAddress = uri
    };
  }
}

IHttpClientFactory is a factory interface that simplifies the management and configuration of HttpClient instances within an application.

Override the registration of IHttpClientFactory:

public class KSqlDBContextWithAuth : KSqlDBContext
{
  private readonly KSqlDBContextOptions contextOptions;

  public KSqlDBContextWithAuth(KSqlDBContextOptions contextOptions) 
    : base(contextOptions)
  {
    this.contextOptions = contextOptions ?? throw new ArgumentNullException(nameof(contextOptions));
  }

  protected override void OnConfigureServices(IServiceCollection serviceCollection, KSqlDBContextOptions contextOptions)
  {
    serviceCollection.AddSingleton<IHttpClientFactory, HttpClientFactoryWithBearerAuth>(sp => new HttpClientFactoryWithBearerAuth(new Uri(contextOptions.Url)));

    base.OnConfigureServices(serviceCollection, contextOptions);
  }
}