Skip to content

Security

The SDK's security posture in one page. The redaction guarantees are verified by an audit test (tests/security/test_secret_leaks.py) that runs on every CI build.

What is redacted

The SDK redacts the following from every log record at every level (DEBUG, INFO, WARNING, ERROR) and from every exception's .response_body and string representation:

Header keys (case-insensitive): - X-User-Token - X-User-Email - X-User-Refresh-Token - Authorization - Cookie - Set-Cookie

Body keys (recursively, case-insensitive): - password - token - refresh_token - access_token - client_secret - api_key

There is no opt-out flag. The filter applies before the record is emitted to a handler.

Where tokens live

  • In memory only, on the _AuthState attached to RtlsClient.
  • Never written to disk by the SDK.
  • Cleared by client.close().
  • Never exposed via a public attribute or method.

If you print() something the SDK returned, double-check the model: the SDK's models never include the user's token, but a custom _request call could surface a raw response. In particular, client.auth.whoami() does not return the token — only the profile.

401 re-login — why it doesn't leak

The lazy-login and 401-replay flows live entirely inside the SDK. The caller sees:

  • One successful method return (the call succeeded silently on retry).
  • Or a single AuthenticationError (the re-login itself failed).

No request body, no token value, no header value is ever logged in plain text. The replay request goes through the same redacted log hook as the first attempt.

BYO-token caveats

In BYO-token mode (RtlsClient(token=...)):

  • The SDK cannot re-login on token expiry — see BYO token.
  • Token-rotation cadence is your responsibility.
  • The token is stored on _AuthState._token exactly like the login-acquired one and benefits from the same redaction.

What the SDK does NOT defend against

These are out of scope:

  • The user print()-ing a token retrieved via a non-SDK path.
  • The user enabling a custom log handler without redaction (e.g. a bare httpx event hook on a separate client).
  • The user storing the password in a plain-text file. The SDK only redacts what passes through its layer.
  • Disk-level data exfiltration. The SDK doesn't persist anything; what your application persists is yours.
  • Network-level interception. Use HTTPS. Pin the CA via a custom httpx.Client(verify=...) if your threat model requires it.

Load credentials from a managed secret store rather than environment variables for production deployments.

Then construct the client with the loaded values:

client = RtlsClient(
    username=secret["email"],
    password=secret["password"],
    base_url=secret["base_url"],
)