Skip to content

Prompt for the host instead of failing when device code login has none - #7179

Open
maksim-zuev-db wants to merge 5 commits into
mainfrom
device-code-hide-create-profile
Open

maksim-zuev-db wants to merge 5 commits into
mainfrom
device-code-hide-create-profile

Conversation

@maksim-zuev-db

@maksim-zuev-db maksim-zuev-db commented Oct 26, 2026 •

Copy link
Copy Markdown
Member

Changes

databricks auth login --use-device-code now prompts for the workspace host when none is known, instead of failing with --use-device-code requires a workspace host. Without a terminal it fails with please specify a host using --host.

Device code login skips the discovery branch, so setHost resolves the host from the argument, --host, or the existing profile, and prompts for it otherwise. errDeviceCodeNeedsHost is removed because nothing returns it any more.

With --use-device-code, the login picker no longer lists profiles that device code login always rejects: profiles on a classic account host and profiles saved with resources. Profiles on unified hosts are still listed, because the discovery URL that identifies them is not saved on the profile. isDeviceCodeSupportedForHost replaces validateDeviceCodeHost, so the picker and the check after setHost share the host check. docs/device-code-login.md describes both changes.

Why

Discovery login opens a browser on this machine through login.databricks.com and learns the workspace host only after sign-in. Device code login is meant for machines without a browser, but when no host was known it still went into the discovery branch and failed. This broke two paths:

  • picking "Create a new profile" in the login picker, which asked for a profile name and then failed
  • databricks auth login --use-device-code --profile <new-profile>, which skips the picker

Picking a profile that device code login always rejects failed only after it was selected. If such a profile was the default, it was at the top of the picker with the cursor on it.

Tests

  • TestLoginDeviceCodeNewProfilePromptsForHost runs auth login --use-device-code --profile newprof through the termtest terminal emulator and checks that the CLI prompts for the host.
  • TestLoginDeviceCodePickerHidesUnsupportedProfiles runs the picker through termtest with a workspace, an account, and a resource-scoped profile, and checks that only the workspace profile is listed.
  • TestMatchDeviceCodeProfiles and TestIsDeviceCodeSupportedForHost cover the profile filter and the host check.
  • The device-code/unsupported-host acceptance test now expects the non-interactive host error for a new profile without a host.

Acceptance tests can't cover the prompts and the picker, because they only appear in an interactive terminal.

No changelog fragment: --use-device-code is still hidden behind DATABRICKS_CLI_DEVICE_CODE.

This pull request and its description were written by Isaac.

@maksim-zuev-db
maksim-zuev-db marked this pull request as ready for review October 26, 2026 09:42
@maksim-zuev-db
maksim-zuev-db requested review from a team as code owners October 26, 2026 09:42
@maksim-zuev-db
maksim-zuev-db requested review from chrisst and simonfaltum and removed request for chrisst October 26, 2026 09:42
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: ffcd8b0

Run: 40326085620

Env 🔄​flaky ✅​pass 🙈​skip Time
🔄​ aws linux-2core-8gb 2 279 16 11:44
✅​ aws-windows-latest-4core-16gb 283 14 7:06
✅​ azure linux-2core-8gb 280 16 11:42
✅​ azure-windows-latest-4core-16gb 282 14 6:45
✅​ gcp linux-2core-8gb 281 16 12:06
✅​ gcp-windows-latest-4core-16gb 283 14 8:10
Test Name aws linux-2core-8gb
🔄​ TestFilerWorkspaceNotebook 🔄​f
🔄​ TestFilerWorkspaceNotebook/scalaJupyterNb.ipynb 🔄​f
Top 13 slowest tests (at least 2 minutes):
duration env testname
4:34 gcp-windows-latest-4core-16gb TestAccept
4:03 aws-windows-latest-4core-16gb TestAccept
3:57 azure linux-2core-8gb TestAccept
3:45 aws linux-2core-8gb TestAccept
3:44 gcp linux-2core-8gb TestAccept
3:28 gcp linux-2core-8gb TestFilerWorkspaceFilesExtensionsRead
3:03 azure-windows-latest-4core-16gb TestFilerWorkspaceFilesExtensionsRead
3:03 azure-windows-latest-4core-16gb TestAccept
3:03 azure linux-2core-8gb TestFilerWorkspaceFilesExtensionsRead
2:21 gcp linux-2core-8gb TestFilerWorkspaceFilesExtensionsReadDir
2:16 azure linux-2core-8gb TestFilerWorkspaceFilesExtensionsReadDir
2:13 gcp linux-2core-8gb TestFilerRecursiveDelete/workspace_files
2:03 aws-windows-latest-4core-16gb TestFilerWorkspaceFilesExtensionsDelete

