Skip to content

feat(cli): add browser-assisted login and logout flow#1985

Open
maciej-flexcompute wants to merge 6 commits intomainfrom
maciej/codex/flow360-cli-login
Open

feat(cli): add browser-assisted login and logout flow#1985
maciej-flexcompute wants to merge 6 commits intomainfrom
maciej/codex/flow360-cli-login

Conversation

@maciej-flexcompute
Copy link
Copy Markdown
Collaborator

@maciej-flexcompute maciej-flexcompute commented Apr 13, 2026

Summary

  • add browser-assisted flow360 login with localhost callback handling
  • add explicit flow360 logout for removing stored credentials by profile/environment
  • align the CLI UX with a Codex-style login transcript, including immediate URL printing and success messages with the authenticated email
  • cross-link the browser confirmation UX implemented in flexcompute/flex#11046

Example

flow360 login --local
Starting local login server on http://127.0.0.1:56656/callback.
If your browser did not open, navigate to this URL to authenticate:

http://local.dev-simulation.cloud:3000/account/cli-login?callback_url=http%3A%2F%2F127.0.0.1%3A56656%2Fcallback&state=uTnSM6eG6XVDZ4C9s5d4DGcrWFmfnux8&profile=default&env=dev

Successfully logged in as maciej@flexcompute.com

Cross-PR

  • Browser confirmation / success UI: flexcompute/flex#11046

Notes

  • flow360 login now always prints the URL immediately, attempts browser-open best-effort, and keeps waiting for the callback.
  • Production URLs omit the redundant env=prod query parameter.
  • --local remains available as a hidden/internal flag for local UI development.

Verification

python -m pytest tests/v1/test_cli_login.py tests/v1/_test_cli.py -q

Result: 11 passed


Note

High Risk
Adds new CLI authentication flows that open a local callback server and write/remove API keys from disk, touching credential handling and introducing new network-facing behavior on localhost. Misconfigurations or edge cases could lead to auth failures or inadvertent key exposure despite added file-permission hardening.

Overview
Adds browser-assisted authentication to the CLI via new flow360 login/flow360 logout commands, including environment/profile selection, best-effort browser launching with printed fallback URL, and localhost callback handling to persist the returned API key.

Refactors configure to use centralized config helpers and consistent environment resolution, and extends user_config with read_user_config/write_user_config plus store_apikey/delete_apikey helpers that harden config directory/file permissions.

Updates tests to use temp config paths and adds coverage for the new login/logout flows and environment-specific API key storage.

Reviewed by Cursor Bugbot for commit 304f955. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread flow360/user_config.py Fixed
Comment thread flow360/cli/app.py
Comment thread flow360/user_config.py Fixed
Comment thread flow360/cli/auth.py
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 304f955. Configure here.

Comment thread flow360/cli/app.py

with open(config_file, "w", encoding="utf-8") as file_handler:
file_handler.write(toml.dumps(config))
write_user_config(config)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Premature config write creates partial state on disk

Low Severity

store_apikey internally does a full read-modify-write cycle (including flushing to disk), but configure then modifies the returned config further (for suppress_submit_warning / beta_features) and calls write_user_config again. When both --apikey and --suppress-submit-warning are passed, the first write from store_apikey creates an intermediate on-disk state missing the other config changes. The initial read_user_config() on line 68 is also discarded when store_apikey re-reads internally. A cleaner approach would separate the merge logic from the I/O so configure can batch all changes into a single write.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 304f955. Configure here.

Comment thread flow360/cli/auth.py

def _store_callback_params(self, params: Dict[str, str]):
self.server.callback_params = params
self.server.callback_event.set()
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Callback event fires once, spurious request blocks login

Low Severity

_store_callback_params unconditionally fires the one-shot callback_event for every request reaching /callback (GET or POST), regardless of whether the payload contains a valid state. Once set, wait_for_login wakes up and checks the params — if the state doesn't match, a LoginError is raised and the legitimate callback arriving later is permanently ignored. Any spurious or duplicate request to the endpoint causes an unrecoverable login failure.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 304f955. Configure here.

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.

2 participants