Skip to content

refactor: delegate auth flow to @doist/cli-core/auth#70

Merged
scottlovegrove merged 4 commits into
mainfrom
refactor/cli-core-auth
May 11, 2026
Merged

refactor: delegate auth flow to @doist/cli-core/auth#70
scottlovegrove merged 4 commits into
mainfrom
refactor/cli-core-auth

Conversation

@scottlovegrove
Copy link
Copy Markdown
Contributor

Summary

  • Drops the bespoke OAuth stack (src/lib/pkce.ts, oauth.ts, oauth-server.ts, the entire login action in commands/auth.ts) and delegates the flow to @doist/cli-core/auth's runOAuthFlow + attachLoginCommand. Mirrors twist-cli#215.
  • New OutlineAuthProvider (src/lib/auth-provider.ts) owns the outline-specific behaviour:
    • authorize() — builds the /oauth/authorize URL with cli-core's generateVerifier / deriveChallenge. Resolves --base-url / --client-id from flags → env → config → interactive prompt.
    • exchangeCode() — form-urlencoded POST to /oauth/token. Public client — no client_secret, no Authorization: Basic header (unlike twist).
    • validateToken() — hits auth.info with the unsaved token via a new apiRequest(path, body, { token, baseUrl }) override so we can identify the user before persisting.
  • New OutlineTokenStore adapter maps the cli-core account onto the existing config file (adds auth_user_id / auth_user_name to round-trip the identity through store.active()).
  • Branded success / error HTML preserved byte-for-byte in src/lib/auth-pages.ts and passed via renderSuccess / renderError.
  • ol auth login gains --read-only, --callback-port, --json, --ndjson for free from attachLoginCommand; --base-url / --client-id chained onto the returned command.
  • Breaking: ol auth login --token <token> flag is gone. Login is OAuth-only now. Set OUTLINE_API_TOKEN env var if you need to script with a personal token.
  • Net: 14 files changed, +625 / −688. 115 tests pass.

Test plan

  • npm run type-check
  • npm run lint:check
  • npm test (115 tests pass)
  • npm run build
  • npm run check:skill-sync
  • ol auth login --help lists --read-only, --callback-port, --json, --ndjson, --base-url, --client-id
  • Smoke: ol auth logout && ol auth login --base-url https://… --client-id … against a real Outline workspace — branded success page renders, token persisted, terminal prints green "Authenticated to … as …"
  • ol auth status reports team + user
  • ol auth login --json emits machine-readable success envelope

🤖 Generated with Claude Code

- Drops the bespoke OAuth stack (`src/lib/pkce.ts`, `oauth.ts`,
  `oauth-server.ts`, the entire login action in `commands/auth.ts`) and
  delegates the flow to `@doist/cli-core/auth`'s `runOAuthFlow` +
  `attachLoginCommand`.
- New `OutlineAuthProvider` (`src/lib/auth-provider.ts`) owns the
  outline-specific behaviour: `authorize` builds the `/oauth/authorize`
  URL with cli-core's `generateVerifier` / `deriveChallenge`,
  `exchangeCode` posts the form-urlencoded token exchange (public
  client — no `client_secret`), `validateToken` hits `auth.info` with
  the unsaved token via a new `apiRequest` token/baseUrl override.
- New `OutlineTokenStore` adapter maps the cli-core account onto the
  existing config file (adds `auth_user_id` / `auth_user_name` to
  round-trip the identity).
- Branded success / error HTML preserved byte-for-byte in
  `src/lib/auth-pages.ts` and passed to `attachLoginCommand` via
  `renderSuccess` / `renderError`.
- `ol auth login` gains `--read-only`, `--callback-port`, `--json`,
  `--ndjson` for free; `--base-url` / `--client-id` chained onto the
  returned command. `--token` paste flag dropped — login is OAuth-only.