@simonfaltum simonfaltum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for picking this up! Left a few comments inline. The main ones:

  • The picker still lists profiles that device code login always rejects (L241).
  • The new test touches the real ~/.databricks/token-cache.json (L225).
  • I think skipping discovery for device code would fix this more generally and remove the need for the picker special case (L245).

The rest are small suggestions.

One more that can't go inline since the file isn't in this PR: step 1 in docs/device-code-login.md says the host comes from an argument, --host, or an existing profile. It doesn't mention the picker, so someone running databricks auth login --use-device-code with no arguments won't find out why "Create a new profile" is missing. Might be worth a line there.

Comment thread cmd/auth/login.go Outdated
Comment on lines +241 to +242
Label: label,
Default: currentDefault,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With --use-device-code the picker still lists every profile (MatchAllProfiles), including ones device code login always rejects:

  • account hosts fail with --use-device-code is only supported for workspace hosts (after host discovery, which can take up to 5s)
  • profiles without a host fail with errDeviceCodeNeedsHost
  • profiles saved with resources fail with cannot be used with profile ... scoped to resources

The default profile is also moved to the top with the cursor on it, so if the default is an account profile, pressing Enter goes straight into one of these errors.

I think we can improve the UX by marking those profiles, i.e. append ** to the name and add a line like "Profiles marked with ** are not supported with --use-device-code yet". Account hosts, missing hosts and resources can all be checked from the profile itself. Unified hosts are harder since that check uses the discovery URL, which isn't stored on the profile.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I filtered out profiles which are guaranteed to fail now. It seems OK to me for now, as we expect all hosts to be supported before the feature becomes stable

Comment thread cmd/auth/login.go Outdated
Comment thread cmd/auth/login.go Outdated
Comment thread cmd/auth/login_device_code_test.go Outdated
Comment thread cmd/auth/login_device_code_test.go Outdated
Comment thread cmd/auth/login_device_code_test.go Outdated
Comment thread cmd/auth/login_device_code_test.go Outdated
Comment thread cmd/auth/profile_picker_test.go Outdated
Comment thread cmd/auth/profile_picker.go Outdated
Comment thread cmd/auth/switch.go Outdated
@maksim-zuev-db
maksim-zuev-db force-pushed the device-code-hide-create-profile branch from f142176 to 7d59c27 Compare October 26, 2026 11:58
Discovery login opens a browser on this machine and learns the workspace
host only after sign-in. Device code login is meant for machines without
a browser, but when no host was known it still went into the discovery
branch and failed with "--use-device-code requires a workspace host".
This broke "Create a new profile" in the login picker and "auth login
--use-device-code --profile <new-profile>".

Skip discovery for device code login so setHost resolves the host. It
prompts for it when interactive and asks for --host otherwise.

Co-authored-by: Isaac <no-reply@databricks.com>
@maksim-zuev-db
maksim-zuev-db force-pushed the device-code-hide-create-profile branch from 7d59c27 to 12f1366 Compare October 26, 2026 12:03
@maksim-zuev-db maksim-zuev-db changed the title Hide "Create a new profile" from the login picker with --use-device-code Prompt for the host instead of failing when device code login has none Oct 26, 2026
@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Commit: ffcd8b0d0 | Workflow run

Regression test report

Selected 1 changed tests (limit=20, 0 not selected)

1 tests: regression=1 unreleased=0 coverage=0 failing=0

test branch main (c6bb214) latest (v1.22.1)
TestAccept/cmd/auth/login/device-code/unsupported-host ✅ ❌ ❌
TestAccept/cmd/auth/login/device-code/unsupported-host: branch ✅ | main (c6bb214) ❌ | latest (v1.22.1) ❌

main (c6bb214):

acceptance_test.go:1311: Diff:
        --- cmd/auth/login/device-code/unsupported-host/output.txt
        +++ /tmp/TestAcceptcmdauthlogindevice-codeunsupported-host3648845438/002/output.txt
        @@ -2,7 +2,7 @@
         === No host
         
         >>> musterr [CLI] auth login --profile new-profile --use-device-code
        -Error: the command is being run in a non-interactive environment, please specify a host using --host
        +Error: --use-device-code requires a workspace host. Pass it as an argument or with --host
         
         === Account host
         
        
FAIL

latest (v1.22.1):

acceptance_test.go:1311: Diff:
        --- cmd/auth/login/device-code/unsupported-host/output.txt
        +++ /tmp/TestAcceptcmdauthlogindevice-codeunsupported-host260196695/002/output.txt
        @@ -2,30 +2,170 @@
         === No host
         
         >>> musterr [CLI] auth login --profile new-profile --use-device-code
        -Error: the command is being run in a non-interactive environment, please specify a host using --host
        +Error: unknown flag: --use-device-code
         
        +Usage:
        +  databricks auth login [PROFILE] [flags]
        +
        +Flags:
        +      --client-id string       OAuth client ID to use for U2M authentication
        +      --configure-cluster      Prompts to configure cluster
        +      --configure-serverless   Prompts to configure serverless
        +  -h, --help                   help for login
        +      --resource stringArray   RFC 8707 resource indicator to scope the login to (repeatable). Requires --host.
        +      --scopes string          Comma-separated list of OAuth scopes to request (defaults to 'all-apis')
        +      --skip-workspace         Skip workspace selection for account-level access
        +      --timeout duration       Timeout for completing login challenge in the browser (default 1h0m0s)
        +
        +Global Flags:
        +      --account-id string     Databricks Account ID
        +      --debug                 enable debug logging
        +      --host string           Databricks Host
        +  -o, --output type           output type: text or json (default text)
        +  -p, --profile string        ~/.databrickscfg profile
        +  -t, --target string         bundle target to use (if applicable)
        +      --workspace-id string   Databricks Workspace ID
        +
        +
         === Account host
         
         >>> musterr [CLI] auth login --host https://accounts.cloud.databricks.test --profile test --use-device-code
        -Warn: [hostmetadata] failed to fetch host metadata for https://accounts.cloud.databricks.test, will skip for 1m0s
        -Error: --use-device-code is only supported for workspace hosts
        +Error: unknown flag: --use-device-code
         
        +Usage:
        +  databricks auth login [PROFILE] [flags]
        +
        +Flags:
        +      --client-id string       OAuth client ID to use for U2M authentication
        +      --configure-cluster      Prompts to configure cluster
        +      --configure-serverless   Prompts to configure serverless
        +  -h, --help                   help for login
        +      --resource stringArray   RFC 8707 resource indicator to scope the login to (repeatable). Requires --host.
        +      --scopes string          Comma-separated list of OAuth scopes to request (defaults to 'all-apis')
        +      --skip-workspace         Skip workspace selection for account-level access
        +      --timeout duration       Timeout for completing login challenge in the browser (default 1h0m0s)
        +
        +Global Flags:
        +      --account-id string     Databricks Account ID
        +      --debug                 enable debug logging
        +      --host string           Databricks Host
        +  -o, --output type           output type: text or json (default text)
        +  -p, --profile string        ~/.databrickscfg profile
        +  -t, --target string         bundle target to use (if applicable)
        +      --workspace-id string   Databricks Workspace ID
        +
        +
         >>> musterr [CLI] auth login --profile account --use-device-code
        -Error: --use-device-code is only supported for workspace hosts
        +Error: unknown flag: --use-device-code
         
        +Usage:
        +  databricks auth login [PROFILE] [flags]
        +
        +Flags:
        +      --client-id string       OAuth client ID to use for U2M authentication
        +      --configure-cluster      Prompts to configure cluster
        +      --configure-serverless   Prompts to configure serverless
        +  -h, --help                   help for login
        +      --resource stringArray   RFC 8707 resource indicator to scope the login to (repeatable). Requires --host.
        +      --scopes string          Comma-separated list of OAuth scopes to request (defaults to 'all-apis')
        +      --skip-workspace         Skip workspace selection for account-level access
        +      --timeout duration       Timeout for completing login challenge in the browser (default 1h0m0s)
        +
        +Global Flags:
        +      --account-id string     Databricks Account ID
        +      --debug                 enable debug logging
        +      --host string           Databricks Host
        +  -o, --output type           output type: text or json (default text)
        +  -p, --profile string        ~/.databrickscfg profile
        +  -t, --target string         bundle target to use (if applicable)
        +      --workspace-id string   Databricks Workspace ID
        +
        +
         === Unified host
         
         >>> DATABRICKS_DISCOVERY_URL=[DATABRICKS_URL]/oidc/accounts/spog-acct-123/.well-known/oauth-authorization-server musterr [CLI] auth login --host [DATABRICKS_URL] --use-device-code
        -Error: --use-device-code is only supported for workspace hosts
        +Error: unknown flag: --use-device-code
         
        +Usage:
        +  databricks auth login [PROFILE] [flags]
        +
        +Flags:
        +      --client-id string       OAuth client ID to use for U2M authentication
        +      --configure-cluster      Prompts to configure cluster
        +      --configure-serverless   Prompts to configure serverless
        +  -h, --help                   help for login
        +      --resource stringArray   RFC 8707 resource indicator to scope the login to (repeatable). Requires --host.
        +      --scopes string          Comma-separated list of OAuth scopes to request (defaults to 'all-apis')
        +      --skip-workspace         Skip workspace selection for account-level access
        +      --timeout duration       Timeout for completing login challenge in the browser (default 1h0m0s)
        +
        +Global Flags:
        +      --account-id string     Databricks Account ID
        +      --debug                 enable debug logging
        +      --host string           Databricks Host
        +  -o, --output type           output type: text or json (default text)
        +  -p, --profile string        ~/.databrickscfg profile
        +  -t, --target string         bundle target to use (if applicable)
        +      --workspace-id string   Databricks Workspace ID
        +
        +
         === Workspace without device code login
         
         >>> musterr [CLI] auth login --host [DATABRICKS_URL] --profile test --use-device-code
        -Error: device code login is not enabled for this workspace
        +Error: unknown flag: --use-device-code
         
        +Usage:
        +  databricks auth login [PROFILE] [flags]
        +
        +Flags:
        +      --client-id string       OAuth client ID to use for U2M authentication
        +      --configure-cluster      Prompts to configure cluster
        +      --configure-serverless   Prompts to configure serverless
        +  -h, --help                   help for login
        +      --resource stringArray   RFC 8707 resource indicator to scope the login to (repeatable). Requires --host.
        +      --scopes string          Comma-separated list of OAuth scopes to request (defaults to 'all-apis')
        +      --skip-workspace         Skip workspace selection for account-level access
        +      --timeout duration       Timeout for completing login challenge in the browser (default 1h0m0s)
        +
        +Global Flags:
        +      --account-id string     Databricks Account ID
        +      --debug                 enable debug logging
        +      --host string           Databricks Host
        +  -o, --output type           output type: text or json (default text)
        +  -p, --profile string        ~/.databrickscfg profile
        +  -t, --target string         bundle target to use (if applicable)
        +      --workspace-id string   Databricks Workspace ID
        +
        +
         >>> musterr [CLI] auth login --profile workspace --use-device-code
        -Error: device code login is not enabled for this workspace
        +Error: unknown flag: --use-device-code
         
        +Usage:
        +  databricks auth login [PROFILE] [flags]
        +
        +Flags:
        +      --client-id string       OAuth client ID to use for U2M authentication
        +      --configure-cluster      Prompts to configure cluster
        +      --configure-serverless   Prompts to configure serverless
        +  -h, --help                   help for login
        +      --resource stringArray   RFC 8707 resource indicator to scope the login to (repeatable). Requires --host.
        +      --scopes string          Comma-separated list of OAuth scopes to request (defaults to 'all-apis')
        +      --skip-workspace         Skip workspace selection for account-level access
        +      --timeout duration       Timeout for completing login challenge in the browser (default 1h0m0s)
        +
        +Global Flags:
        +      --account-id string     Databricks Account ID
        +      --debug                 enable debug logging
        +      --host string           Databricks Host
        +  -o, --output type           output type: text or json (default text)
        +  -p, --profile string        ~/.databrickscfg profile
        +  -t, --target string         bundle target to use (if applicable)
        +      --workspace-id string   Databricks Workspace ID
        +
        +
         === Device authorization requests
         
         >>> print_requests.py //oidc/v1/device/auth
        +File [OUTPUT_DIR]/out.requests.txt not found
        +
        +Exit code: 1
        
