getHeaders method
Implementation
Future<Map<String, String>> getHeaders(
HttpOptions? options, {
bool isFile = false,
}) async {
// The caller's headers go down first, minus the ones the transport owns, and
// the SDK's own go on top. Spreading the caller's map over the SDK's let it
// replace `x-api-key`, the refresh-token `Cookie` or the transport marker,
// and the request then came back as an opaque 400. `Authorization` survived
// only because it happened to be assigned further down.
//
// Dropping the reserved names rather than relying on assignment order,
// because the order alone does not cover a header the SDK sets only
// sometimes: `x-auth-transport` is written on the auth endpoints, so on
// every other request a caller's value would have gone out unopposed.
final headers = <String, String>{};
// Copied out rather than filtered in place: an HttpOptions may be held and
// reused by the application, and stripping its map would be a side effect of
// sending one request that changed the next.
options?.headers?.forEach((name, value) {
if (!_isReservedHeader(name)) headers[name] = value;
});
headers['x-api-key'] = config.getApiKey();
if (options?.useAuthBodyTransport == true) {
headers[authTransportHeader] = 'body';
}
// One copy of the credential per request, not two. Setting both
// `refreshToken` and `useAuthBodyTransport` used to put the token in this
// Cookie *and* in the JSON body - and `_refreshTokens`, the only caller that
// passes a refresh token, sets both. Two copies is two chances for a proxy
// log, a WAF rule or a crash dump to capture it, for no gain: the
// `x-auth-transport: body` header above exists precisely to tell the API
// which one to read.
if (options?.refreshToken != null &&
options?.useAuthBodyTransport != true) {
headers['Cookie'] = '$refreshTokenCookieName=${options!.refreshToken}';
}
if (options?.refreshToken == null &&
options?.skipAuthHeader != true &&
_tokenProvider != null) {
final token = await _tokenProvider();
if (token != null) {
headers['Authorization'] = 'Bearer $token';
}
}
if (isFile != true) {
headers['Content-Type'] = 'application/json';
}
return headers;
}