Skip to content

Commit db2a10f

Browse files
SNOW-2466332: Do not require user when using OAuth flow (#2606)
1 parent 9c9be36 commit db2a10f

File tree

4 files changed

+93
-0
lines changed

4 files changed

+93
-0
lines changed

DESCRIPTION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Source code is also available at: https://github.com/snowflakedb/snowflake-conne
1313
- Fix compilation error when building from sources with libc++.
1414
- Pin lower versions of dependencies to oldest version without vulnerabilities.
1515
- Added no_proxy parameter for proxy configuration without using environmental variables.
16+
- Added OAUTH_AUTHORIZATION_CODE and OAUTH_CLIENT_CREDENTIALS to list of authenticators that don't require user to be set
1617

1718
- v4.0.0(October 09,2025)
1819
- Added support for checking certificates revocation using revocation lists (CRLs)

src/snowflake/connector/connection.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,8 @@ def __config(self, **kwargs):
16941694
WORKLOAD_IDENTITY_AUTHENTICATOR,
16951695
PROGRAMMATIC_ACCESS_TOKEN,
16961696
PAT_WITH_EXTERNAL_SESSION,
1697+
OAUTH_AUTHORIZATION_CODE,
1698+
OAUTH_CLIENT_CREDENTIALS,
16971699
}
16981700

16991701
if not (self._master_token and self._session_token):

test/unit/test_auth_oauth_auth_code.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,46 @@ def mock_request_tokens(self, **kwargs):
285285
assert isinstance(conn.auth_class, AuthByOauthCode)
286286

287287
conn.close()
288+
289+
290+
@pytest.mark.skipolddriver
291+
def test_oauth_authorization_code_allows_empty_user(monkeypatch, omit_oauth_urls_check):
292+
"""Test that OAUTH_AUTHORIZATION_CODE authenticator allows connection without user parameter."""
293+
import snowflake.connector
294+
295+
def mock_post_request(self, url, headers, json_body, **kwargs):
296+
return {
297+
"success": True,
298+
"message": None,
299+
"data": {
300+
"token": "TOKEN",
301+
"masterToken": "MASTER_TOKEN",
302+
"idToken": None,
303+
"parameters": [{"name": "SERVICE_NAME", "value": "FAKE_SERVICE_NAME"}],
304+
},
305+
}
306+
307+
monkeypatch.setattr(
308+
snowflake.connector.network.SnowflakeRestful, "_post_request", mock_post_request
309+
)
310+
311+
# Mock the OAuth authorization flow to avoid opening browser and starting HTTP server
312+
def mock_request_tokens(self, **kwargs):
313+
# Simulate successful token retrieval
314+
return ("mock_access_token", "mock_refresh_token")
315+
316+
monkeypatch.setattr(AuthByOauthCode, "_request_tokens", mock_request_tokens)
317+
318+
# Test connection without user parameter - should succeed
319+
conn = snowflake.connector.connect(
320+
account="testaccount",
321+
authenticator="OAUTH_AUTHORIZATION_CODE",
322+
oauth_client_id="test_client_id",
323+
oauth_client_secret="test_client_secret",
324+
)
325+
326+
# Verify that the connection was successful
327+
assert conn is not None
328+
assert isinstance(conn.auth_class, AuthByOauthCode)
329+
330+
conn.close()

test/unit/test_auth_oauth_credentials.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,53 @@ def mock_get_request_token_response(self, connection, fields):
137137
conn.close()
138138

139139

140+
@pytest.mark.skipolddriver
141+
def test_oauth_client_credentials_allows_empty_user(monkeypatch):
142+
"""Test that OAUTH_CLIENT_CREDENTIALS authenticator allows connection without user parameter."""
143+
import snowflake.connector
144+
145+
def mock_post_request(request, url, headers, json_body, **kwargs):
146+
return {
147+
"success": True,
148+
"message": None,
149+
"data": {
150+
"token": "TOKEN",
151+
"masterToken": "MASTER_TOKEN",
152+
"idToken": None,
153+
"parameters": [{"name": "SERVICE_NAME", "value": "FAKE_SERVICE_NAME"}],
154+
},
155+
}
156+
157+
monkeypatch.setattr(
158+
"snowflake.connector.network.SnowflakeRestful._post_request",
159+
mock_post_request,
160+
)
161+
162+
# Mock the OAuth client credentials token request to avoid making HTTP requests
163+
def mock_get_request_token_response(self, connection, fields):
164+
return ("mocked_token_response", None)
165+
166+
monkeypatch.setattr(
167+
AuthByOauthCredentials,
168+
"_get_request_token_response",
169+
mock_get_request_token_response,
170+
)
171+
172+
# Test connection without user parameter - should succeed
173+
conn = snowflake.connector.connect(
174+
account="testaccount",
175+
authenticator="OAUTH_CLIENT_CREDENTIALS",
176+
oauth_client_id="test_client_id",
177+
oauth_client_secret="test_client_secret",
178+
)
179+
180+
# Verify that the connection was successful
181+
assert conn is not None
182+
assert isinstance(conn.auth_class, AuthByOauthCredentials)
183+
184+
conn.close()
185+
186+
140187
def test_oauth_credentials_missing_client_id_raises_error():
141188
"""Test that missing client_id raises a ProgrammingError."""
142189
with pytest.raises(ProgrammingError) as excinfo:

0 commit comments

Comments
 (0)