๐ 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