diff --git a/docs/architecture.md b/docs/architecture.md index bae4238..d3e8b9a 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -102,6 +102,15 @@ Route modules use the `schemas` option so request validation, runtime response v OpenAPI generation stay aligned. Every route should declare an explicit response schema. Admin/user responses are intentionally minimized and should return only fields the route contract names. +## Logging and Redaction + +All log output passes through a central redaction step (`src/utils/redaction.ts`) before it is +written. Log messages are scrubbed for tokens, OTPs, magic-link URLs, bootstrap tokens, emails, +phone numbers, and known sensitive query parameters; structured metadata is redacted by key name. +This means route logs and auth events do not leak secrets even when a URL or payload contains them. +Treat redaction as a hard requirement: new sensitive fields should be added to the redaction +patterns. See [production-operations.md](./production-operations.md) for the operator-facing detail. + ## Operational Boundaries This repository contains the auth server only. It does not include billing, hosted tenant lifecycle, managed observability, managed secret storage, or the hosted control plane. Self-hosted deployments can integrate their own infrastructure for those responsibilities. diff --git a/src/utils/redaction.ts b/src/utils/redaction.ts index d37c52a..89dc98f 100644 --- a/src/utils/redaction.ts +++ b/src/utils/redaction.ts @@ -17,7 +17,10 @@ const TOKEN_TEXT_PATTERNS: Array<[RegExp, string]> = [ [/\+[1-9]\d{6,14}\b/g, REDACTED], [/\b(Bearer\s+)[A-Za-z0-9._~+/=-]+/gi, `$1${REDACTED}`], [/(\/magic-link\/verify\/)[^/?#\s]+/gi, `$1${REDACTED}`], - [/([?&](?:token|bootstrapToken|state|code|salt)=)[^&#\s]+/gi, `$1${REDACTED}`], + [ + /([?&](?:token|bootstrapToken|verificationToken|otp|state|code|salt)=)[^&#\s]+/gi, + `$1${REDACTED}`, + ], [ /\b((?:token|bootstrapToken|verificationToken|identifier|email(?:\s+address)?|phone(?:\s+number)?|state|code|secret|salt)\s*[:=]\s*)[^,&\s}]+/gi, `$1${REDACTED}`, diff --git a/tests/unit/utils/redaction.spec.ts b/tests/unit/utils/redaction.spec.ts index dc8deb3..d993a2a 100644 --- a/tests/unit/utils/redaction.spec.ts +++ b/tests/unit/utils/redaction.spec.ts @@ -57,4 +57,10 @@ describe('redaction utilities', () => { ), ).toBe('phone number: [REDACTED] email address: [REDACTED] identifier: [REDACTED]'); }); + + it('redacts otp and verificationToken query parameters in a URL', () => { + expect( + redactSensitiveText('Received GET request for /verify?otp=999888&verificationToken=abc123'), + ).toBe('Received GET request for /verify?otp=[REDACTED]&verificationToken=[REDACTED]'); + }); });