snowflakedb / snowflakedb/snowflake-connector-python
SNOW-3557849: `AuthByOauthCredentials` does not send `audience` in token request body, breaking Auth0 compatibility
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 730
- Forks
- 574
- Avg merge
- 5h 45m
- Merged PRs (30d)
- 16
Description
Python version
Python 3.12.3
Operating system and processor architecture
macOS-26.5-arm64-arm-64bit
Installed packages
asn1crypto==1.5.1
cryptography==46.0.4
PyJWT==2.11.0
requests==2.32.5
snowflake-connector-python==4.2.0
snowflake-ml-python==1.39.0
snowflake-snowpark-python==1.45.0
urllib3==2.6.3
What did you do?
"""
Run against any Auth0 Machine-to-Machine app:
export AUTH0_CLIENT_ID=...
export AUTH0_CLIENT_SECRET=...
export AUTH0_TOKEN_URL=https://<tenant>.auth0.com/oauth/token
export AUTH0_AUDIENCE=<api-identifier>
"""
import base64, inspect, os, urllib3
from snowflake.connector.auth.oauth_credentials import AuthByOauthCredentials
# 1) Show the connector's source — `audience` is not in the request body.
print(inspect.getsource(AuthByOauthCredentials._request_tokens))
client_id = os.environ["AUTH0_CLIENT_ID"]
client_secret = os.environ["AUTH0_CLIENT_SECRET"]
token_url = os.environ["AUTH0_TOKEN_URL"]
audience = os.environ["AUTH0_AUDIENCE"]
# 2) Try the connector against a real Auth0 tenant.
auth = AuthByOauthCredentials(
application="repro",
client_id=client_id,
client_secret=client_secret,
token_request_url=token_url,
scope=audience,
)
try:
auth._request_tokens(conn=None, authenticator="oauth_client_credentials",
service_name=None, account="dummy", user="dummy")
except Exception as e:
print(f"FAILED: {type(e).__name__}: {e}")
# 3) Same request, with `audience` added — succeeds.
resp = urllib3.PoolManager().request_encode_body(
"POST", token_url,
headers={
"Authorization": "Basic " + base64.b64encode(f"{client_id}:{client_secret}".encode()).decode(),
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
},
encode_multipart=False,
fields={"grant_type": "client_credentials", "audience": audience},
)
print(f"Direct call status: {resp.status}")
print(f"Direct call body: {resp.data.decode()[:200]}")
What did you expect to see?
EXPECTED: AuthByOauthCredentials._request_tokens mints a token (step 2 of the repro succeeds).
ACTUAL: Step 2 fails with KeyError: 'access_token' because Auth0 returned
{"error":"access_denied","error_description":"..."} due to missing audience parameter.
Step 3 of the repro proves the same request succeeds when audience is included in the body.
ROOT CAUSE:
_request_tokens builds the request body with grant_type, scope, and conditionally client_id/client_secret,
but never includes audience. Auth0 requires audience to determine which API the token is for
(https://auth0.com/docs/api/authentication#client-credentials-flow). Confirmed the same gap exists on main:
https://github.com/snowflakedb/snowflake-connector-python/blob/main/src/snowflake/connector/auth/oauth_credentials.py
This makes oauth_client_credentials unusable with Auth0 as an IdP without monkey-patching the connector.
Other IdPs that route by scope (e.g. Okta) are unaffected.
SUGGESTED FIX:
Accept an optional audience constructor argument and include it in the request body when set:
fields = {"grant_type": "client_credentials", "scope": self._scope}
if self._audience is not None:
fields["audience"] = self._audience
if self._credentials_in_body:
fields["client_id"] = self._client_id
fields["client_secret"] = self._client_secret
return self._get_request_token_response(conn, fields)
Expose audience (e.g. oauth_audience) as a connection parameter so it can be set via Session.builder.configs(...) / connect(...).
Can you set logging to DEBUG and collect the logs
2026-05-20 20:19:52,874 - MainThread oauth_credentials.py:60 - _request_tokens() - DEBUG - authenticating with OAuth client credentials flow
2026-05-20 20:19:53,248 - MainThread connectionpool.py:544 - _make_request() - DEBUG - https://<REDACTED-TENANT>.us.auth0.com:443 "POST /oauth/token ****" 200 N
2026-05-20 20:19:53,248 - MainThread _oauth_base.py:397 - _get_request_token_response() - DEBUG - OAuth IdP response received, try to parse it
2026-05-20 20:19:53,248 - MainThread _oauth_base.py:406 - _get_request_token_response() - ERROR - oauth response invalid, does not contain 'access_token'
2026-05-20 20:19:53,248 - MainThread _oauth_base.py:407 - _get_request_token_response() - DEBUG - received the following response body when requesting oauth token:
MaskedMessageData(is_masked=False, masked_text='b\'{"error":"access_denied","error_description":"Client \\"<REDACTED_CLIENT_ID>\\" is not authorized to access resource server
\\"https://azure-latest.relationalai.com\\". You need to create a \\"client-grant\\" associated to this API."}\'', error_str=None)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.