fix: surface actionable auth hint on validate, transform and publishing commands - #300
Open
MuhammadRafay1 wants to merge 2 commits into
Open
fix: surface actionable auth hint on validate, transform and publishing commands#300MuhammadRafay1 wants to merge 2 commits into
MuhammadRafay1 wants to merge 2 commits into
Conversation
…ng errors
Three unauthenticated code paths bypassed the shared unauthorizedWithHint
factory and printed stale or bare messages:
- api validate had its own message catalog referencing a nonexistent
'auth:login' command syntax
- api transform concatenated the API's own 401 reason with the same legacy
string, rendering a doubled message
- publishing profile list and sdk publish returned the bare
ServiceError.UnAuthorized singleton ("Unauthorized access.")
The publishing pre-checks additionally tested the wrong condition: auth
logout blanks config.json rather than deleting it, so getAuthInfo returns a
non-null AuthInfo with an empty key. A logged-out user therefore skipped the
pre-check, sent an empty X-Auth-Key and got a wire 401 mapped to the bare
singleton. The guard now checks the key rather than the object.
Both service-level message catalogs keep their existing 400/403/500 text; only
the 401 branches were redirected, so no non-auth message changes.
Verified end to end against a logged-out config: all three commands now print
the login command and the --auth-key flag. Cognitive complexity is unchanged
for every function touched (sonarjs S3776).
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
auth status printed "Invalid API key provided." when the user was simply logged out, and printed nothing at all when config.json was absent. Both stemmed from the same wrong condition. removeAuthInfo (auth logout) blanks config.json rather than deleting it, so getAuthInfo returns a non-null AuthInfo with an empty key. The action's `accountInfo === null` guard therefore never fired for a logged-out user: it sent /account/profile a request with an empty X-Auth-Key purely to receive a 401, which was then rendered with the login flow's "invalid key" copy — misleading, since auth status accepts no auth key flag at all. When config.json was genuinely missing the guard did fire, but returned a failed ActionResult without printing any message. The guard now tests the key rather than the object, so both logged-out shapes are caught locally and print an actionable message with no wasted request. "Invalid API key provided." is now only reachable where it is accurate: a non-empty stored key that the API rejects as expired or revoked. Verified in all three states: blank config.json, missing config.json, and a planted invalid key. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
MuhammadRafay1
requested review from
Shield-Jaguar,
aliasghar98 and
saeedjamshaid
as code owners
July 28, 2026 13:24
|
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.



Fix misleading auth error messages across CLI commands
This PR fixes gaps in Gap#2 found by QA and reported here https://github.com/apimatic/apimatic-io/issues/2180
Note: These are not regression errors from previous changes on this branch, instead new issues identified
Four commands reported unauthenticated and invalid-credential states with stale,
duplicated, bare, or outright wrong messages. None of them reached the
ServiceError.unauthorizedWithHintfactory introduced earlier on this branch.api validate…Please run 'auth:login' or provide a valid auth key.You are not authorized to perform this action. Please run apimatic auth login to log in, or provide a valid auth key using the --auth-key flag.api transformAuthorization has been denied for this request. Please run apimatic auth login to log in, or provide a valid auth key using the --auth-key flag.publishing profile list,sdk publishUnauthorized access.api validateauth status(logged out)Invalid API key provided.You are not logged in. Please run apimatic auth login to log in.auth status(no config file)Failedauth status(stored key rejected)Invalid API key provided.Two commits: the service-layer messages, then
auth status.The blank-config bug behind most of this
removeAuthInfo(auth logout) blanksconfig.jsoninstead of deleting it:So getAuthInfo returns a non-null AuthInfo with an empty key, and every
authInfo === null guard in the codebase silently fails to fire for a logged-out
user. Those call sites sent a request with an empty X-Auth-Key purely to
receive a 401, then rendered whatever that 401 mapped to.
That is why publishing profile list showed the bare singleton message, and why
auth status claimed an invalid key had been "provided" to a command that
accepts no auth-key flag. Guards now test the key, not the object:
-if (authInfo === null) {
+if (!authInfo?.authKey) {
Besides fixing the message, this removes a pointless network round-trip from
every logged-out invocation (auth status drops from ~1.5s to ~1s).
auth status specifics
Two separate defects, one condition:
and printed the login flow's "invalid key" copy. Nothing was provided — and
StatusAction.execute(authKey) is always called with null from
commands/auth/status.ts, so a provided key is impossible here.
ActionResult.failed() without printing anything — a bare Failed with no
explanation.
With the guard fixed, both print the actionable "not logged in" message, and
Invalid API key provided. is now reachable only where it's accurate: a
non-empty stored key that the API rejects as expired or revoked. Verified in all
three states, including with a planted invalid key.
Service-layer message fixes
message catalog and never call the shared mapper, so both carried the legacy
'auth:login' text — a command syntax this CLI doesn't have. transform
additionally concatenated it on top of the API's own 401 reason, producing a
visibly doubled message.
400/403/500 text in both catalogs is untouched, so no non-auth message changes.
profile list one — they share the identical condition, and fixing one would
leave sdk publish printing the bare string.
Decisions
prompts/auth/status.ts identity-compares against the
ServiceError.UnAuthorized singleton to select its invalid-key message;
unauthorizedWithHint returns a fresh instance, so changing that branch would
silently break it.
Known gap:
Below Gap is reported by QA as Gap#3 in the Test report added earlier in the message.
This will be handled in a seperate issue here #301. This is a Bug.
401 into "falling back to the default TOC structure", overwrites a real
toc.yml with an empty-component one, returns exit 0, and then hangs
indefinitely: generateTocData is a stream-response endpoint, so the SDK
returns ApiError.body as an undrained IncomingMessage, the TLS socket stays
open, and outro() only sets process.exitCode rather than calling
process.exit. Confirmed via handle probe (TLSSocket … readable=true);
destroying that stream turns a 90s hang into a 3s exit. Latent in any
stream-endpoint error, including the portal/SDK downloads.