Skip to content

feat(cli): pre-fill the SSO verification code in the browser when the proxy allows it - #39428

Merged
mateo-berri merged 5 commits into
litellm_internal_stagingfrom
litellm_lite_login_prefill_code
Sep 3, 2026
Merged

mateo-berri merged 5 commits into
litellm_internal_stagingfrom
litellm_lite_login_prefill_code

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • lite login prints a verification code the user has to retype in the browser
  • The proxy can already pre-fill that page (allow_cli_sso_verification_uri_complete)
  • The CLI never used it, so turning the flag on changed nothing for lite login

How it solves it:

  • lite login treats verification_uri_complete in the /sso/cli/start reply as the proxy's opt-in
  • When it is there, the CLI opens /sso/key/generate with user_code added, so the page comes pre-filled
  • The terminal says the code is pre-filled in the browser and only needs checking
  • Flag off (the default) or an older proxy: byte-for-byte the same flow as today
  • The URL is still built from the --base-url the user gave, never the proxy's absolute URL

User Flow

Before: a developer whose proxy has the pre-fill flag on still has to copy the code from the terminal into the browser

  1. The proxy admin sets general_settings.allow_cli_sso_verification_uri_complete: true and restarts the proxy
  2. The developer runs lite login with LITELLM_PROXY_URL=https://litellm-domain
  3. The terminal prints Verification code: ABCD-EFGH and opens GET https://litellm-domain/sso/key/generate?source=litellm-cli&key=cli-... in the browser
  4. The browser bounces through the SSO provider (no password prompt, the browser is already signed in there) and lands on the "Complete CLI Login" page with an empty verification code box
  5. They copy ABCD-EFGH out of the terminal, paste it into the box, and click Continue
  6. The page says the login is complete and the terminal prints Login successful!

After: the same login opens the page with the code already in the box, so they only confirm it

  1. The proxy admin sets general_settings.allow_cli_sso_verification_uri_complete: true and restarts the proxy
  2. The developer runs lite login with LITELLM_PROXY_URL=https://litellm-domain
  3. The terminal prints Verification code: ABCD-EFGH (pre-filled in the browser, check it matches) and opens GET https://litellm-domain/sso/key/generate?source=litellm-cli&key=cli-...&user_code=ABCD-EFGH in the browser
  4. The browser bounces through the SSO provider as before and lands on the "Complete CLI Login" page, which now says "Confirm the verification code below to finish this login." with ABCD-EFGH already in the box
  5. They check the code matches the terminal and click Continue
  6. The page says the login is complete and the terminal prints Login successful!

With the flag off (the default), After is identical to Before: the URL carries no code and the page asks for it

Relevant issues

Linear ticket

Resolves LIT-6637

LIT-6636 (skip the code when the browser already holds an SSO session) is covered by lite login --pkce since v1.99.0, so it gets a docs pointer rather than a new mode: BerriAI/litellm-docs#1144

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • The handful of test files covering my change pass locally, e.g. uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*, make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

Shared setup: real Keycloak 26.3 as the OIDC IdP (realm litellm, user dev), Postgres and Redis in docker, every proxy booted with --num_workers 2 and litellm_settings.cache on Redis so the CLI login session is shared across both workers, EXPERIMENTAL_UI_LOGIN=True, GENERIC_* pointing at Keycloak, and this config:

model_list:
  - model_name: gpt-5.4-mini
    litellm_params:
      model: openai/gpt-5.4-mini
      api_key: os.environ/OPENAI_API_KEY
general_settings:
  allow_cli_sso_verification_uri_complete: true

BROWSER=<script that logs the URL> makes lite login write the URL it opens to a file instead of popping a window; that URL is then opened in a Playwright-driven Chromium, which signs in to Keycloak once and keeps that session for the rest. HOME points at a scratch directory with LITELLM_CLI_DISABLE_KEYRING=1 so each leg's credential lands in its own token.json instead of the machine keychain. Same steps, same IdP, same real lite TUI in tmux in every leg; only the commit the proxy and CLI run from (and, for the last leg, the config) differs

Before (632898b, the merge base)

  1. Start the real CLI in tmux (lite login, no flags) against the flag-on proxy booted from the merge base on port 38556