FAIL

maksim-zuev-db and others added 4 commits October 26, 2026 12:31
On Windows, bubbletea cannot cancel its read from the test's stdin pipe,
so after the profile picker quits its reader swallows the input typed for
the profile name prompt, and the test timed out waiting for the host
prompt. Passing --profile makes the host prompt the only prompt while
still covering the skipped discovery branch.

Co-authored-by: Isaac <no-reply@databricks.com>
With --use-device-code, the login picker leaves out profiles on a classic
account host and profiles saved with resources, which device code login
always rejects. Profiles on unified hosts are still listed, because the
discovery URL that identifies them is not saved on the profile.

isDeviceCodeSupportedForHost replaces validateDeviceCodeHost so the
picker and the check after setHost share the host check.

Co-authored-by: Isaac <no-reply@databricks.com>
Share the setup of the two termtest tests in startDeviceCodeLogin.

Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>

@simonfaltum simonfaltum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks, the discovery change looks good and the earlier comments are all covered. One issue with an empty host answer below, plus an optional suggestion.

Comment thread cmd/auth/login.go
}
// an account ID for account and unified hosts. A workspace without
// device code login enabled is rejected later by DeviceCodeChallenge.
if useDeviceCode && !isDeviceCodeSupportedForHost(authArguments.Host, authArguments.DiscoveryURL) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

