auth: drop `auth list`, show active sessions in `auth status` · Entire

auth: drop auth list, show active sessions in auth status

0f84383·

toothbrush·1mo ago·2 files·+74 added/-142 removed

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

Sessions

1774a9e75c37View transcript

Changes

2

import (
    "context"
    "encoding/json"
    "errors"
    "fmt"
    "io"
    "github.com/spf13/cobra"
)

// authTokenLister lists API tokens for the authenticated user. The
// implementation resolves its own data-API bearer via
// auth.TokenForResource (RFC 8693 exchange in split-host setups, same-
// host shortcut otherwise); callers don't pass a bearer through, which
// removes the temptation to forward the wrong-audience keyring token.
// authTokenLister lists the authenticated user's active login sessions —
// the server-side refresh-token families (one per `entire login`, across
// all devices), surfaced by `entire auth status` and used by revoke as a
// liveness probe. Despite the api.Token name, these are sessions, not
// personal access tokens; the CLI never mints them. The implementation
// resolves its own data-API bearer via auth.TokenForResource (RFC 8693
// exchange in split-host setups, same-host shortcut otherwise); callers
// don't pass a bearer through, which removes the temptation to forward the
// wrong-audience keyring token.
type authTokenLister func(ctx context.Context) ([]api.Token, error)

// authTokenRevoker revokes a single API token by id. Same bearer-
// (same implementation as above)

// defaultListTokens fetches the authenticated user's active login sessions
// from the server. See authTokenLister for what these rows actually are.
func defaultListTokens(ctx context.Context) ([]api.Token, error) {
    token, err := resolveDataAPIToken(ctx)
    if err != nil {
        return nil, err
    }

tokens, err := list(ctx)
    sessions, err := list(ctx)
    if err != nil {
        if isKeychainTokenRejected(err) {
            fmt.Fprintf(w, "Token in keychain for %s is no longer valid.\n", baseURL)
        }
    }

return tokens, nil
}

// --- list -------------------------------------------------------------------
func newAuthListCmd() *cobra.Command {
    var jsonOut bool
    var insecureHTTPAuth bool
    cmd := &cobra.Command{
        Use:   "list",
        Short: "List active API tokens for the authenticated user",
        RunE: func(cmd *cobra.Command, _ []string) error {
            if err := requireSecureBaseURL(insecureHTTPAuth); err != nil {
                return err
            }
            return runAuthList(cmd.Context(), cmd.OutOrStdout(),
                auth.NewContextStore(), defaultListTokens, api.AuthBaseURL(), jsonOut)
        },
    }
    cmd.Flags().BoolVar(&jsonOut, "json", false, "Print tokens as JSON")
    addInsecureHTTPAuthFlag(cmd, &insecureHTTPAuth)
    return cmd
}

func runAuthList(ctx context.Context, w io.Writer, store tokenStore, list authTokenLister, baseURL string, jsonOut bool) error {
    token, err := store.GetToken(baseURL)
    if err != nil {
        return fmt.Errorf("read keychain: %w", err)
    }
    if token == "" {
        return fmt.Errorf("not logged in to %s; run 'entire login' first", baseURL)
    }

tokens, err := list(ctx)
    if err != nil {
        return err
    }

if jsonOut {
        enc := json.NewEncoder(w)
        enc.SetIndent("", "  ")
        if err := enc.Encode(tokens); err != nil {
            return fmt.Errorf("encode JSON: %w", err)
        }
    }

if len(tokens) == 0 {
        fmt.Fprintln(w, "No active tokens.")
        return nil
    }
    fmt.Fprintln(w, "Active sessions:")
    sortSessionsByRecency(tokens)
    renderSessionsTable(w, newSessionsTableStyles(w), tokens, time.Now())
    return nil
}

// sortSessionsByRecency orders sessions most-recently-used first
// ....
// renderSessionsTable prints a styled, column-aligned table of login sessions.
// ....