tmux send-keys -t lit6636 'env LITELLM_PROXY_URL=http://localhost:38556 BROWSER=$S/browser-logger.sh lite login; echo EXIT_CODE=$?' Enter
tmux capture-pane -t lit6636 -p
Opening browser to: http://localhost:38556/sso/key/generate?source=litellm-cli&key=cli-CMjl-s6aj2XyB17aLNTzOUCSFzjlxw3W
Please complete the SSO authentication in your browser...
Verification code: UZ75-KS6S
Session ID: cli-CMjl-s6aj2XyB17aLNTzOUCSFzjlxw3W
Waiting for authentication...
  1. Open that URL in the browser: it goes through Keycloak (GET /realms/litellm/protocol/openid-connect/auth?..., one sign-in) back to http://localhost:38556/sso/callback?..., which renders "Complete CLI Login" with "Enter the verification code shown in your terminal to finish this login." and an EMPTY "Verification code" box, even though the server flag is on. The user has to go back to the terminal, read UZ75-KS6S, and type it in
- heading "Complete CLI Login" [level=1]
- paragraph: Enter the verification code shown in your terminal to finish this login.
- textbox "Verification code" [active]
- button "Continue"
  1. Type UZ75-KS6S and press Enter: POST http://localhost:38556/sso/cli/complete/cli-CMjl-s6aj2XyB17aLNTzOUCSFzjlxw3W renders "CLI Authentication Successful" and the terminal continues
Login successful!
JWT Token: iuswZNo8az6157Ov8ZtO...
Keychain storage is off (LITELLM_CLI_DISABLE_KEYRING). Credential stored in <scratch HOME>/.litellm/token.json (owner-only).
You can now use the CLI without specifying --api-key
[... command list ...]
EXIT_CODE=0
  1. Real provider call through the logged-in CLI (interactive, same tmux window)
env LITELLM_PROXY_URL=http://localhost:38556 lite chat gpt-5.4-mini
You: Reply with exactly one word: pong
Assistant:
pong

After (62badd5; the tip 8442fb2 differs from it only by a staging merge that touches no CLI or SSO path)

  1. Same command against the flag-on proxy booted from the PR tip on port 39016. The URL now carries user_code, and the terminal says the code is pre-filled
tmux send-keys -t lit6636 'env LITELLM_PROXY_URL=http://localhost:39016 BROWSER=$S/browser-logger.sh lite login; echo EXIT_CODE=$?' Enter
tmux capture-pane -t lit6636 -p
Opening browser to: http://localhost:39016/sso/key/generate?source=litellm-cli&key=cli-eoKfSm1Mg3rKjEmP0V0EhiMOm0hfZQAx&user_code=C62G-MCF5
Please complete the SSO authentication in your browser...
Verification code: C62G-MCF5 (pre-filled in the browser, check it matches)
Session ID: cli-eoKfSm1Mg3rKjEmP0V0EhiMOm0hfZQAx
Waiting for authentication...
  1. Open that URL in the browser: same Keycloak hop (session reused, no sign-in form) back to http://localhost:39016/sso/callback?..., and the page now says "Confirm the verification code below to finish this login." with C62G-MCF5 already in the box, matching the terminal
- heading "Complete CLI Login" [level=1]
- paragraph: Confirm the verification code below to finish this login.
- textbox "Verification code" [active]: C62G-MCF5
- button "Continue"
  1. Click Continue without typing anything: POST http://localhost:39016/sso/cli/complete/cli-eoKfSm1Mg3rKjEmP0V0EhiMOm0hfZQAx renders "CLI Authentication Successful" and the terminal continues
Login successful!
JWT Token: psOFNMU0eIony0tahx7n...
Keychain storage is off (LITELLM_CLI_DISABLE_KEYRING). Credential stored in <scratch HOME>/.litellm/token.json (owner-only).
You can now use the CLI without specifying --api-key
[... command list ...]
EXIT_CODE=0
  1. Real provider call through the logged-in CLI (interactive, same tmux window)
env LITELLM_PROXY_URL=http://localhost:39016 lite chat gpt-5.4-mini
You: Reply with exactly one word: pong
Assistant:
pong

Flag off (62badd5, general_settings block removed)

  1. Same command against a third proxy booted from the PR tip on port 37283 with the default config (no allow_cli_sso_verification_uri_complete). The URL and the terminal are byte-for-byte the pre-PR shape: no user_code, no "(pre-filled ...)" hint
