Skip to content

feat: bind stored credentials to their issuing auth endpoint - #20

Merged
nycomp merged 2 commits into
mainfrom
feat/cred-endpoint-binding
Oct 1, 2026
Merged

nycomp merged 2 commits into
mainfrom
feat/cred-endpoint-binding

Conversation

@nycomp

@nycomp nycomp commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Closes #18. Addresses the near-term (surface-the-endpoint) half of #19; the production-default flip stays open there until a prod deployment exists.

What

  • Binding: campus auth login and every successful token refresh now store a token_auth_url keyring entry recording the resolved auth URL that minted the tokens.
  • Mismatch check: get_api_client() and campus auth refresh compare the stored URL against the currently resolved one (trailing-slash-insensitive) and fail fast with:

    Stored token was issued by <A> but the CLI is targeting <B>. Run campus auth login to re-authenticate against <B>.

  • Login is the remediation: campus auth login no longer short-circuits as "Already authenticated" when the binding mismatches — it warns and re-authenticates against the current target.
  • Surfaced endpoints: auth login prints the endpoint it authenticates against; auth status shows the targeted endpoint plus the endpoint that issued the stored token (flagging mismatches); auth status --json gains auth_url, token_auth_url and endpoint_match.
  • Logout clears the binding along with the token set.

Migration / existing credentials

Deliberately zero-action, per #18:

  • Credentials stored before this change have no token_auth_url and are treated as matching — no wave of false failures on upgrade.
  • They bind naturally at the next login or successful refresh, so active users are fully bound within one token lifetime of upgrading.
  • Old CLI versions ignore the new keyring entry, so mixed-version use of the same OS account is safe in both directions.
  • When the campus-cli: surface the target auth endpoint now; flip default from development to production when prod exists #19 default flip to production eventually happens, every dev-bound token will mismatch and the check converts what would be silent 401s into a one-line re-login instruction. If the logout-side server revocation lands first, release notes can tell users to logout && login to also revoke the stale dev tokens server-side.

Testing

  • 96 tests pass (pytest -q), including new unit tests for the binding helpers and refresh stamping, and integration tests for the mismatch UX (status flag, login bypass of the short-circuit, refresh fail-fast, login stamping).
  • ruff check . clean.
  • Manually smoke-tested campus auth status against real legacy (unbound) credentials: shows both endpoints, reports binding as pending, no false mismatch.

Implements the design from #18; per-host key namespacing remains explicitly out of scope there.

Implements #18 and the near-term half of #19.

- store token_auth_url alongside the token set at login and refresh
- fail fast in get_api_client and auth refresh when the stored token
  was issued by a different endpoint than the one currently targeted
  (trailing-slash-insensitive), with a re-login instruction
- credentials stored before this change have no binding and are
  treated as matching; they bind at the next login or refresh
- auth login no longer short-circuits as already-authenticated when
  the binding mismatches; it re-authenticates against the new target
- auth login and auth status show the targeted endpoint and the
  endpoint that issued the stored token; auth status --json gains
  auth_url, token_auth_url and endpoint_match
- logout clears the binding along with the token
…nding

# Conflicts:
#	campus_cli/auth/common.py
#	campus_cli/auth/login.py
@nycomp
nycomp merged commit 6a82eea into main Oct 1, 2026
1 check passed
@nycomp
nycomp deleted the feat/cred-endpoint-binding branch October 1, 2026 03:50
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.

campus-cli: bind stored credentials to their issuing auth endpoint (per-environment mismatch check)

2 participants