Repository navigation
Preserve auth hints and render provider diagnostics - #183
Merged
luciusmagn merged 1 commit intoNov 2, 2026
Merged
Conversation
luciusmagn
force-pushed
the
fix/auth-401-diagnostics
branch
from
November 2, 2026 22:44
8aa5fa4 to
0795637
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 readsProvider 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-detailredacts 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-fieldsreads a bounded response body and extracts only JSONerror.messageanderror.codestrings. Malformed JSON and non-string fields do not become diagnostic text.provider-signal-transport-failure :aroundmethod 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-messagemarks 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-failurecarries the final status, code, and request ID as anauthentication-error, outside provider retry classification. Itsprovider-api-error-messagemethod returns the full report;provider-error-responseandprovider-error-response-idreturnnil.provider--authentication-conditionappends available diagnostics while preserving the existing API-keyrun autolith auth PROVIDERhint and the subscriptionafter a bounded refreshhint.provider--call-with-bounded-retriesuses 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
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
Verified in use
Verified in pristine sessions against a loopback HTTP 401 provider. Each pair is upstream baseline → final rendering:
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)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)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)