- Skill content + skills/outline-cli/SKILL.md updated to match.
- 115 tests pass; type-check + oxlint clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@scottlovegrove scottlovegrove self-assigned this May 11, 2026
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 delegates the bespoke OAuth stack to @doist/cli-core/auth, introducing a streamlined OutlineAuthProvider and OutlineTokenStore while preserving the custom branded authentication pages. Leveraging the shared core library significantly reduces duplication and standardizes the login flow across Doist CLI tools. There are a few remaining details to adjust, such as ensuring proxy-aware fetching during token exchange, routing interactive prompts to stderr to protect JSON outputs, preserving environment variable overrides, and addressing a few test coverage and skill documentation updates.

Share FeedbackReview Logs

Comment thread src/lib/auth-provider.ts Outdated
Comment thread src/commands/auth.ts Outdated
Comment thread src/lib/auth-provider.ts
Comment thread src/lib/auth-provider.ts Outdated
Comment thread src/lib/auth-provider.ts Outdated
Comment thread src/__tests__/auth-provider.test.ts Outdated
Comment thread src/commands/auth.ts
Comment thread src/lib/auth-pages.ts
Comment thread src/__tests__/auth-provider.test.ts Outdated
Comment thread src/__tests__/auth-provider.test.ts Outdated
scottlovegrove and others added 3 commits May 11, 2026 18:17
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- [P1] Route OAuth token exchange through `fetchWithRetry` so it picks
  up the shared Undici proxy/retry dispatcher used by the rest of the
  network stack.
- [P2] Preserve `OUTLINE_OAUTH_CALLBACK_PORT` env override by reading
  it in `commands/auth.ts` and passing it to `attachLoginCommand`'s
  `preferredPort` (falls back to the default for unparseable values).
- [P2] Send the interactive base-URL / client-ID prompts to stderr so
  `--json` / `--ndjson` envelopes on stdout stay clean.
- [P2] Persist `auth_team_name` alongside the rest of the auth identity
  so `OutlineTokenStore.active()` round-trips the full account shape
  instead of fabricating an empty string. `teamName` is now optional.
- [P2] Document `ol auth login --read-only` in `SKILL_CONTENT` and
  regenerate the synced skill file.
- [P2] Tests now mock `apiRequest` (not `fetchWithRetry`) when
  exercising `validateToken`, per `CLAUDE.md`.
- [P2] New `auth-command.test.ts` covers the Commander-level surface:
  asserts the `--base-url` / `--client-id` chained options, the
  `OUTLINE_OAUTH_CALLBACK_PORT` override, and the `onSuccess` hook in
  both default and JSON output modes.
- [P2] New `auth-pages.test.ts` covers the renderSuccess / renderError
  output so future edits can't silently change the branded UX or
  break the html-escaping on the error message.
- [P2] `OutlineTokenStore.clear` test now inspects the on-disk config
  and asserts every auth-related key is removed (and non-auth keys
  like `update_channel` are preserved).
- [P3] Delete `saveConfig` from `lib/auth.ts` — superseded by the
  token store; remove its lingering mocks in `commands.test.ts` and
  `empty-output.test.ts`.
- [P3] Switch test mocks to `vi.mocked(fn)` instead of forced
  `as ReturnType<typeof vi.fn>` casts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Squashed redundant cases in auth-provider / auth-pages / auth-command
without losing coverage of the substance: provider authorize / exchange
/ validate; store round-trip + legacy + clear; chained command flags +
env-driven callback port + success-mode silencing in JSON output;
HTML rendering + escape.

Net 487 -> 266 lines across the three new test files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@scottlovegrove scottlovegrove requested review from a team and pawelgrimm and removed request for a team May 11, 2026 18:17
@scottlovegrove scottlovegrove added the 👀 Show PR PR must be reviewed before or after merging label May 11, 2026
@scottlovegrove scottlovegrove merged commit d1b20b2 into main May 11, 2026
4 checks passed
@scottlovegrove scottlovegrove deleted the refactor/cli-core-auth branch May 11, 2026 18:18
@doist-release-bot
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.6.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