Skip to content

feat(auth): add token command group (save + view)#80

Merged
scottlovegrove merged 3 commits into
mainfrom
scottl/cli-core-auth-token
May 24, 2026
Merged

feat(auth): add token command group (save + view)#80
scottlovegrove merged 3 commits into
mainfrom
scottl/cli-core-auth-token

Conversation

@scottlovegrove
Copy link
Copy Markdown
Contributor

@scottlovegrove scottlovegrove commented May 24, 2026

Summary

Implements the auth token command group.

  • ol auth token [token] — saves a personal Outline API token. Validates via auth.info, resolves the real account identity (user id, name, team), and persists a full account record so --user, account list, and auth status all work. Reuses auth login's base-URL cascade (--base-url$OUTLINE_URL → saved default → prompt). With no argument it prompts for the token with masked input; in a non-interactive shell it errors with NO_TOKEN.
  • ol auth token view — delegates to cli-core's attachTokenViewCommand: prints the bare stored token to stdout for scripts (newline only on a TTY), honours --user, and refuses (TOKEN_FROM_ENV) when the token comes from $OUTLINE_API_TOKEN.
  • Any auth.info failure on save is wrapped as a single AUTH_VERIFICATION_FAILED error with a base-URL hint, instead of leaking the raw API string.

Test plan

  • npm run type-check — clean
  • npm run test — 218 + 7 new tests pass
  • npm run check:skill-sync — in sync
  • Live against handbook.doist.com: save (happy path), view (bare token, no trailing newline when piped), $OUTLINE_API_TOKEN refusal, NO_TOKEN in non-TTY, bad-token + wrong-base-url → AUTH_VERIFICATION_FAILED
  • Manual: interactive masked prompt (ol auth token in a TTY) — not automatable here

🤖 Generated with Claude Code

`ol auth token [token]` saves a personal Outline API token: it validates
the token via `auth.info`, resolves the real account identity (user id,
name, team), and persists a full account record so `--user`, `account
list`, and `auth status` all work. Reuses the same base-URL cascade as
`auth login` (`--base-url` -> $OUTLINE_URL -> saved default -> prompt) and
prompts for the token with masked input when no argument is given.

`ol auth token view` delegates to cli-core's `attachTokenViewCommand` to
print the bare stored token to stdout for scripts, with a newline only on
a TTY and a refusal when the token comes from $OUTLINE_API_TOKEN.

Any `auth.info` failure on save (bad token, wrong instance, unreachable
host) is wrapped as a single AUTH_VERIFICATION_FAILED error with a
base-URL hint, rather than leaking the raw API string.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@doistbot doistbot left a comment

Choose a reason for hiding this comment

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

This PR introduces the new auth token command group for saving and viewing Outline API tokens, along with helpful account identity resolution and base-URL cascading. These additions are a solid step toward completing the authentication roadmap and nicely expand the CLI's utility for CI workflows and AI agents. There are a few areas to refine, primarily concerning the removal of the positional token argument to comply with secrets management standards, fixing the interactive masked prompt rendering, and consolidating duplicated authentication and prompt helpers. Some additional polish around test coverage, preventing global state leakage in tests, and ensuring error messages consistently hide raw API details will round out the implementation.

Share FeedbackReview Logs

Comment thread src/commands/auth.ts Outdated
Comment thread src/commands/auth.ts Outdated
Comment thread src/lib/skills/content.ts Outdated
Comment thread src/commands/auth.ts Outdated
Comment thread src/commands/auth.ts Outdated
Comment thread src/commands/auth.ts
Comment thread src/commands/auth-token.test.ts Outdated
Comment thread src/commands/auth-token.test.ts Outdated
Comment thread src/commands/auth-token.test.ts
Comment thread src/commands/auth.ts
- Fix masked prompt: it dropped readline's ANSI line-clear codes, so the
  label repeated on every keystroke. Consolidate into a shared
  `prompt(question, { hidden })` in auth-provider (mute-after-prompt
  pattern) and drop the duplicate `promptHiddenToken`.
- Collapse any `auth.info` verification failure into a single stable
  `AUTH_VERIFICATION_FAILED` with base-URL hints, never interpolating the
  raw API/network string.
- Extract `identifyAccount(token, baseUrl, oauthClientId?)` and reuse it
  from the OAuth `validate` hook and `auth token` so identity resolution
  lives in one place.
- `resolveBaseUrl`: explicit `{ baseUrl?: unknown }` input shape and a
  non-TTY fast path that returns the configured default instead of
  blocking a CI shell on a prompt.
- Fix the SKILL doc: `--user` is a root flag (`ol --user <ref> auth token
  view`), not a subcommand option.
- Tests: assert the wrapped error contract (message hidden, hints
  present), snapshot/restore `process.stdin.isTTY`, and cover the masked
  prompt save path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@scottlovegrove
Copy link
Copy Markdown
Contributor Author

@doistbot /review

Copy link
Copy Markdown
Member

@doistbot doistbot left a comment

Choose a reason for hiding this comment

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

This PR successfully implements the new auth token command group, enabling users to save and view personal Outline API tokens. The addition is highly valuable and integrates well with the existing authentication workflows. To fully align with security standards and ensure long-term maintainability, a few updates are needed, such as strictly enforcing interactive-only token input to prevent shell history leaks, refactoring duplicated reporting logic, and avoiding private Node internals in the custom prompt. Addressing these alongside a few test scoping and coverage gaps will help completely solidify this excellent feature.

Share FeedbackReview Logs

Comment thread src/commands/auth.ts
Comment thread src/lib/auth-provider.ts Outdated
Comment thread src/commands/auth.ts Outdated
Comment thread src/commands/auth.ts Outdated
Comment thread src/lib/auth-provider.ts Outdated
Comment thread src/commands/auth-token.test.ts Outdated
Comment thread src/commands/auth-token.test.ts Outdated
Comment thread src/lib/auth-provider.ts Outdated
Comment thread src/lib/auth-provider.ts
- Masked prompt no longer pokes readline's private `_writeToOutput`; it
  routes echo through a muted `Writable` passed as `output` (public API).
- Extract `logSaveResult` in auth-output.ts and reuse it from both the
  `auth login` success hook and `auth token`, so the two save flows share
  one machine-output/warning path (mirrors `logClearResult`).
- Fix the `NO_TOKEN` hint: it no longer implies `auth token` reads
  `OUTLINE_API_TOKEN` as input — it's framed as an alternative auth method.
- `stringFlag` now takes a value (`stringFlag(options.baseUrl)`); callers
  updated.
- Tests: use `.mock*Once` to stop hoisted-mock bleed, capture the rejection
  with `.catch`, add an isolated `prompt({ hidden })` masking test (mocked
  `node:readline/promises`) and a non-TTY `resolveBaseUrl` fallback test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@scottlovegrove scottlovegrove requested review from a team and gnapse and removed request for a team May 24, 2026 17:21
@scottlovegrove scottlovegrove self-assigned this May 24, 2026
@scottlovegrove scottlovegrove added the 👀 Show PR PR must be reviewed before or after merging label May 24, 2026
@scottlovegrove scottlovegrove merged commit 99789cc into main May 24, 2026
5 checks passed
@scottlovegrove scottlovegrove deleted the scottl/cli-core-auth-token branch May 24, 2026 17:22
doist-release-bot Bot added a commit that referenced this pull request May 24, 2026
## [1.10.0](v1.9.0...v1.10.0) (2026-05-24)

### Features

* **auth:** add `token` command group (save + view) ([#80](#80)) ([99789cc](99789cc))
@doist-release-bot
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.10.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

released 👀 Show PR PR must be reviewed before or after merging

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants