Sanitizing secrets
editRecording files are usually committed, so anything secret in a request or a response ends up in the repository: authentication headers, cookies, API keys in the URL, tokens in the bodies. Sanitizers rewrite the recordings before they are saved:
var options = new HttpRecordingOptions
{
Sanitizers =
{
new HeaderRemovalSanitizer("Authorization", "Cookie"),
new UriQueryParameterSanitizer("api_key", "sig"),
},
};- HeaderRemovalSanitizer removes the named headers, compared case-insensitively, from the request and the response. It does not touch the URI or the bodies.
- UriQueryParameterSanitizer replaces the value of the named query string parameters with
***. - Credentials in the URI (
https://user:password@host/) are always removed, without a sanitizer.
The sanitizers run in the order of the Sanitizers list. There are none by default.
Rewrite a body
Implement IHttpRecordingSanitizer to change anything else. Sanitize receives the HttpRecordingEntry and changes it in place; RequestBody and ResponseBody are the bodies as bytes. This sanitizer replaces a known secret, such as a token read from the test configuration, in the response bodies:
// Replaces a known secret in the response bodies. It runs before the entries are saved.
public sealed class ResponseBodySanitizer(string secret) : IHttpRecordingSanitizer
{
public void Sanitize(HttpRecordingEntry entry)
{
if (entry.ResponseBody is { } body)
{
var text = Encoding.UTF8.GetString(body);
entry.ResponseBody = Encoding.UTF8.GetBytes(text.Replace(secret, "***", StringComparison.Ordinal));
}
}
}var options = new HttpRecordingOptions
{
Sanitizers = { new ResponseBodySanitizer("s3cr3t-t0ken") },
};A sanitizer changes the recording, not the response: while recording, the code under test receives the real response; when replaying, it receives the sanitized one. A test that replays must therefore not depend on a value a sanitizer removed.
Sanitizers must be deterministic
The sanitizers also run on each incoming request before its fingerprint is computed. A request whose api_key is masked in the recording is masked the same way when it is looked up, so it still matches. This only works when a sanitizer gives the same result for the same input: replace a value with a constant, never with a random or time-based one.