wso2 / wso2/wso2-cli

A post-discovery issuer refusal reports auth.discovery_failed: decide whether the stable code list may grow

Open
#40 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Priority/Normal ready-for-agent Severity/Minor Type/Question
Dominant language
Go
Stars
0
Forks
3
Avg merge
8h 43m
Merged PRs (30d)
60

Description

Problem

internal/auth/source_clientcred.go:125 refuses with auth.discovery_failed on a branch reached only after discovery has demonstrably succeeded.

Execution arrives there having already: read the OIDC discovery document, resolved the token endpoint from it, sent a client_credentials request to that endpoint, and received an answer. The deployment refused, in terms refusedGrant has no rule for — not refusedToNarrow(), not rejectedClient(). Every step proves discovery worked. "Discovery failed" is the one thing that certainly did not happen.

Why the wrong code costs something

The code is not cosmetic. Section 8 of the login walkthrough keys a troubleshooting entry off it, and that entry sends a reader to check:

  • the issuer string, character for character, against the discovery document
  • TLS trust for the deployment's certificate
  • proxy, VPN and firewall reachability
  • whether the issuer advertises S256

All four are about reaching and reading the issuer. A CI engineer who lands on this branch will check their issuer URL, their trust store and their network, and find every one of them healthy — because the issuer answered.

The refusal's own recovery text already says the right thing ("check that this context's OAuth application is registered for the client-credentials grant and carries the permissions the command needs"). So the prose points one way and the code points another, and the code is what a script branches on.

The inconsistency

The other three uses of auth.discovery_failed agree with each other:

Site Condition
internal/auth/discovery.go:52 the discovery document could not be read
internal/auth/oauthflow/login.go:297 the same, on the login path
internal/auth/tokenrequest.go:168 (issuerUnreachable) the token endpoint could not be reached

Each means the shell never obtained an answer. The client-credentials branch is the outlier: it obtained one and could not classify it.

Worth noting how the browser path solves the same problem. internal/auth/source_browser.go:154 has the identical unclassifiable-refusal branch and returns auth.login_required, because a browser identity always has something to do — log in again. A client-credentials identity has no such fallback: wso2 login refuses that kind outright, so pointing there would leave the reader with nothing actionable. That is why this branch reached for a general-purpose code, and why it reached for the wrong one.

The decision

The accurate fix is a distinct code — auth.access_not_issued, or whatever name survives review — meaning the deployment answered and declined to issue access, for a reason the shell cannot classify.

That is a change to a contract, not a rename. Issue #17 defines the problem codes as a closed, stable list, and its user story 21 makes that stability the point: automation branches on these codes to tell "you may not" from "it is broken" without parsing prose. So the question this issue exists to settle is not really the name:

Under what rule may the stable code list grow? A code added for a condition that genuinely has no existing home is a different act from a code added because an existing one reads awkwardly. Whatever is decided here should be written down where the code list lives, so the next case does not re-open it.

Options, in the order I would consider them:

  1. Add auth.access_not_issued and record the rule that admitted it. Scripts matching auth.discovery_failed today would stop matching this branch — a behavior change for anyone already handling it, though the slice has not shipped to main yet, so the window for making it cheaply is now.
  2. Keep the code, fix the guide. Give section 8's auth.discovery_failed entry a fourth case covering the post-discovery refusal. Costs nothing, leaves a script unable to tell an unreachable issuer from a refusing one.
  3. Reuse an existing code. auth.narrowing_unavailable and auth.credential_unavailable are the near neighbours, and both are wrong here — that is precisely what the two branches above this one already ruled out.

Scope

Severity is low. The refusal is correct, the exit class is correct, and the recovery text is correct. Only the code is wrong, and only on one branch — but it is wrong in the direction that sends someone to inspect infrastructure that is working.

If option 1 is taken, section 8 of docs/guides/login.md gains an entry, and the acceptance tests around the client-credentials path pin the new code.

Found by review on #38, where it was deferred as a design change rather than a review fix.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with issue #17 and the refusal branches in internal/auth/source_clientcred.go, comparing them with internal/auth/discovery.go, internal/auth/oauthflow/login.go, and internal/auth/source_browser.go. Review the client-credentials acceptance tests and docs/guides/login.md. Done means the rule for extending the stable code list is decided and recorded, with the selected behavior and documentation covered by tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
authentication, cli, documentation, testing
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.