Skip to content

Support OAuth M2M (client credentials) on the default backend; reject unknown auth_type - #962

Open
aminghadersohi wants to merge 2 commits into
databricks:mainfrom
aminghadersohi:thrift-oauth-m2m
Open

aminghadersohi wants to merge 2 commits into
databricks:mainfrom
aminghadersohi:thrift-oauth-m2m

Conversation

@aminghadersohi

@aminghadersohi aminghadersohi commented Sep 26, 2026 •

Copy link
Copy Markdown

What type of PR is this?

  • Feature
  • Bug Fix

Description

Changes:

  • oauth_client_id + oauth_client_secret now authenticate a Databricks service principal on the default (Thrift) backend with OAuth M2M (client credentials against https://<host>/oidc/v1/token, scope all-apis). Tokens are refreshed when they expire. This is the credential shape the kernel backend (use_kernel=True) already accepts.
  • An auth_type the connector does not implement now raises ValueError. Before, it fell through to the interactive browser login.
  • Ambiguous combinations are rejected, as the kernel auth bridge does: oauth_client_secret with auth_type="databricks-oauth"/"azure-oauth", and oauth_client_secret with a custom credentials_provider. auth_type="azure-sp-m2m" keeps ignoring oauth_* values.
  • ClientCredentialsTokenSource ignores unknown fields in the token response. The workspace endpoint returns scope, and OAuthResponse(**payload) raised TypeError on it.
  • Docs: the connect() docstring and CONNECTION_PARAMETERS.md describe oauth_client_secret on Thrift, and oauth_redirect_port is documented as U2M-only. Changelog entries under # Unreleased.

Why: on the Thrift backend oauth_client_secret was silently ignored. oauth_client_id was then used as the client of an interactive U2M login: the connector opened a listener on 127.0.0.1:8020 and blocked until a browser redirect arrived. On a server that redirect never comes, so the process hangs. A mistyped auth_type hung the same way. For Databricks-managed service principals, the only M2M option was a credentials_provider callable, which applications that configure the connector from JSON or connection strings cannot pass.

How is this tested?

  • Unit tests

  • E2E Tests

  • Manually

  • N/A

  • Unit: tests/unit/test_auth.py covers the M2M request/header, the M2M argument errors (including credentials_provider + oauth_client_secret), and an unknown auth_type with no interactive fallback. The first three fail on main. At the first commit tests/unit passed (530 passed, 237 skipped; test_parameters.py excluded because it fails to collect in the local environment with and without this change). The follow-up commit (ambiguity check, docs) was not run locally; CI covers it.

  • Live, against a Databricks SQL warehouse on AWS with a service principal (scope all-apis, CAN USE on the warehouse):

    • connect(oauth_client_id=..., oauth_client_secret=...) runs queries, and current_user() is the service principal.
    • A wrong secret fails right away with RequestError ... 401 invalid_client.
    • auth_type="oauth-u2m" raises ValueError and opens no listener.
    • Before the OAuthResponse fix, the live connect failed with OAuthResponse.__init__() got an unexpected keyword argument 'scope'.

Related Tickets & Documents

None.

… unknown auth_type

oauth_client_id + oauth_client_secret now authenticate a Databricks
service principal with the client-credentials flow against the
workspace /oidc/v1/token endpoint (scope all-apis), with tokens
refreshed as they expire. Previously the Thrift backend ignored
oauth_client_secret and started an interactive browser login with the
service principal's client ID, which blocks indefinitely on a server.
This matches the credential shape the kernel backend already accepts.

An auth_type the connector does not implement now raises ValueError
instead of falling through to the interactive login, and a U2M
auth_type combined with oauth_client_secret is rejected as ambiguous.

The client-credentials token source also ignores extra fields in the
token response (the workspace endpoint returns 'scope'), which made
OAuthResponse(**payload) raise.
Copilot AI lite review requested due to automatic review settings September 26, 2026 12:10

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.

Copilot review overview

🟡 Changes recommended

Reject the ambiguous combination of credentials_provider and oauth_client_secret, and update the OAuth parameter documentation.

Review effort: Lite
Findings: 1 Low severity

Open (1)
What changed in this PR

Adds OAuth M2M client-credentials authentication for the default Thrift backend and rejects invalid or ambiguous authentication settings.

Changes:

  • Adds service-principal token acquisition and refresh.
  • Supports oauth_client_id and oauth_client_secret.
  • Validates unsupported authentication types and OAuth response fields.
  • Adds authentication tests.
File Description
tests/​unit/​test_auth.py Tests M2M authentication and validation.
src/​databricks/​sql/​client.py Documents OAuth configuration.
src/​databricks/​sql/​auth/​oauth.py Handles extra token-response fields.
src/​databricks/​sql/​auth/​common.py Stores the OAuth client secret.
src/​databricks/​sql/​auth/​authenticators.py Implements service-principal authentication.
src/​databricks/​sql/​auth/​auth.py Routes M2M credentials and validates auth types.

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

Comment thread src/databricks/sql/client.py Outdated
…tions

- credentials_provider together with oauth_client_secret now raises
  ValueError instead of silently using the provider, matching the kernel
  auth bridge. azure-sp-m2m keeps ignoring oauth_* values.
- The missing-oauth_client_id check no longer fires for azure-sp-m2m.
- oauth_redirect_port is documented as U2M-only; oauth_client_id and
  oauth_client_secret docs describe the M2M shape and its exclusions.
- CONNECTION_PARAMETERS.md: oauth_client_secret is supported on Thrift.
- Add changelog entries.

Signed-off-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>

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.

2 participants