Skip to content

Logging #113

@PhilipWoulfe

Description

@PhilipWoulfe

Ticket Addendum: Auth Failure Observability
Goal: keep client responses generic while preserving actionable diagnostics for operators.

Scope
Add structured server-side logging for Cloudflare auth failures in CloudflareAccessMiddleware.cs and CloudflareJwtValidator.cs.
Do not expose detailed failure reasons in HTTP response bodies.
Required Log Fields
eventName
reasonCode
path
method
requestId or traceId
environment
hasJwtHeader
kid (if present, truncated or hashed if needed)
statusCode
Reason Codes (minimum set)
missing_jwt_header
malformed_jwt
missing_kid
jwks_fetch_failed
token_invalid
token_expired
missing_email_claim
config_invalid
Security Requirements
Never log raw JWTs.
Never log secrets or connection strings.
If logging email, either avoid it or mask it according to team policy.
Keep HTTP 401 response body generic.
Acceptance Criteria
Every 401 from Cloudflare auth path writes exactly one structured warning log with one reasonCode.
Happy path does not emit warning logs.
Existing generic Unauthorized response behavior remains unchanged.
Logs include request correlation id to enable traceability.
Unit tests cover at least missing header, invalid token, and missing email claim reason mapping.
build.sh passes with tests and coverage report generated.
Test/Verification Notes
Add middleware/validator tests asserting logger was called with expected reasonCode.
Manual smoke check: trigger each major failure mode and confirm log payload shape.

Auth Failure Logging Plan

Objective

Keep client auth responses generic.
Preserve actionable internal diagnostics for support and incident response.
Reason Code Mapping

missing_jwt_header
Trigger: request has no Cf-Access-Jwt-Assertion header.
Source: middleware pre-validation check.
HTTP: 401.
simulate_cloudflare_used
Trigger: Development-only SimulateCloudflare path is used.
Source: middleware dev shortcut.
HTTP: 200/next middleware.
Log level: Information (not Warning).
legacy_bypass_used
Trigger: Development-only legacy email header bypass is used.
Source: middleware legacy fallback.
HTTP: 200/next middleware.
Log level: Warning (security-sensitive behavior even in dev).
validator_rejected_token
Trigger: validator returns IsValid=false or Principal=null.
Source: middleware after ValidateAsync.
HTTP: 401.
missing_email_claim
Trigger: validated principal lacks email/ClaimTypes.Email.
Source: middleware claim extraction branch.
HTTP: 401.
malformed_jwt
Trigger: JWT parse fails.
Source: validator ReadJwtToken catch.
HTTP: 401.
missing_kid
Trigger: token header kid is empty.
Source: validator kid check.
HTTP: 401.
config_invalid
Trigger: Audience/Issuer missing.
Source: validator options check.
HTTP: 401.
jwks_fetch_failed
Trigger: JWKS download/parse exception.
Source: validator GetJwksAsync call path.
HTTP: 401.
signing_key_not_found
Trigger: no matching signing key after refresh logic.
Source: validator key lookup.
HTTP: 401.
token_expired
Trigger: SecurityTokenExpiredException.
Source: validator validate catch.
HTTP: 401.
token_invalid
Trigger: SecurityTokenException.
Source: validator validate catch.
HTTP: 401.
token_validation_unexpected_error
Trigger: non-token exception during validation.
Source: validator generic catch.
HTTP: 401.
Required Log Fields

eventName
reasonCode
path
method
statusCode
requestId
traceId
environment
hasJwtHeader
kidPresent
remoteIp (if policy allows)
Security Constraints

Never log raw JWT.
Never log secrets or connection strings.
Avoid full email logging unless masked.
Keep client body as generic Unauthorized.
Acceptance Criteria

Each auth failure emits exactly one structured Warning with one reasonCode.
Success path emits no Warning logs.
Correlation fields are present for all auth logs.
Unit tests verify reasonCode emission for:
missing_jwt_header
validator_rejected_token
missing_email_claim
config_invalid or jwks_fetch_failed
build.sh passes and coverage artifact is produced.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions