Skip to content
Document DB v7: Temporal Support and Telemetry Collections! Feed The Machine Here

Sync Interceptors

An ISyncInterceptor is a cross-cutting hook invoked on every sync HTTP request the engine emits — inbox pulls, outbox pushes (single or batched), and tombstone fetches. Register one or more in DI to attach auth headers, trace ids, or signing once instead of repeating the logic in every endpoint’s OnBeforeSend.

public interface ISyncInterceptor
{
Task BeforePull(SyncEndpoint endpoint, string? cursor, HttpRequestMessage request);
Task BeforePush(SyncEndpoint endpoint, IReadOnlyList<SyncOperation> operations, HttpRequestMessage request);
Task BeforeTombstoneFetch(SyncEndpoint endpoint, string? cursor, HttpRequestMessage request)
=> this.BeforePull(endpoint, cursor, request); // default forwards to BeforePull
}

BeforePush’s operations is the full coalesced batch when the endpoint has Batch = true; for single-send endpoints it is a one-element list.

public class AuthInterceptor(ITokenService tokens) : ISyncInterceptor
{
public async Task BeforePull(SyncEndpoint endpoint, string? cursor, HttpRequestMessage req)
{
var token = await tokens.GetAccessTokenAsync();
req.Headers.Authorization = new("Bearer", token);
}
public async Task BeforePush(SyncEndpoint endpoint, IReadOnlyList<SyncOperation> ops, HttpRequestMessage req)
{
var token = await tokens.GetAccessTokenAsync();
req.Headers.Authorization = new("Bearer", token);
}
// BeforeTombstoneFetch's default forwards to BeforePull — override only if your tombstone URL is on a different auth domain.
}
builder.Services.AddSyncInterceptor<AuthInterceptor>();

Multiple interceptors can be registered — they execute in registration order. All registered interceptors run before the per-endpoint SyncEndpoint.OnBeforeSend, so endpoint hooks still win on header conflicts.

The two hooks compose:

Use the interceptor forUse OnBeforeSend for
Auth headers (Bearer / API keys)Endpoint-specific trace ids
Request signing (HMAC, etc.)Tenant headers that vary by entity
Tracing / correlation idsPer-endpoint feature flags
Anything you’d otherwise repeat in every endpointOne-off behaviour

On iOS / Mac Catalyst the outbox uses NSURLSession background upload tasks, which require file-backed uploads. The HttpRequestMessage your interceptor sees has the headers populated but no body attached — the engine writes the payload to a temp file separately. This is fine for header-based auth (Bearer, API key, etc.) but breaks signers that hash the request body (e.g. AWS SigV4).

If you need body-hashing auth on Apple, either:

  • have the server validate the body via a downstream service (the upload still succeeds), or
  • pin the Apple platforms to the HttpClient path with AddHttpClientDataSync<TDelegate> (you lose the survives-app-kill guarantee for the outbox).