Skip to content

auth: simplify auth/login UX — drop PATs, context-aware status & logout#1341

Open
toothbrush wants to merge 13 commits into
mainfrom
auth-context-consolidation
Open

auth: simplify auth/login UX — drop PATs, context-aware status & logout#1341
toothbrush wants to merge 13 commits into
mainfrom
auth-context-consolidation

Conversation

@toothbrush
Copy link
Copy Markdown
Contributor

@toothbrush toothbrush commented Jun 3, 2026

https://entire.io/gh/entireio/cli/trails/495

Simplifies the entire auth surface and fixes a logout/status bug, building on #1337.

User impact

  • entire auth status shows who you are (Name (@handle) <email> + provider identity from /me), the active context, and the active sessions on that core (NAME / CREATED / LAST USED / EXPIRES) — so the effect of logout / logout --all is visible. It queries the active context's login server, so auth use <ctx> retargets it.
  • entire logout revokes your session server-side via entire-core against the active context's core (--all = every session on it) — exactly the sessions status lists. Previously hit entire.io's PAT endpoint and 400'd.
  • entire auth contexts gets a table with headers + active marker.
  • Removed entire auth list and entire auth revoke (they managed ent_ PATs, which are sunset, and by now unused by the CLI).

What changed

  • All ent_ PAT machinery ripped out; session list/revoke target entire-core /api/auth/tokens on the active context's core, never entire.io's /api/v1/auth/tokens.
  • api.Tokenapi.Session; added coreapi.NewWithBearer; newSessionsClient(coreURL, token).
  • Hardened "token invalid → re-login" detection (incl. non-JSON 401s).

Screenshots

image

Not in this PR (follow-ups)

  • The COR-389 core: silent JWT refresh on control-plane calls (contextTokenStore + RefreshPath into defaultManager) — untouched.
  • Multi-core retargeting for the other control-plane commands (org/repo/project/grant via coreapi.New()) — still static AuthBaseURL. auth status + logout are retargeted here; the rest aren't.
  • Minor: resolveAuthHostToken is now prod-unused (kept alive only by its tests) — prune candidate.

🤖 Generated with Claude Code


Note

Medium Risk
Changes authentication, session revocation, and multi-context core targeting for status/logout; mistakes could leave stale sessions or hit the wrong login server, though behavior is heavily tested.

Overview
This PR reframes CLI auth around entire-core login sessions instead of data-API PATs (ent_ tokens). It removes entire auth list / entire auth revoke and the api auth-token client; session list/revoke now goes through /api/auth/tokens on the active login server (api.Session, WithSessionsPath).

entire auth status resolves the active context’s CoreURL and session JWT (resolveStatusTarget), validates via GET /me (coreapi.NewWithBearer), prints profile + context, and shows an active sessions table aligned with logout behavior. Invalid-login detection is broadened (core 401, non-JSON 401 decode errors, STS failures).

entire logout revokes the current session (or all sessions on that core with --all) against the same target core, clears local credentials, then promoteNextLogin so repeated logout can drain saved contexts. RemoveAllContexts is dropped; entire auth contexts gets a styled table.

Provider AuthTokensPath routing is removed; OAuth provider config is unchanged aside from that.

Reviewed by Cursor Bugbot for commit f9b8c3e. Configure here.

toothbrush and others added 9 commits June 3, 2026 15:47
Remove the `entire auth list` command. The rows it listed are server-side
login sessions (OAuth refresh-token families), not personal access tokens —
nothing functional depends on listing them (see COR-389 notes). Fold that
view into `entire auth status` as a clearly-labelled "Active sessions" table,
reusing the table renderer.

`auth revoke <id>` still works; the session IDs now come from `auth status`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 1774a9e75c37
Delete the `entire auth revoke` command. Session management collapses to
two verbs: `auth status` shows active sessions, `logout` ends them.

Redefine the `logout --all` flag — it no longer removes all *local*
contexts. Instead:

  - `logout`        revokes the active session server-side (DELETE
                    .../tokens/current) and removes the active context
                    locally. (Unchanged default behaviour.)
  - `logout --all`  additionally asks the server to revoke *every* session
                    on the active core (list families -> delete each by id).
                    The local side is identical to the default.

After a logout clears the active context, the next saved context is
promoted to active, so running `entire logout` repeatedly drains every
saved login in turn.

Cross-core revoke is out of scope: these endpoints target AuthBaseURL's
core only, pending the COR-389 control-plane retargeting.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 9dc3b1c4312c
Replace the tab-separated, headerless context listing with an aligned,
styled table (CONTEXT / HANDLE / CORE URL columns, "*" marks the active
context), matching the `auth status` active-sessions table.

Extract the column-sizing/writing loop into a shared renderAlignedTable
helper and rename the shared style set authTableStyles, since both auth
tables now use it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 52bdb2ae5d4e
These rows are OAuth refresh-token families (login sessions), not personal
access tokens — the CLI never mints them. Rename so the types are
self-documenting and drop the "Despite the api.Token name…" caveat:

  api.Token              -> api.Session
  api.TokensResponse     -> api.SessionsResponse   (wire key stays "tokens")
  (*Client).ListTokens   -> ListSessions
  (*Client).RevokeToken  -> RevokeSession
  (*Client).RevokeCurrentToken -> RevokeCurrentSession

  cli: authTokenLister   -> sessionLister
       defaultListTokens -> defaultListSessions
       defaultRevokeCurrentToken -> defaultRevokeCurrentSession
       newAPITokensClient -> newSessionsClient

Pure rename: wire paths and JSON field names are unchanged, so the server
contract is untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 0e17fccbbe86
Dead since `logout --all` was redefined to revoke server-side sessions
rather than nuke all local contexts. Nothing else references it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 7dc263eaaac8
`entire auth status` now calls the core API's GET /me, which both validates
the stored token (liveness) and supplies a profile header:

  Logged in to https://us.auth.entire.io
    User:     Alice Smith (@alice) <alice@example.com>
    Identity: github/alice
    Token:    stored in OS keychain

  Active sessions:
  ...

