Skip to content

Commit f8ec13a

Browse files
SNOW-2329031: revert exception type for Oauth authenticator (#2552)
1 parent 2ea207a commit f8ec13a

File tree

3 files changed

+83
-2
lines changed

3 files changed

+83
-2
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
- Added the `oauth_credentials_in_body` parameter supporting an option to send the oauth client credentials in the request body
1414
- Fix retry behavior for `ECONNRESET` error
1515
- Added an option to exclude `botocore` and `boto3` dependencies by setting `SNOWFLAKE_NO_BOTO` environment variable during installation
16+
- Revert changing exception type in case of token expired scenario for `Oauth` authenticator back to `DatabaseError`
1617
- Added support for pandas conversion for Day-time and Year-Month Interval types
1718

1819
- v3.17.4(September 22,2025)

src/snowflake/connector/auth/_auth.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
from ..token_cache import TokenCache, TokenKey, TokenType
5959
from ..version import VERSION
6060
from .no_auth import AuthNoAuth
61+
from .oauth import AuthByOAuth
6162

6263
if TYPE_CHECKING:
6364
from . import AuthByPlugin
@@ -373,7 +374,11 @@ def post_request_wrapper(self, url, headers, body) -> None:
373374
sqlstate=SQLSTATE_CONNECTION_WAS_NOT_ESTABLISHED,
374375
)
375376
)
376-
elif errno == OAUTH_ACCESS_TOKEN_EXPIRED_GS_CODE:
377+
elif (errno == OAUTH_ACCESS_TOKEN_EXPIRED_GS_CODE) and (
378+
# SNOW-2329031: OAuth v1.0 does not support token renewal,
379+
# for backward compatibility, we do not raise an exception here
380+
not isinstance(auth_instance, AuthByOAuth)
381+
):
377382
raise ReauthenticationRequest(
378383
ProgrammingError(
379384
msg=ret["message"],

test/unit/test_auth.py

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,24 @@
1818
from .mock_utils import mock_connection
1919

2020
try: # pragma: no cover
21-
from snowflake.connector.auth import Auth, AuthByDefault, AuthByPlugin
21+
from snowflake.connector.auth import (
22+
Auth,
23+
AuthByDefault,
24+
AuthByOAuth,
25+
AuthByOauthCode,
26+
AuthByOauthCredentials,
27+
AuthByPlugin,
28+
)
2229
except ImportError:
2330
from snowflake.connector.auth import Auth
2431
from snowflake.connector.auth_by_plugin import AuthByPlugin
2532
from snowflake.connector.auth_default import AuthByDefault
33+
from snowflake.connector.auth_oauth import AuthByOAuth
34+
from snowflake.connector.auth_oauth_code import AuthByOauthCode
35+
from snowflake.connector.auth_oauth_credentials import AuthByOauthCredentials
36+
37+
from snowflake.connector.errors import DatabaseError
38+
from snowflake.connector.network import ReauthenticationRequest
2639

2740

2841
def _init_rest(application, post_requset):
@@ -354,3 +367,65 @@ def test_auth_by_default_prepare_body_does_not_overwrite_client_environment_fiel
354367
for k in req_body_before["data"]["CLIENT_ENVIRONMENT"]
355368
]
356369
)
370+
371+
372+
def _mock_oauth_token_expired_rest_response(url, headers, body, **kwargs):
373+
"""Mock rest response for OAuth access token expired error."""
374+
from snowflake.connector.network import OAUTH_ACCESS_TOKEN_EXPIRED_GS_CODE
375+
376+
return {
377+
"success": False,
378+
"message": "OAuth access token expired",
379+
"code": OAUTH_ACCESS_TOKEN_EXPIRED_GS_CODE,
380+
"data": {},
381+
}
382+
383+
384+
@pytest.mark.skipolddriver
385+
@pytest.mark.parametrize(
386+
"auth_instance, expected_exc_type",
387+
[
388+
(AuthByOAuth("test_oauth_token"), DatabaseError),
389+
(
390+
AuthByOauthCode(
391+
application="testapp",
392+
client_id="test_client_id",
393+
client_secret="test_client_secret",
394+
authentication_url="https://auth.example.com",
395+
token_request_url="https://token.example.com",
396+
redirect_uri="http://localhost:8080",
397+
scope="session:role-any",
398+
host="testaccount.snowflakecomputing.com",
399+
),
400+
ReauthenticationRequest,
401+
),
402+
(
403+
AuthByOauthCredentials(
404+
application="testapp",
405+
client_id="test_client_id",
406+
client_secret="test_client_secret",
407+
token_request_url="https://token.example.com",
408+
scope="session:role-any",
409+
),
410+
ReauthenticationRequest,
411+
),
412+
],
413+
)
414+
def test_oauth_token_expired_error_handling(auth_instance, expected_exc_type):
415+
"""Test that OAuth authenticators handle token expiry errors differently.
416+
417+
- AuthByOAuth should raise DatabaseError (falls through to general error handling)
418+
- AuthByOauthCode and AuthByOauthCredentials should raise ProgrammingError (via ReauthenticationRequest)
419+
"""
420+
421+
def mock_errorhandler_always_raise(connection, cursor, error_class, error_value):
422+
raise error_class(**error_value)
423+
424+
application = "testapplication"
425+
account = "testaccount"
426+
user = "testuser"
427+
rest = _init_rest(application, _mock_oauth_token_expired_rest_response)
428+
rest._connection.errorhandler = mock_errorhandler_always_raise
429+
auth = Auth(rest)
430+
with pytest.raises(expected_exc_type):
431+
auth.authenticate(auth_instance, account, user)

0 commit comments

Comments
 (0)