Skip to content

Revoke token server-side on logout#34

Open
lohnim wants to merge 9 commits intochris/authfrom
chris/cli-logout
Open

Revoke token server-side on logout#34
lohnim wants to merge 9 commits intochris/authfrom
chris/cli-logout

Conversation

@lohnim
Copy link
Collaborator

@lohnim lohnim commented Mar 25, 2026

Summary

  • alchemy auth logout now calls POST /api/cli/logout to invalidate the token in Redis before clearing the local config
  • Server-side revocation is best-effort — local cleanup always runs even if the server call fails
  • Stacked on Add alchemy auth command for browser-based login #30

How it works

  1. Read token from config
  2. Call POST /api/cli/logout with Authorization: Bearer <token> (best-effort)
  3. Clear auth_token and auth_token_expires_at from config

Test plan

  • alchemy auth logout clears local config
  • Token is revoked server-side (verify Redis key deleted)
  • Logout succeeds even if server is unreachable

lohnim and others added 8 commits March 24, 2026 11:50
Adds a new `alchemy auth` command that authenticates via browser
redirect. The CLI starts a local HTTP server on port 16424, opens
the browser to authchemy, and receives the auth token via callback.

New commands:
- `alchemy auth` / `alchemy auth login` - browser-based login
- `alchemy auth status` - show current auth state
- `alchemy auth logout` - clear saved token

Also updates config schema, onboarding, and error messages to
recognize auth_token as a valid authentication method.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of receiving the auth token directly in the callback URL,
the CLI now receives a short-lived code and exchanges it for a token
via a backchannel POST to /api/cli/token.

- waitForCallback() returns code + deferred response handlers
- exchangeCodeForToken() handles the backchannel exchange
- Browser sees success/error HTML only after exchange completes
- Add withAuthRetry() helper for automatic 401 re-authentication

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix login URL to use redirectUrl (not redirect) matching authchemy frontend
- Add resolveAuthToken() for reading auth token from config with expiry check
- adminClientFromFlags() falls back to auth token when no access key set

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use redirectUrl (not redirect) to match authchemy frontend
- Update token expiry from 24h to 90 days
- Add resolveAuthToken() with expiry check
- adminClientFromFlags() falls back to auth token

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CLI sends DEFAULT_EXPIRES_IN_SECONDS (90 days) on token exchange
- Use server-returned expiresAt instead of computing locally
- Remove hardcoded AUTH_TOKEN_TTL_MS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
alchemy auth now checks for an existing non-expired token first.
If found, prints status and exits. Use --force to re-authenticate.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
alchemy auth logout now calls POST /api/cli/logout to invalidate
the token in Redis before clearing it from the local config.
Server-side revocation is best-effort — local cleanup always runs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lohnim lohnim requested a review from a team as a code owner March 25, 2026 01:58
- Extract performBrowserLogin() to eliminate duplicate login flow
- Simplify auth-retry to use performBrowserLogin and CLIError codes
- Use resolveAuthToken() for expiry check in auth status (single source)
- Remove fragile string-based 401 detection, use CLIError.code instead
- Remove redundant config load in auth-retry
- Add coupling comment for 90-day TTL constant

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@lohnim lohnim force-pushed the chris/auth branch 2 times, most recently from 4fb8611 to f2676aa Compare March 25, 2026 14:46
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