With discovery skipped, setHost now prompts for the host, but promptForHost accepts an empty answer. If the user presses Enter at "Databricks host", Host stays "" and isDeviceCodeSupportedForHost("", "") returns true, so login continues:

  • ToOAuthArgument resolves the config with the ConfigAttributes loader, which reads env vars. With DATABRICKS_HOST set, login runs against that host (this workspace-only check never sees it), and the profile is saved without a host key.
  • Without DATABRICKS_HOST, it fails later with host must start with 'https://': .

Picker → "Enter a host URL manually" → empty input hits the same path, and the user gets the profile name prompt followed by a second host prompt. Before this PR, errDeviceCodeNeedsHost caught both cases.

I think the simplest fix is to reject empty input in promptForHost (cmdio.PromptOptions has Validate), or an empty host check here for device code.

Comment thread cmd/auth/login.go
Comment on lines +228 to +230
// (Create a new profile) and a manual host URL. Device code login skips
// discovery, so for it "Create a new profile" prompts for the host after
// the profile name.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Optional, and mostly unrelated to this PR: after "Create a new profile" no host is known yet, so the name prompt suggests DEFAULT, and pressing Enter loads the existing DEFAULT profile if there is one. If that's an account profile the picker just hid, the user gets --use-device-code is only supported for workspace hosts for a profile they didn't pick. If it's a workspace profile, login reuses its host instead of prompting as this comment describes. Browser login reuses DEFAULT the same way, so fine to leave for a follow-up.

This branch has not been deployed

No deployments
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.

3 participants