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
_AuthStateattached toRtlsClient. - 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._tokenexactly 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
httpxevent 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.
Recommended secret managers¶
Load credentials from a managed secret store rather than environment variables for production deployments.
- AWS Secrets Manager —
boto3.client("secretsmanager").get_secret_value(SecretId="…") - Azure Key Vault —
SecretClient(vault_url=…, credential=…).get_secret("…") - GCP Secret Manager —
SecretManagerServiceClient().access_secret_version(...) - Kubernetes Secrets —
mount as files or env vars; load with the usual
os.environpath.
Then construct the client with the loaded values: