Skip to content

Preserve auth hints and render provider diagnostics - #183

Merged
luciusmagn merged 1 commit into
lambda-symbolics:masterfrom
htayj:fix/auth-401-diagnostics
Nov 2, 2026
Merged

luciusmagn merged 1 commit into
lambda-symbolics:masterfrom
htayj:fix/auth-401-diagnostics

Conversation

@htayj

@htayj htayj commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #182.

Problem

When a provider returns HTTP 401, the final authentication error shows only a generic hint to enter an API key or reports that credentials were rejected after a refresh. An invalid key and a token missing required scopes look identical. The provider's request ID, needed to investigate the failure with support, is also lost.

For example, a missing-scope response currently ends with Provider rejected Autolith's credentials after a bounded refresh. With this change it reads Provider rejected Autolith's credentials after a bounded refresh. (HTTP 401, request req-123, code scope_missing, Token is missing required scopes for this call).

Fix

  • provider--authentication-detail redacts credentials, replaces control characters with spaces, and copies length-bounded diagnostic strings so later changes to the original strings cannot alter the report.
  • provider--unauthorized-body-fields reads a bounded response body and extracts only JSON error.message and error.code strings. Malformed JSON and non-string fields do not become diagnostic text.
  • The provider-signal-transport-failure :around method captures HTTP 401 status, request ID, message, and code before normal error handling can discard them. It leaves other statuses unchanged and retains no response body.
  • provider--unauthorized-without-message marks responses without a usable JSON message, so the final report does not repeat a generic credentials-rejected sentence. The intermediate condition keeps that sentence for other callers.
  • provider--authentication-failure carries the final status, code, and request ID as an authentication-error, outside provider retry classification. Its provider-api-error-message method returns the full report; provider-error-response and provider-error-response-id return nil.
  • provider--authentication-condition appends available diagnostics while preserving the existing API-key run autolith auth PROVIDER hint and the subscription after a bounded refresh hint. provider--call-with-bounded-retries uses it for the final failure without changing the refresh policy.

Response-body recovery is limited to the HTTP client's 401 error carrying a response body, reading up to 4000 bytes; this does not add body recovery to other error paths. Details are sanitized and length-bounded, including an 80-character code limit and a 200-character request-ID limit.

Tradeoffs

  • Without a usable JSON message, the report omits body text and shows the available status, request ID, and any valid JSON error code. A non-JSON body therefore contributes no explanation.

Tests

  • provider-tests--authentication-hook: exercises 401 bodies as strings, bytes, and streams; malformed or missing JSON fields; a genuine message matching the generic fallback; secret redaction after JSON decoding; control-character removal; length limits; absent request IDs; stream closure; and independence from mutable response strings.
  • test-provider-authentication-retries: verifies one forced refresh for refreshable credentials, no refresh for static API keys, no extra provider events, and both existing hints with and without a provider message. Final failures preserve diagnostic fields and consistent rendered/readable reports without retaining response objects or entering provider retry classification.

Validation

  • Provider suite: 26 cases, 368 checks, 0 failures; source check passed. Both ran serially in one 4 GiB job.

Verified in use

Verified in pristine sessions against a loopback HTTP 401 provider. Each pair is upstream baseline → final rendering:

  • API key: auth49-loopback rejected Autolith's API key; run autolith auth auth49-loopback to enter it. → auth49-loopback rejected Autolith's API key; run autolith auth auth49-loopback to enter it. (HTTP 401, request auth49-public-request-id, code invalid_api_key, auth49-loopback-marker)
  • Missing scopes: auth49-loopback rejected Autolith's credentials after a bounded refresh. → auth49-loopback rejected Autolith's credentials after a bounded refresh. (HTTP 401, request auth49-public-request-id, code scope_missing, Token is missing required scopes for this call)
  • Non-JSON body: auth49-loopback rejected Autolith's API key; run autolith auth auth49-loopback to enter it. → auth49-loopback rejected Autolith's API key; run autolith auth auth49-loopback to enter it. (HTTP 401, request auth49-public-request-id)

@luciusmagn
luciusmagn force-pushed the fix/auth-401-diagnostics branch from 8aa5fa4 to 0795637 Compare November 2, 2026 22:44
@luciusmagn
luciusmagn merged commit 0795637 into lambda-symbolics:master Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Authentication failures lose provider diagnostics after credential exhaustion

2 participants