snowflakedb / snowflakedb/snowflake-connector-python

SNOW-3560581: OAuth authorization code flow appends offline_access and causes invalid scope with Snowflake custom OAuth

Open
#2,885 3 comments 2 reactions 1 assignee View on GitHub

@sfc-gh-snow-drivers-warsaw-dl is already working on this.

Since May 22, 2026.

bug status-triage_done
Dominant language
Python
Stars
730
Forks
574
Avg merge
5h 45m
Merged PRs (30d)
16

Description

Summary

OAUTH_AUTHORIZATION_CODE with refresh-token reuse enabled appends offline_access to the authorization request scope. This causes Snowflake custom OAuth to fail with invalid_scope, because Snowflake custom OAuth documents refresh_token as the scope used to request offline access, not offline_access.

Environment

  • Snowflake CLI: 3.18.0
  • Bundled connector: snowflake-connector-python 4.5.0
  • OS: macOS
  • Authenticator: OAUTH_AUTHORIZATION_CODE
  • OAuth server: Snowflake custom OAuth security integration

Current behavior

With this connection config:

[connections.example]
account = "<account_identifier>"
user = "<user>"
warehouse = "<warehouse>"
role = "<role>"
authenticator = "OAUTH_AUTHORIZATION_CODE"

oauth_client_id = "<client id>"
oauth_client_secret = "<client secret>"
oauth_redirect_uri = "http://localhost:8001/snowflake/oauth-redirect"
oauth_scope = "refresh_token session:role:<ROLE>"

oauth_enable_refresh_tokens = true
oauth_enable_single_use_refresh_tokens = true
client_store_temporary_credential = true

The browser authorization request includes:

scope=refresh_token+session%3Arole%3A<ROLE>+offline_access

Snowflake then fails in the browser with:

Error occurred in authorization
The requested scope is invalid.

If I copy the failing request, remove the offline_access from scope string, it works as expected.

The security integration is configured to issue refresh tokens:

OAUTH_ISSUE_REFRESH_TOKENS = true
OAUTH_REFRESH_TOKEN_VALIDITY = <configured_validity>
OAUTH_SINGLE_USE_REFRESH_TOKENS_REQUIRED = true
OAUTH_ALLOW_NON_TLS_REDIRECT_URI = true

There does not appear to be a Snowflake OAuth custom-client integration parameter
that allows adding arbitrary accepted scopes such as offline_access.

Expected behavior

For Snowflake custom OAuth, enabling refresh-token reuse should not append
offline_access to the authorization request.

The connector should either:

  • rely on the user-provided refresh_token scope, or
  • append refresh_token when refresh-token support is enabled and the scope does
    not already include it, or
  • otherwise avoid adding an unsupported scope when the OAuth server is Snowflake
    custom OAuth.

Why this looks like a connector issue

Snowflake custom OAuth docs list these relevant valid authorization scopes:

  • refresh_token
  • session:role:
  • session:role-encoded:<URL_ENCODED_ROLE>

The docs describe refresh_token as the scope that requests offline access:

https://docs.snowflake.com/en/user-guide/oauth-custom

But current connector code appends offline_access whenever refresh-token support
is enabled:

if refresh_token_enabled:
    self._scope += (" " if self._scope else "") + "offline_access"

In my local install this is in:

snowflake/connector/auth/_oauth_base.py

and it's present on main

Impact

This prevents using Snowflake CLI / Python connector authorization-code OAuth with
Snowflake custom OAuth and refresh-token caching.

A minimal OAUTH_AUTHORIZATION_CODE config without refresh-token settings works,
but it opens the browser every time. Enabling refresh-token reuse causes the
invalid scope error before authentication.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.