Skip to content

fix(kernel): Azure OAuth U2M — forward the in-house app/scopes uniformly on the kernel path - #449

Merged
eric-wang-1990 merged 5 commits into
mainfrom
eric-wang/kernel-azure-u2m-inhouse
Aug 22, 2026
Merged

fix(kernel): Azure OAuth U2M — forward the in-house app/scopes uniformly on the kernel path#449
eric-wang-1990 merged 5 commits into
mainfrom
eric-wang/kernel-azure-u2m-inhouse

Conversation

@eric-wang-1990

Copy link
Copy Markdown
Contributor

What

Fixes OAuth U2M on the kernel backend (WithUseKernel(true)) against Azure workspaces. Today an Azure U2M kernel connection opens a malformed AAD authorize URL (https://login.microsoftonline.com/{tenant}/v1/authorize?…) and the browser 404s. AWS/GCP U2M and the Thrift path are unaffected.

Root cause

The kernel runs a single, cloud-blind in-house U2M flow: it does OIDC discovery against {host}/oidc/.well-known/… and uses the discovered authorization_endpoint ({host}/oidc/v1/authorize) verbatim — it has no Azure branching (confirmed in the kernel: azure.rs states "Azure U2M has no dedicated flow").

resolveKernelAuth was handing that in-house flow the Thrift Azure values: the Entra-direct OAuth app id (U2MClientID()96eecda7… on Azure) and the …/user_impersonation scope (oauth.GetScopes). 96eecda7 is registered for Thrift's Entra-direct flow, so the workspace federation routes it to AAD — producing the broken URL. The in-house app (databricks-sql-connector) does not.

I verified this by curling the workspace discovery (returns the valid {host}/oidc/v1/authorize) and by comparing against the AWS/GCP inputs, which resolve to databricks-sql-connector + sql offline_access and work.

Fix (Go-side only)

resolveKernelAuth's U2M case now forwards the in-house app + scopes uniformly across every clouddatabricks-sql-connector + sql offline_access — instead of the cloud-inferred Azure Entra-direct app/scope:

case kernel.U2MCredentialsProvider:
    return kernel.Auth{Mode: kernel.AuthU2M, ClientID: u2mKernelClientID, Scopes: []string{"sql", "offline_access"}}, nil
  • AWS/GCP: no behavior changeU2MClientID() was already databricks-sql-connector and the scopes were already sql offline_access.
  • Azure: now uses the in-house flow the kernel actually runs (workspace-federated, which Azure Databricks workspaces support), matching how the Python and Node connectors thread Azure U2M to the kernel.
  • Thrift path is untouched — it keeps the cloud-specific values it needs.
  • No kernel change and no KERNEL_REV bump — the fix is entirely in the connector's kernel-auth mapping.

Testing

  • Updated the two U2M unit tests (kernel_config_test.go, kernel_auth_real_test.go) to assert the uniform in-house mapping; go test (kernel-auth units), gofmt, and go vet all clean.
  • E2E: ran U2M via WithUseKernel(true) against a live Azure workspace — round-trips SELECT 1 authenticated as the interactive user (previously 404'd at the AAD URL).

Not in scope: Azure M2M with an Entra service-principal secret — the Go driver has no such path (its WithClientCredentials exchanges at the Databricks workspace endpoint, which rejects Entra app secrets with invalid_client; verified). That would be new functionality (a new option → the kernel's azure-sp-m2m), tracked separately.

This pull request and its description were written by Isaac.

On the kernel backend (WithUseKernel(true)), Azure OAuth U2M failed: the
browser opened a malformed AAD authorize URL
(login.microsoftonline.com/{tenant}/v1/authorize) and 404'd.

Root cause: the kernel runs a single, cloud-blind in-house U2M flow — it does
OIDC discovery against {host}/oidc and uses the discovered authorize endpoint
verbatim; it has no Azure branching. resolveKernelAuth was forwarding the
cloud-inferred Azure Entra-direct app id (via U2MClientID) + user_impersonation
scope (via oauth.GetScopes). Handing those Entra-direct values to the in-house
flow made the workspace federation route the browser to AAD.

Fix (Go-side only): resolveKernelAuth's U2M case now forwards the in-house app
(databricks-sql-connector) + sql/offline_access scopes uniformly for every
cloud. AWS/GCP is a no-op (already those values); only Azure changes. The
Thrift path keeps the cloud-specific values it needs. No kernel change.

Verified end-to-end against a live Azure workspace (SELECT 1 authenticated as
the interactive user). Updated the two U2M unit tests to the uniform mapping.

Co-authored-by: Isaac
Signed-off-by: eric-wang-1990 <e.wang@databricks.com>
Copilot AI lite review requested due to automatic review settings August 21, 2026 17:07

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verdict: 1 Low

Looks good — the kernel-path U2M mapping is correctly made cloud-agnostic (in-house app + sql/offline_access), the now-unused oauth imports are removed, and both unit tests are updated to match. One low note: the hardcoded scope slice reverses the historical AWS/GCP ordering, so the "no behavior change on AWS/GCP" claim is true set-wise but not order-wise.

Comment thread kernel_config.go

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Fixes OAuth U2M when using the experimental SEA-via-kernel backend (WithUseKernel(true)) against Azure Databricks workspaces by making the kernel-path U2M auth descriptor cloud-agnostic (in-house client + scopes), avoiding Azure’s Entra-direct client/scope inference that breaks the kernel’s in-house flow.

Changes:

  • Update resolveKernelAuth to always forward the in-house U2M client (databricks-sql-connector) and scopes (sql, offline_access) on the kernel path.
  • Update U2M-related unit tests to assert the new uniform kernel-path mapping.
  • Document the behavior change in CHANGELOG.md.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
kernel_config.go Makes kernel-path U2M mapping uniform (fixed client id + scopes) to fix Azure U2M.
kernel_config_test.go Adjusts unit test expectations for the new kernel-path U2M mapping.
kernel_auth_real_test.go Updates “real authenticator” kernel-auth test assertions for the uniform mapping.
CHANGELOG.md Adds an Unreleased entry describing the Azure kernel U2M fix.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread kernel_config.go
Comment on lines 319 to +334
case kernel.U2MCredentialsProvider:
// Forward the SAME cloud-specific scopes the Thrift path requests via
// oauth.GetScopes (offline_access + sql on AWS/GCP, offline_access +
// <tenant>/user_impersonation on Azure), so both backends authorize against
// the built-in databricks-sql-connector client identically. Without this the
// kernel applied its own default set (all-apis + offline_access), which a
// workspace whose public client isn't granted all-apis rejects with
// access_denied. RedirectPort is still left zero (no user option; kernel
// default 8020). Passing nil to GetScopes yields the pure cloud-default set.
return kernel.Auth{Mode: kernel.AuthU2M, ClientID: a.U2MClientID(), Scopes: oauth.GetScopes(cfg.Host, nil)}, nil
// The kernel runs a single, cloud-agnostic in-house U2M flow: it does OIDC
// discovery against {host}/oidc and uses that authorize endpoint verbatim —
// it has NO Azure/cloud branching. That in-house workspace-federated flow
// works on every cloud including Azure (the workspace federates the browser
// login to Entra server-side). So forward the in-house app +
// `sql offline_access` scopes UNIFORMLY across clouds; do NOT forward the
// Azure Entra-direct app id / `user_impersonation` scope that
// a.U2MClientID() / oauth.GetScopes pick for an Azure host. Handing those
// Entra-direct values to the kernel's in-house flow makes the workspace
// federation route the browser to AAD and yields a broken authorize URL
// (login.microsoftonline.com/{tenant}/v1/authorize). The Thrift path keeps
// the cloud-specific values (it needs them); only this kernel-path mapping
// is uniform. On AWS/GCP this is a no-op — a.U2MClientID() is already
// databricks-sql-connector and the scopes are already sql+offline_access.
// RedirectPort stays zero (no user option; kernel default).

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.

I've updated all four stale doc/comment sites the reviewer identified to reflect the new cloud-agnostic kernel U2M behavior. All edits were comment-only and correctly describe that the kernel path now uses a fixed in-house client and scopes rather than forwarding the cloud-inferred Thrift-parity values.

One note flagged in my report: make test surfaced a pre-existing, unrelated failure in kernel_auth_real_test.go (a scope-ordering assertion against kernel_config.go — neither file touched by my comment-only edits), which the PR author should reconcile separately.

Pushed 4a00e71 (bundled with 4 other thread(s)).

Comment thread kernel_config_test.go Outdated
Comment thread kernel_config_test.go Outdated
Comment on lines 186 to 188
if a.Mode != kernel.AuthU2M || a.ClientID != "databricks-sql-connector" {
t.Errorf("auth = %+v, want mode=U2M clientID=databricks-sql-connector", a)
t.Errorf("auth = %+v, want mode=U2M clientID=databricks-sql-connector (in-house, cloud-agnostic)", a)
}

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.

Resolved the reviewer's comment with a code change. The test hard-coded "databricks-sql-connector" in the U2M assertion; I swapped it for the u2mKernelClientID constant introduced by this PR (it lives in the same dbsql package), in both the comparison and the error message. TestValidateKernelConfig passes and make lint reports 0 issues.

Pushed 4a00e71 (bundled with 4 other thread(s)).

Comment thread kernel_auth_real_test.go Outdated
@eric-wang-1990 eric-wang-1990 added the engineer-bot Maintainer-only: triggers the autonomous engineer-bot (bug-fix author on issues; follow-up on PRs) label Aug 21, 2026

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verdict: 1 Low

Looks good — a focused, well-justified fix that stops the kernel U2M path from forwarding Azure Entra-direct app/scopes to the kernel's cloud-blind in-house flow. Removed imports are clean, tests updated to match, and the AWS/GCP "no-op" claim holds (same scope set, order-insignificant). One low doc-consistency note: the kernel.Auth struct/field comments in internal/backend/kernel/auth.go still describe the old oauth.GetScopes/cloud-inferred behavior.

Comment thread kernel_config.go
Addresses:
  - #3832204630 at kernel_config.go:339
  - #3832207441 at kernel_config.go:334
  - #3832207487 at kernel_config_test.go:175
  - #3832207522 at kernel_config_test.go:188
  - #3832207599 at kernel_auth_real_test.go:76

Signed-off-by: peco-engineer-bot[bot] <peco-engineer-bot[bot]@users.noreply.github.com>

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verdict: 1 High

One high-severity issue: the new kernel_auth_real_test.go scope assertion (line 77) expects ["sql", "offline_access"], but resolveKernelAuth returns ["offline_access", "sql"] and the sibling kernel_config_test.go asserts that correct order — order-sensitive reflect.DeepEqual makes this test fail in CI. The production change itself (forwarding the in-house app + offline_access/sql uniformly on the kernel path) is sound and well-documented; the only defect is the reversed expected slice in the test.

Comment thread kernel_auth_real_test.go Outdated
Addresses:
  - #3832615584 at kernel_auth_real_test.go:77

Signed-off-by: peco-engineer-bot[bot] <peco-engineer-bot[bot]@users.noreply.github.com>

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ No issues identified by the review bot.

…e-u2m-inhouse

# Conflicts:
#	internal/backend/kernel/auth.go
#	kernel_config.go
#	kernel_config_test.go

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ No issues identified by the review bot.

@eric-wang-1990
eric-wang-1990 added this pull request to the merge queue Aug 22, 2026
Merged via the queue into main with commit be48c9e Aug 22, 2026
12 of 13 checks passed
@eric-wang-1990
eric-wang-1990 deleted the eric-wang/kernel-azure-u2m-inhouse branch August 22, 2026 01:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

engineer-bot Maintainer-only: triggers the autonomous engineer-bot (bug-fix author on issues; follow-up on PRs)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants