๐Ÿ” Authentication Providers

Multiple authentication strategies for secure HTTP requests with built-in provider support

๐Ÿ”‘
API Key

Header or query parameter based authentication

๐ŸŽซ
Bearer Token

OAuth 2.0 and JWT token support

๐Ÿ‘ค
Basic Auth

Username/password authentication

๐Ÿ”ง
Custom

Implement your own authentication provider

๐Ÿ“ Implementation Examples
1. API Key Authentication
using WebSpark.HttpClientUtility.Authentication;
using WebSpark.HttpClientUtility.RequestResult;

// Create API key provider
var apiKeyProvider = new ApiKeyAuthenticationProvider("your-api-key-here");

// Option 1: Set globally in DI (recommended)
builder.Services.AddSingleton<IAuthenticationProvider>(apiKeyProvider);

// Option 2: Use per-request
var request = new HttpRequestResult<MyData>
{
    RequestPath = "https://api.example.com/data",
    RequestMethod = HttpMethod.Get,
    AuthenticationProvider = apiKeyProvider  // Per-request auth
};

var result = await _requestService.HttpSendRequestResultAsync(request);

// The provider automatically adds the header:
// X-API-Key: your-api-key-here
2. Bearer Token Authentication
// For OAuth 2.0 / JWT tokens
var bearerProvider = new BearerTokenAuthenticationProvider("eyJhbGciOiJIUzI1NiIs...");

var request = new HttpRequestResult<MyData>
{
    RequestPath = "https://api.example.com/protected",
    RequestMethod = HttpMethod.Get,
    AuthenticationProvider = bearerProvider
};

// Automatically adds:
// Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

// Refresh token support
var tokenProvider = new RefreshableBearerTokenProvider(
    getAccessToken: async () => await GetAccessTokenAsync(),
    refreshToken: async () => await RefreshAccessTokenAsync(),
    tokenLifetime: TimeSpan.FromHours(1)
);
3. Basic Authentication
// Username and password
var basicAuthProvider = new BasicAuthenticationProvider("username", "password");

var request = new HttpRequestResult<MyData>
{
    RequestPath = "https://api.example.com/secure",
    RequestMethod = HttpMethod.Get,
    AuthenticationProvider = basicAuthProvider
};

// Automatically adds:
// Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
4. Custom Authentication Provider
// Implement IAuthenticationProvider interface
public class CustomAuthProvider : IAuthenticationProvider
{
    private readonly string _customToken;
    
    public CustomAuthProvider(string customToken)
    {
        _customToken = customToken;
    }
    
    public Task<Dictionary<string, string>> GetAuthenticationHeadersAsync(
        CancellationToken cancellationToken = default)
    {
     var headers = new Dictionary<string, string>
 {
   { "X-Custom-Auth", _customToken },
            { "X-Request-Time", DateTime.UtcNow.ToString("O") },
 { "X-Client-Id", "my-app-v1.0" }
        };
        
    return Task.FromResult(headers);
    }
}

// Use it
var customProvider = new CustomAuthProvider("custom-token-123");
var request = new HttpRequestResult<MyData>
{
    RequestPath = "https://api.example.com/data",
    RequestMethod = HttpMethod.Get,
    AuthenticationProvider = customProvider
};
โš™๏ธ Configuration Patterns
Global Configuration (Recommended for Single Auth)
// In Program.cs
// Read from configuration
var apiKey = builder.Configuration["ApiSettings:ApiKey"];
var apiKeyProvider = new ApiKeyAuthenticationProvider(apiKey);

// Register as singleton
builder.Services.AddSingleton<IAuthenticationProvider>(apiKeyProvider);

// All requests automatically use this auth
builder.Services.AddScoped<IHttpRequestResultService>(provider =>
{
    var service = provider.GetRequiredService<HttpRequestResultService>();
    return new HttpRequestResultServiceTelemetry(
        provider.GetRequiredService<ILogger<HttpRequestResultServiceTelemetry>>(),
   service
    );
});
Per-Service Configuration (Multiple APIs)
// Different auth for different services
public class PaymentService
{
    private readonly IHttpRequestResultService _requestService;
    private readonly IAuthenticationProvider _paymentAuth;
    
    public PaymentService(IHttpRequestResultService requestService)
    {
        _requestService = requestService;
        // Specific auth for payment API
   _paymentAuth = new ApiKeyAuthenticationProvider("payment-api-key");
    }
    
    public async Task<Payment> ProcessPaymentAsync(decimal amount)
    {
        var request = new HttpRequestResult<Payment>
        {
 RequestPath = "https://payment-api.com/process",
   AuthenticationProvider = _paymentAuth  // Override default
        };
    
        var result = await _requestService.HttpSendRequestResultAsync(request);
  return result.ResponseResults;
    }
}

public class UserService
{
    private readonly IHttpRequestResultService _requestService;
    private readonly IAuthenticationProvider _userAuth;
    
    public UserService(IHttpRequestResultService requestService)
    {
        _requestService = requestService;
        // Different auth for user API
        _userAuth = new BearerTokenAuthenticationProvider("user-api-token");
    }
    
    public async Task<User> GetUserAsync(int userId)
    {
        var request = new HttpRequestResult<User>
 {
            RequestPath = $"https://user-api.com/users/{userId}",
       AuthenticationProvider = _userAuth  // Different auth
        };
      
        var result = await _requestService.HttpSendRequestResultAsync(request);
        return result.ResponseResults;
    }
}
Dynamic Token Management
// Token refresh and caching
public class TokenManager
{
    private string _cachedToken;
  private DateTime _tokenExpiry;
    private readonly SemaphoreSlim _lock = new(1);
    
    public async Task<string> GetValidTokenAsync()
    {
     await _lock.WaitAsync();
   try
        {
  if (string.IsNullOrEmpty(_cachedToken) || DateTime.UtcNow >= _tokenExpiry)
  {
             // Fetch new token
             _cachedToken = await FetchNewTokenAsync();
       _tokenExpiry = DateTime.UtcNow.AddHours(1);
        }
 
     return _cachedToken;
        }
        finally
     {
   _lock.Release();
        }
 }
    
  private async Task<string> FetchNewTokenAsync()
    {
      // Your token acquisition logic
 var tokenRequest = new HttpRequestResult<TokenResponse>
  {
            RequestPath = "https://auth.example.com/token",
     RequestMethod = HttpMethod.Post,
  // ... token request details
        };
        
        var result = await _requestService.HttpSendRequestResultAsync(tokenRequest);
        return result.ResponseResults.AccessToken;
    }
}
Security Best Practices
โœ… Do
  • Store credentials in Azure Key Vault or similar
  • Use environment variables for dev/test
  • Implement token rotation
  • Use HTTPS for all authenticated requests
  • Set appropriate token expiration times
  • Log authentication failures (without credentials)
โŒ Don't
  • Hard-code credentials in source code
  • Commit credentials to version control
  • Log sensitive authentication data
  • Share API keys across environments
  • Use the same credentials for dev and prod
  • Ignore token expiration
๐Ÿ“Š Authentication Method Comparison
Method Security Complexity Best For
API Key โญโญโญ Simple Internal APIs, basic auth
Bearer Token โญโญโญโญโญ Moderate OAuth 2.0, JWT, modern APIs
Basic Auth โญโญ Very Simple Legacy systems, internal tools
Custom Varies Complex Proprietary auth schemes
Key Benefits
  • Standardized: Consistent authentication across all HTTP requests
  • Flexible: Per-request or global authentication configuration
  • Extensible: Implement custom providers for any auth scheme
  • Secure: Automatic header injection prevents credential exposure
  • Testable: Mock authentication providers for unit testing
  • Maintainable: Centralized authentication logic