Skip to main content
ZombieMutex

30 results · ↑ ↓ navigate · Enter open · Esc close

All writing
November 6, 20263 min read

Authentication telemetry without leaking tokens or recovery secrets

Design privacy-conscious auth decision logs that help explain failures without recording the credentials that caused them.

By

Share

Send this article to someone or copy its link.

Suggest a correction

Reader tools

3 min remaining · 0% of article

Select a passage and choose Highlight selection to save it. Local browser storage only. Shift+F toggles focus.

I built authentication telemetry around a simple constraint: an engineer must be able to distinguish token expiry, replay, recovery rejection and dependency failure without logging the credential or sensitive request that triggered the decision. "Authentication failed" is not enough context to debug a production incident.

The opposite extreme is worse: a verbose debug log that captures raw bearer tokens, passwords, one-time codes, or private account payloads. Good observability starts with a restricted event schema and a clear data-handling policy.

Start with decisions, not request dumps

For a security-sensitive endpoint, an event can record the decision and its context without recording the proof itself. Useful fields depend on the threat model, but a small allowlisted schema is easier to audit than arbitrary JSON properties.

json
{
  "event": "auth.decision",
  "operation": "refresh",
  "outcome": "denied",
  "reason": "token_reused",
  "policyVersion": "2026-11",
  "correlationId": "req_7f6e1",
  "environment": "production"
}

All values here are synthetic. There is no token, code, email address, phone number, recovery challenge or unredacted payload. In a real deployment, identifiers and operational metadata can still be sensitive and need access controls, retention limits, and privacy review.

Name errors the operator can act on

Avoid collapsing distinct failures into “network error.” An operator needs to know whether a request was rejected by policy, was invalid, exhausted retry limits, or could not reach an upstream dependency.

DecisionSuggested category
Expired access credentialAuthentication state
Refresh token reusedReplay / token-lifecycle policy
Insufficient object permissionAuthorization decision
App attestation verification unavailableDependency / integrity evidence
Recovery step-up deniedRecovery policy
Backend timed out after an ambiguous writeReliability / reconciliation

The category should describe a stable failure class, not reveal secrets to the end user.

Avoid building a log-based oracle

Detailed internal failure reasons help debugging but can also disclose account state if returned to an untrusted client. Keep the public response appropriately generic where enumeration or side-channel risks apply, and retain detailed diagnostic reasons in protected telemetry.

Aggregate rates by operation, rollout, policy, and failure category before drilling into individual trace IDs. Rate limits and retention policy should protect both the primary system and the observability pipeline.

Test redaction as a security property

Unit tests should generate synthetic token-like values, recovery codes, and PII and assert that serialized events never contain them. Validate logs for success and failure paths, exception handlers, retries, and traces from third-party SDKs.

Further reading: OWASP Logging Cheat Sheet and the API authorization review.


I prepared this guide with AI assistance. The example logs are synthetic, not taken from customer systems.

Related technical notes with overlapping topics.

Discuss a passage

Select a paragraph above, copy it with its article link, then paste into the discussion. Don't include private data.

Jump to discussion ↓

Public conversation / GitHub Discussions

Discuss this article

Read and reply using GitHub Discussions. A GitHub account is needed to post. Comments are public and subject to GitHub moderation.

For privacy, the external giscus widget does not load until you choose to open it. Opening it connects your browser to giscus and GitHub. Do not post credentials or private project data.