Skip to content

feat(cli): boxlite auth login --web (RFC 8628 device flow)#529

Closed
DorianZheng wants to merge 1 commit into
feat/auth-rest-credentialfrom
feat/auth-cli-device-flow
Closed

feat(cli): boxlite auth login --web (RFC 8628 device flow)#529
DorianZheng wants to merge 1 commit into
feat/auth-rest-credentialfrom
feat/auth-cli-device-flow

Conversation

@DorianZheng

@DorianZheng DorianZheng commented May 14, 2026

Copy link
Copy Markdown
Member

Summary

Adds the boxlite auth {login,logout,status} subcommand family with two co-equal paths matching how dev-workstation products (Daytona, Gitpod, Codespaces, Vercel) ship auth:

  • --api-key-stdin — paste an opaque key from the dashboard (no secret on argv)
  • --web — browser-based device flow (recommended)

Interactive boxlite auth login (no flags) prompts the user to pick.
--non-interactive emits the verification URL + user_code as JSON for IDE / agent integration (Stripe pattern).

Credentials are stored at ~/.config/boxlite/credentials.toml (0600, parent 0700) as a typed sum:

```toml
[profiles.default]
url = "https://api.boxlite.ai"

[profiles.default.credential.api_key]
key = "blk_live_..."

OR (mutually exclusive):

[profiles.default.credential.oauth]
access_token = "blo_..."
refresh_token = "blr_..."
expires_at = "2026-06-14T12:00:00Z"
```

Sum-type-on-disk means the file parser rejects mixed state, not a runtime warn!().

Logout calls POST /v1/oauth/revoke best-effort (2s timeout) before deleting the profile from disk.

Precedence:

  • URL: --url / BOXLITE_REST_URL > stored profile.
  • Credential: BOXLITE_API_KEY env > stored profile.

Stacked PRs

Base is PR 2 (feat/auth-rest-credential), not main. The diff shown here is CLI-only.

Test plan

  • cargo check -p boxlite-cli + cargo test -p boxlite-cli
  • boxlite auth login interactive flow against local boxlite serve reference server (PR 4)
  • echo "blk_test_xxx" | boxlite auth login --api-key-stdin
  • BOXLITE_API_KEY=blk_test_xxx boxlite list — env beats stored profile
  • boxlite auth logout — revoke + delete profile
  • Credentials file is 0600, parent dir 0700
  • No secret material printed in auth status or any debug output

Adds the auth subcommand family (login / logout / status) to
boxlite-cli with two co-equal paths matching how dev-workstation
products (Daytona, Gitpod, Codespaces, Vercel) ship auth:

- --api-key-stdin   paste an opaque key from the dashboard
- --web             browser-based device flow (recommended)

The interactive `boxlite auth login` (no flags) prompts the user to
pick between the two; --non-interactive emits the verification URL +
user_code as JSON for agent / IDE integrations.

Credentials at ~/.config/boxlite/credentials.toml (0600, parent 0700)
as a typed sum: [profiles.<name>.credential.api_key] XOR
[profiles.<name>.credential.oauth]. Sum-type-on-disk means the file
parser rejects mixed state, not a runtime warn!() (matches the
type-driven-over-data-driven rule).

Logout calls POST /v1/oauth/revoke best-effort (2s timeout) before
deleting the profile from disk. Failure to revoke is non-fatal — local
cleanup wins.

URL precedence:        --url / BOXLITE_REST_URL > stored profile.
Credential precedence: BOXLITE_API_KEY env     > stored profile.

New deps:
  rpassword 7        hidden TTY prompt for --api-key-stdin
  toml 0.8           credentials file format
  directories 5      XDG_CONFIG_HOME resolution
  reqwest 0.12       device flow polling (rustls-tls)
  webbrowser 1       open verification_uri_complete

Depends on the Rust SDK Credential enum (feat/auth-rest-credential).
Wire protocol on feat/auth-single-bearer-impl.
Server stubs on feat/auth-server-stubs.
@DorianZheng

Copy link
Copy Markdown
Member Author

Superseded by #532 — three logical commits (SDK + CLI + server) consolidated into one PR.

@DorianZheng DorianZheng deleted the feat/auth-cli-device-flow branch May 15, 2026 01:52
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.

1 participant