/me is the primary liveness gate (a 401 surfaces as
*coreapi.ErrorModelStatusCode, now recognised by isKeychainTokenRejected).
The active-sessions list runs after, on the data API; since the token is
already known good, a list failure degrades to a stderr warning instead of
failing the command. Empty profile fields are omitted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 5ca10643dc53
`auth status` and `logout` were pointing session list/revoke at entire.io's
/api/v1/auth/tokens — which is the legacy `ent_` personal-access-token
surface, not login sessions. For a JWT login that endpoint lists nothing
(no ent_ PATs) and rejects DELETE /current with 400 ("revoke entire-core
JWTs via entire-core"). The CLI never mints or sends ent_ PATs, so it has no
business there.

Repoint session management at entire-core (the auth host) /api/auth/tokens,
authenticated with the session-scoped login JWT (resolveAuthHostToken — a
same-host resolution that preserves the entire:session scope core's session
routes require):

- auth status: drop the server-side session table entirely. Status is now
  local: GET /me (profile + liveness) + the active login context. No PAT
  endpoint, no empty "active sessions".
- logout: revoke the current session (and --all: every session on the core)
  via entire-core, not entire.io.

Removes the now-dead session-table rendering + date-formatting helpers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 99a4950a334d
entire.io's ent_ personal-access-token surface (/api/v1/auth/tokens) is
being sunset, and the CLI never used it for auth — it authenticates with the
core JWT. Remove every trace from this repo:

- Drop the dead Provider.AuthTokensPath field (and its /api/v1/auth/tokens
  values + tests); nothing references the entire.io PAT path anymore.
- Rename the api.Client session plumbing off PAT-era naming:
  api/auth_tokens.go -> api/sessions.go, WithAuthTokensPath -> WithSessionsPath,
  authTokensPath -> sessionsPath, errAuthTokensPathUnset -> errSessionsPathUnset.
- Scrub PAT / ent_ / personal-access-token mentions from comments.

Session management (auth status liveness via /me, logout revocation) targets
entire-core's /api/auth/tokens on the auth host (api.AuthBaseURL()) with the
session-scoped core JWT — never entire.io's PAT endpoint, so the 400 from
that endpoint cannot recur.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 5969a20f41e3
`auth status` queried /me against the static api.AuthBaseURL(), so with an
active context on a different core (e.g. `auth use eu.auth.entire.io` while
AuthBaseURL defaults to us.*) it sent the context's token to the wrong core
and got a 401 — surfaced as a raw ogen decode dump because the 401 body was
text/plain.

- Resolve the active contexts.json context first (resolveStatusTarget): use
  its CoreURL + session token, falling back to AuthBaseURL + the legacy
  keyring entry only when no context is active. `auth use` now retargets
  status. "Logged in to <core>" reflects the active context.
- Add coreapi.NewWithBearer(coreURL, token) to hit a specific login server
  with a fixed bearer (no STS), used by status's /me.
- Harden isKeychainTokenRejected: a non-JSON 401 (ogen "decode response:
  ... (code 401)") now maps to the friendly re-login hint, not a raw dump.
- TLS-guard the resolved context core URL before sending the token.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 1385b003c7a8
Copilot AI review requested due to automatic review settings June 3, 2026 06:22
Comment thread cmd/entire/cli/auth.go
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR simplifies the entire auth command surface by removing deprecated PAT management and shifting “status”/“logout” behavior to use entire-core session concepts, with better multi-context UX.

Changes:

  • Removed auth list / auth revoke (PAT/token-management) and introduced core session management via /api/auth/tokens.
  • Updated auth status to query GET /me on the active context’s core, printing user identity + active context details.
  • Improved auth contexts output formatting and updated logout flow/tests (including --all server-side session revocation).

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/coreapi/client.go Adds NewWithBearer to query a specific core origin with a fixed bearer for context-aware status checks.
cmd/entire/cli/logout.go Reworks logout messaging and server-side revocation to use sessions endpoints; adds context promotion behavior.
cmd/entire/cli/logout_test.go Updates logout unit tests for new revoke paths and --all behavior.
cmd/entire/cli/auth/provider.go Removes provider-level PAT endpoint configuration (AuthTokensPath).
cmd/entire/cli/auth/provider_test.go Adjusts provider tests to match provider struct changes.
cmd/entire/cli/auth/contexts_test.go Removes tests for deleted RemoveAllContexts behavior.
cmd/entire/cli/auth/context_store.go Removes RemoveAllContexts; keeps context-preferring token read behavior and current-context deletion.
cmd/entire/cli/auth.go Drops list/revoke subcommands; adds context-aware auth status via /me, introduces sessions client wiring + table helpers.
cmd/entire/cli/auth_test.go Refactors auth tests to validate /me-based status behavior and broadened invalid-token detection.
cmd/entire/cli/auth_context.go Renders auth contexts as a styled, aligned table with headers and active marker.
cmd/entire/cli/auth_context_test.go Adds coverage for resolveStatusTarget preference + contexts table headers + logout promotion behavior.
cmd/entire/cli/api/sessions.go Introduces Session API (list/revoke/current) against entire-core session endpoints.
cmd/entire/cli/api/sessions_test.go Adds/updates tests for the new sessions API methods and paths.
cmd/entire/cli/api/client.go Renames client path config from auth-tokens to sessions (WithSessionsPath).
cmd/entire/cli/api/auth_tokens.go Removes the old PAT/auth-token management client implementation.

Comment thread cmd/entire/cli/logout.go Outdated
Comment thread cmd/entire/cli/logout.go Outdated
Comment thread cmd/entire/cli/logout.go
Bring back the sessions table now that it correctly lists entire-core login
sessions (not entire.io PATs), so the effect of `logout` / `logout --all` is
visible:

- `auth status` lists the active sessions (NAME / CREATED / LAST USED /
  EXPIRES) on the active context's core, after the profile/context lines,
  with a hint tying the table to `logout` and `logout --all`. Best-effort:
  a listing failure is a soft note (liveness already confirmed via /me).
- `logout` now revokes against the **active context's core** too (shared
  resolveStatusTarget), so it acts on exactly the sessions status shows —
  not a static AuthBaseURL. Fixes the same multi-core mismatch for logout.
- newSessionsClient takes an explicit coreURL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 8159eed97feb
@toothbrush toothbrush requested a review from Copilot June 3, 2026 06:50
@toothbrush
Copy link
Copy Markdown
Contributor Author

@cursor review

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Comment thread cmd/entire/cli/logout.go
Comment thread cmd/entire/cli/logout.go
Comment thread cmd/entire/cli/logout.go Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit f9b8c3e. Configure here.

toothbrush and others added 2 commits June 3, 2026 16:43
revokeAllSessions wrapped ListSessions/RevokeSession failures with their
own prefixes, but (*api.Client) already wraps both (incl. the session id),
producing "list sessions: list sessions: …" / "revoke session X: revoke
session X: …". Return the wrapped errors verbatim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 009341d5e790
The comment claimed the impl resolves its own data-API bearer; the caller
now resolves the active context's core URL + token and binds them into the
closure. Describe the actual contract.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 2525dd1ceb9f
@toothbrush toothbrush marked this pull request as ready for review June 3, 2026 07:30
@toothbrush toothbrush requested a review from a team as a code owner June 3, 2026 07:30
Better name for the flag.

Entire-Checkpoint: 0eb8618db00d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants