Outbound Integrations
Aggregator-backed providers reach out to a third-party API (Enode, OEM cloud, Tibber, …) using OAuth2 client-credentials. The SDK ships a typed-HttpClient + token-cache helper so every adapter doesn't rebuild this from scratch.
Quick start
// Program.cs
builder.Services.AddOutboundOAuth2Client<EnodeApiClient>(
builder.Configuration, "enode")
.ConfigureHttpClient((sp, http) =>
{
var opts = sp.GetRequiredService<IOptions<EnodeOptions>>().Value;
http.BaseAddress = new Uri(opts.ApiBaseUrl);
});
EnodeApiClient is an ordinary typed client whose constructor takes
HttpClient:
public sealed class EnodeApiClient
{
private readonly HttpClient _http;
public EnodeApiClient(HttpClient http) { _http = http; }
public async Task<JsonNode?> ListChargersAsync(CancellationToken ct = default)
{
using var resp = await _http.GetAsync("/chargers", ct);
resp.EnsureSuccessStatusCode();
return await JsonNode.ParseAsync(
await resp.Content.ReadAsStreamAsync(ct), cancellationToken: ct);
}
// ... etc.
}
The handler attached by AddOutboundOAuth2Client:
- Adds
Authorization: Bearer <token>to every outgoing request, - Caches the access token in process,
- Refreshes within
RefreshSkewSecondsof expiry, - On a
401response, forces a refresh and replays the request once (the body is cloned so POST/PUT/PATCH retry cleanly).
Configuration
{
"Outbound": {
"enode": {
"TokenUrl": "https://oauth.sandbox.enode.io/oauth2/token",
"ClientId": "<from secret store>",
"ClientSecret": "<from secret store>",
"Scope": null,
"Audience": null,
"RefreshSkewSeconds": 60
}
}
}
Use dotnet user-secrets for development; in production source
secrets from your secret store. The name (enode here) is both the
options-binding key and the per-call cache slot — multiple integrations
under the same host coexist by name.
What you get for free
- One
IOutboundTokenProvidersingleton, one cache slot per name. SemaphoreSlimper name so concurrent first-time fetches don't duplicate the token call.- Refresh-on-401 with body cloning.
- Standard ASP.NET resilience (timeouts, retry policies) layered via
the
IHttpClientBuilderreturned fromAddOutboundOAuth2Client.
What you don't get
- Refresh-token / authorization-code flows — only client-credentials. File a separate request if a probe needs interactive auth.
- mTLS-authenticated outbound calls — separate concern; layer your own handler.
See also
- Webhooks Inbound — third party → us
- Aggregator Providers — the full pattern