withHeaders method

ServiceContext withHeaders(
  1. Map<String, String> headers
)

Returns a context that shares this one's session state but sends headers in place of this context's own.

The current session, the single in-flight refresh, and onSessionUpdated are one thing shared by both contexts: a refresh started through either is seen by both, and the refresh token — which is single-use — is spent exactly once. Everything else is carried over unchanged: protocol, service, relay service, timeout, retry strategy, HTTP clients, and the OAuth session manager when there is one.

This exists because request headers belong to the client that sends them, while the session belongs to the account. A client that must send a header the others must not — an atproto-proxy routing its calls to a different service, say — would otherwise need a context of its own, and a second context used to mean a second copy of the session. Two copies race the moment the access token expires: whichever refreshes first spends the token, and the other's refresh is rejected by the server as an UnauthorizedException the caller did nothing to provoke.

final bare = ctx.withHeaders(const {
  'atproto-proxy': 'did:web:example.com#service',
});

headers replaces this context's headers rather than extending them, so bare above sends the proxy header and nothing else. To keep the origin's headers, use withAdditionalHeaders rather than spreading headers of the origin context by hand: a spread is key-exact, and header names are not, so an origin sending Atproto-Proxy would keep it alongside the added atproto-proxy and the request would carry the header twice.

Implementation

ServiceContext withHeaders(final Map<String, String> headers) =>
    ServiceContext._shared(
      _state,
      headers: headers,
      protocol: _protocol,
      explicitService: _explicitService,
      relayService: relayService,
      oAuthSessionManager: oAuthSessionManager,
      //! Stateless and immutable, so sharing the instance is equivalent to
      //! rebuilding one from the same retry strategy.
      challenge: _challenge,
      timeout: _timeout,
      getClient: _getClient,
      postClient: _postClient,
    );