Opening browser to: http://localhost:37283/sso/key/generate?source=litellm-cli&key=cli-DysQBQcZKiSz7TcQx5hydbbufd9SFLLQ
Please complete the SSO authentication in your browser...
Verification code: FGF7-EUVF
Session ID: cli-DysQBQcZKiSz7TcQx5hydbbufd9SFLLQ
Waiting for authentication...
  1. The page is the pre-PR one too: "Enter the verification code shown in your terminal to finish this login." with an empty box
- heading "Complete CLI Login" [level=1]
- paragraph: Enter the verification code shown in your terminal to finish this login.
- textbox "Verification code" [active]
- button "Continue"
  1. Type FGF7-EUVF, press Enter, Login successful! and EXIT_CODE=0 in the terminal, then lite chat gpt-5.4-mini answers pong through this proxy as well

Caveats

  • The one-time code rides the URL into browser history
  • Flag flipped mid-login: empty box, code still printed
  • Before leg's first callback hit a cold-Keycloak timeout 500, retried
  • lite login --pkce is unaffected; it never shows a code

Verdict: PASS

Type

🆕 New Feature

Caveats (if any)

Low

  • Pre-fill needs both the proxy flag and this CLI; older CLIs keep opening the page without the code
  • With the flag on, the one-time code also lands in the browser's history via the URL
    • It is single-use, tied to that login session, and expires with it
  • If the proxy flag is turned off between lite login starting and the browser hop, the page shows an empty box while the terminal still says pre-filled; typing the printed code completes the login as before

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

Note

Low Risk
CLI-only SSO UX change with backward-compatible defaults; the verification code may appear in browser history when pre-fill is enabled.

Overview
lite login now honors the proxy’s optional verification_uri_complete field from /sso/cli/start. When that value is a string, the CLI treats it as opt-in to browser pre-fill: it opens /sso/key/generate with user_code on the query string (still using the user’s --base-url, not the proxy’s absolute URI) and tells the user the code is pre-filled and only needs to match.

If the field is missing or not a string, behavior stays the same—no user_code in the URL and the plain verification-code message. CliSsoStartData gains the optional field with ReadOnly typing; tests cover both paths plus regressions on the default flow.

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

@devin-ai-integration

Copy link
Copy Markdown
Contributor

PR #39428 labeled risk:high (touches CLI SSO/auth login flow — verification code added to the browser URL; 3 files, +90/-8). No enterprise label, so Linear routing skipped.

@greptile-apps

greptile-apps Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR updates standard CLI SSO login to honor the proxy’s optional prefill capability while retaining the configured CLI base URL.

  • Adds the verification code to the browser URL only when verification_uri_complete is advertised.
  • Updates terminal guidance for the prefilled flow.
  • Adds compatibility, URL-host safety, and response-type tests.
  • Tightens the type-discipline budgets after the typing improvements.

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains.

No blocking failure remains.

Important Files Changed

Filename Overview
litellm/proxy/client/cli/commands/auth.py Adds capability-gated verification-code prefill to the standard CLI SSO browser flow while preserving the legacy path when the field is absent.
tests/test_litellm/proxy/client/cli/test_auth_commands.py Adds coverage for prefill behavior, configured-host preservation, legacy responses, and non-string capability values.
type-discipline-budget.json Reduces several static-type violation budgets to reflect the improved TypedDict declarations.

Reviews (3): Last reviewed commit: "chore: merge litellm_internal_staging an..." | Re-trigger Greptile

@codspeed

codspeed Bot commented Sep 3, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_lite_login_prefill_code (8442fb2) with litellm_internal_staging (1e6a4d9)1

Open in CodSpeed

Footnotes

  1. No successful run was found on litellm_internal_staging (e1a7af7) during the generation of this report, so 1e6a4d9 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@mateo-berri mateo-berri added run-ci and removed run-ci labels Sep 3, 2026
@codecov

codecov Bot commented Sep 3, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 62badd5. Configure here.

…get conflict

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ mateo-berri
❌ yassin-berriai
You have signed the CLA already but the status is still pending? Let us recheck it.

@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 8442fb2. Configure here.

@mateo-berri
mateo-berri merged commit edbd4d1 into litellm_internal_staging Sep 3, 2026
85 checks passed
@mateo-berri
mateo-berri deleted the litellm_lite_login_prefill_code branch September 3, 2026 00:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:high Sensitive, broad, or high-risk change run-ci

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants