[BUG] Can't specify OAuth scope for Snowflake MCP

Status Fixed / completed
Reported on v2.1.81
Maintainer reply None cached
Activity 13 comments · opened Apr 2, 2026 · closed Apr 15, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When using a Snowflake-managed MCP server with OAuth authentication, Claude Code requests the scope session:role:all by default. However, in my company, the Snowflake OAuth is configured to disallow this, and instead, requires a specific Snowlfake role called out in that request (e.g. session:role:ANALYST_ROLE).

What Should Happen?

Users should be able to specify a custom OAuth scope in the MCP server configuration, e.g.:

{
  "mcpServers": {
    "snowflake": {
      "type": "http",
      "url": "https://...",
      "oauth": {
        "scope": "session:role:ANALYST_ROLE"
      }
    }
  }
}

Error Messages/Logs

Steps to Reproduce

I added the Snowflake-managed MCP like this:

MCP_CLIENT_SECRET="..." \
claude mcp add --transport http --scope user \
  --client-id "..." \
  --client-secret \
  --callback-port 6274 \
  snowflake \
  https://[account].snowflakecomputing.com/api/v2/databases/[db]/schemas/[schema]/mcp-servers/[mcp-server]

Snowflake OAuth has been configured like this:

CREATE OR REPLACE SECURITY INTEGRATION oauth_claude_code_localhost
  TYPE = OAUTH
  OAUTH_CLIENT = CUSTOM
  ENABLED = TRUE
  OAUTH_CLIENT_TYPE = 'CONFIDENTIAL'
  OAUTH_REDIRECT_URI = 'http://localhost:6274/callback'
  OAUTH_ALLOW_NON_TLS_REDIRECT_URI = TRUE  // required for non-TLS localhost redirect endpoint
  OAUTH_USE_SECONDARY_ROLES = NONE  // this disables session:role:all
  PRE_AUTHORIZED_ROLES_LIST = ([roles allowed for MCP use, most users have multiple roles])
  BLOCKED_ROLES_LIST = ('SYSADMIN', 'USERADMIN', [a bunch of roles]);

When attempting to authenticate this Snowflake-managed MCP Server with OAuth via /mcp interface, Claude Code opens this URL:

https://[ACCOUNT-NAME].snowflakecomputing.com/oauth/authorize?response_type=code&client_id=...&code_challenge=...&code_challenge_method=S256&redirect_uri=http%3A%2F%2Flocalhost%3A6274%2Fcallback&state=...&scope=session%3Arole%3Aall&resource=...

Since this scope is disabled from Snowflake side, I get the following error:

The role ALL requested has been explicitly blocked for use with this application by an administrator. Please try logging in with a different role, or contact your administrator.

Manually editing the authorization URL during the OAuth flow to replace session:role:all with session:role:<specific_role> results in successful authentication, confirming this is purely a scope configuration issue.

https://[ACCOUNT-NAME].snowflakecomputing.com/oauth/authorize?response_type=code&client_id=...&code_challenge=...&code_challenge_method=S256&redirect_uri=http%3A%2F%2Flocalhost%3A6274%2Fcallback&state=...&scope=session%3Arole%3AANALYST_ROLE&resource=...

Claude Model

Sonnet (default)

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.81

Platform

AWS Bedrock

Operating System

macOS

Terminal/Shell

iTerm2

Additional Information

Why this matters: Least privilege principle. Without this scope configurability, Claude Code can't use MCPs in security-conscious environments.

View original on GitHub ↗

13 Comments

github-actions[bot] · 5 months ago

Found 2 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/7744
  2. https://github.com/anthropics/claude-code/issues/4540

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

davidlee-ca · 5 months ago

I don't see how #7744 is a duplicate.

Snowflake OAuth doesn't support dynamic client registration so #4540 isn't quite a duplicate. There's a recent post suggesting the addition of a scope key under oauth. I think that's more incidental than not. So, I believe my issue is not a duplicate.

davidlee-ca · 4 months ago

To add to this issue -- Snowflake misrepresents supported scopes of their MCP server in the resource metadata.

% curl -i https://[account].snowflakecomputing.com/api/v2/databases/[db]/schemas/[schema]/mcp-servers/[mcpserverobject]

HTTP/2 401
date: Mon, 06 Apr 2026 13:48:03 GMT
www-authenticate: Bearer resource_metadata="https://[account].snowflakecomputing.com/.well-known/oauth-protected-resource/api/v2/databases/[db]/schemas/[schema]/mcp-servers/[mcpserverobject]"
x-snowflake-request-id: [uuid]
content-type: application/json
content-length: 0
server: SF-LB
x-envoy-upstream-service-time: 6
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
expect-ct: enforce, max-age=3600
strict-transport-security: max-age=31536000
x-snowflake-fe-instance: -
x-snowflake-fe-config: v20260331.2.0-c2e20a542.1774996792.va3.1775483247765
x-frame-options: deny
x-envoy-attempt-count: 1

The resource metadata shows the wrong, possibly hard-coded, supported scope. Yes, Snowflake should fix this, but Claude Code should still also allow an override:

% curl https://[account].snowflakecomputing.com/.well-known/oauth-protected-resource/api/v2/databases/[db]/schemas/[schema]/mcp-servers/[mcpserverobject]
{
  "resource" : "https://[account].snowflakecomputing.com/api/v2/databases/[db]/schemas/[schema]/mcp-servers/[mcpserverobject]",
  "authorization_servers" : [ "https://[account].snowflakecomputing.com/oauth" ],
  "scopes_supported" : [ "session:role:all" ],
  "bearer_methods_supported" : [ "header" ],
  "resource_name" : "[db].[schema].[mcpserverobject]",
  "resource_documentation" : "https://docs.snowflake.com/en/developer-guide/snowflake-rest-api/snowflake-rest-api"
}

BTW, their noted authorization server doesn't offer scopes_supported:

curl https://[account].snowflakecomputing.com/.well-known/oauth-authorization-server/oauth

{
  "authorization_endpoint": "https://[account].snowflakecomputing.com/oauth/authorize",
  "token_endpoint": "https://[account].snowflakecomputing.com/oauth/token-request", 
  "issuer": "https://[account].snowflakecomputing.com/oauth",
  "response_types_supported": ["code"], 
  "response_modes_supported": ["query"], 
  "grant_types_supported": ["authorization_code", "refresh_token", "urn:ietf:params:oauth:grant-type:token-exchange"], 
  "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "private_key_jwt"], 
  "request_uri_parameter_supported": true, 
  "subject_types_supported": ["public"]
}

Claude Code documentation claims that the OAuth metadata endpoints can be overridden. From this snippet, I thought it'd override both the Protected Resource Metadata and the authorization server metadata:

If your MCP server’s standard OAuth metadata endpoints return errors but the server exposes a working OIDC endpoint, you can point Claude Code at a specific metadata URL to bypass the default discovery chain. By default, Claude Code first checks RFC 9728 Protected Resource Metadata at /.well-known/oauth-protected-resource, then falls back to RFC 8414 authorization server metadata at /.well-known/oauth-authorization-server.

I've tried adding:

  • "scopes_supported": ["session:role:SPECIFIC_ROLE"]
  • everything in the resource metadata

to the auth server metadata override (authServerMetadataUrl), but it gets ignored, according to the following snippet in the debug log:

2026-04-06T17:59:44.933Z [DEBUG] MCP server "snowflake-local": Cleared stored tokens
2026-04-06T17:59:44.934Z [DEBUG] MCP server "snowflake-local": Using redirect port: 6274 (from config)
2026-04-06T17:59:44.950Z [DEBUG] MCP server "snowflake-local": Fetched OAuth metadata with scope: session:role:SPECIFIC_ROLE
2026-04-06T17:59:44.951Z [DEBUG] MCP server "snowflake-local": Generated new OAuth state
2026-04-06T17:59:44.956Z [DEBUG] MCP server "snowflake-local": Starting SDK auth
2026-04-06T17:59:44.956Z [DEBUG] MCP server "snowflake-local": Server URL: https://[account].snowflakecomputing.com/api/v2/databases/[db]/schemas/[schema]/mcp-servers/[mcpserverobject]
2026-04-06T17:59:44.957Z [DEBUG] MCP server "snowflake-local": Fetching metadata from configured URL: ...
2026-04-06T17:59:45.036Z [DEBUG] MCP server "snowflake-local": Saving discovery state (authServer: https://[account].snowflakecomputing.com/oauth)
2026-04-06T17:59:45.037Z [WARN] Keychain payload (12116B JSON) exceeds security -i stdin limit; using argv
2026-04-06T17:59:45.134Z [DEBUG] MCP server "snowflake-local": Using pre-configured client ID
2026-04-06T17:59:45.134Z [DEBUG] MCP server "snowflake-local": Token expired without refresh token
2026-04-06T17:59:45.134Z [DEBUG] MCP server "snowflake-local": Saving code verifier
2026-04-06T17:59:45.134Z [DEBUG] MCP server "snowflake-local": Authorization URL: https://[account].snowflakecomputing.com/oauth/authorize?scope=session%3Arole%3Aall&response_type=code&...
2026-04-06T17:59:45.135Z [DEBUG] MCP server "snowflake-local": Scopes in URL: session:role:all
2026-04-06T17:59:45.135Z [DEBUG] MCP server "snowflake-local": Captured scopes from authorization URL: session:role:all
2026-04-06T17:59:45.135Z [DEBUG] MCP server "snowflake-local": Redirecting to authorization URL
2026-04-06T17:59:45.135Z [DEBUG] MCP server "snowflake-local": Authorization URL: https://[account].snowflakecomputing.com/oauth/authorize?scope=session%3Arole%3Aall&response_type=code&...
2026-04-06T17:59:45.135Z [DEBUG] MCP server "snowflake-local": Opening authorization URL: https://[account].snowflakecomputing.com/oauth/authorize?scope=session%3Arole%3Aall&response_type=code&...

Claude Code's offered explanation was that the authServerMetadataUrl only overrides the authorization server metadata, not the protected resource metadata, and the latter's scope prevails over the former. I'm only human, but I think the docs may be slightly misleading.

davidlee-ca · 4 months ago

bump -- it's still an issue

tielur · 4 months ago

@davidlee-ca the issue I reported related to the authServerMetadataUrl being a fallback instead of an override I believe is being addressed. This should ideally let you override the scopes with the authServerMetadataUrl setup after that gets released.

tielur · 4 months ago

@davidlee-ca give claude code 2.1.108 a try with the authServerMetadataUrl setup

Simonmaignan · 4 months ago

Thanks for describing this issue @davidlee-ca . I'm facing the same issue on my side.
I'd like to test the authServerMetadataUrl fix, but I struggle to understand how to change the snowflake mcp oauth server metadata and to which value set the claude code authServerMetadataUrl value.
Would you mind explaining or pointing me to documentation that explains how to add "scopes_supported": ["session:role:SPECIFIC_ROLE"] to the MCP oauth server metadata?

davidlee-ca · 4 months ago

@tielur it works!! Thank you for the nudge. This is with Claude v2.1.109:

2026-04-15T13:17:46.084Z [DEBUG] MCP server "snowflake-local": Fetched OAuth metadata with scope: session:role: SPECIFIC_ROLE
2026-04-15T13:17:46.085Z [DEBUG] MCP server "snowflake-local": Generated new OAuth state
2026-04-15T13:17:46.088Z [DEBUG] MCP server "snowflake-local": Starting SDK auth
2026-04-15T13:17:46.089Z [DEBUG] MCP server "snowflake-local": Server URL: https://[account].snowflakecomputing.com/api/v2/databases/[db]/schemas/[schema]/mcp-servers/[mcpserver]
2026-04-15T13:17:46.089Z [DEBUG] MCP server "snowflake-local": Fetching metadata from configured URL: https://gist.githubusercontent.com/[...]/mcp-auth-server-override-v2.json
2026-04-15T13:17:46.294Z [DEBUG] MCP server "snowflake-local": Saving discovery state (authServer: https://[account].snowflakecomputing.com/oauth)
2026-04-15T13:17:46.296Z [WARN] Keychain payload (8366B JSON) exceeds security -i stdin limit; using argv
2026-04-15T13:17:46.397Z [DEBUG] MCP server "snowflake-local": Using pre-configured client ID
2026-04-15T13:17:46.397Z [DEBUG] MCP server "snowflake-local": Token expired without refresh token
2026-04-15T13:17:46.397Z [DEBUG] MCP server "snowflake-local": Saving code verifier
2026-04-15T13:17:46.398Z [DEBUG] MCP server "snowflake-local": Overrode authorization scope from session:role:all to configured: session:role:SPECIFIC_ROLE  # this is new
2026-04-15T13:17:46.398Z [DEBUG] MCP server "snowflake-local": Authorization URL: ...
2026-04-15T13:17:46.398Z [DEBUG] MCP server "snowflake-local": Scopes in URL: session:role:SPECIFIC_ROLE  # yes!
2026-04-15T13:17:46.398Z [DEBUG] MCP server "snowflake-local": Captured scopes from authorization URL: session:role:SPECIFIC_ROLE  # woohoo!
2026-04-15T13:17:46.398Z [DEBUG] MCP server "snowflake-local": Redirecting to authorization URL

So, this works! Very happy to see that. I'll close the issue now.

davidlee-ca · 4 months ago

@Simonmaignan

Run this in a terminal, with your account identifier: curl https://[account].snowflakecomputing.com/.well-known/oauth-authorization-server/oauth Then you get something like this:

{
  "authorization_endpoint": "https://[account].snowflakecomputing.com/oauth/authorize",
  "token_endpoint": "https://[account].snowflakecomputing.com/oauth/token-request", 
  "issuer": "https://[account].snowflakecomputing.com/oauth",
  "response_types_supported": ["code"], 
  "response_modes_supported": ["query"], 
  "grant_types_supported": ["authorization_code", "refresh_token", "urn:ietf:params:oauth:grant-type:token-exchange"], 
  "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "private_key_jwt"], 
  "request_uri_parameter_supported": true, 
  "subject_types_supported": ["public"]
}

Add "scopes_supported" : [ "session:role:SPECIFIC_ROLE" ], save this as a JSON, and make it available from a public https endpoint (has to be https, http won't work per documentation on overriding oauth discovery). The easiest way to do this is through a secret gist (https://gist.github.com/) and get the raw URI.

Then, create the MCP with that override. I created the following json as snowflake-mcp-claude-code-config.json:

{
    "type": "http",
    "url": "(your Snowflake-managed MCP server URL",
    "oauth": {
        "authServerMetadataUrl": "(your secret gist's raw URL)",
        "clientId": "(client ID)",
        "callbackPort": (client port that you configured with the Snowflake OAuth security integration, I used 6274)
    }
}

then run in command: claude mcp add-json snowflake "$(jq -c . snowflake-mcp-claude-code-config.json)" --client-secret

Happy to follow up!

Simonmaignan · 4 months ago

@davidlee-ca , I'm not sure if I was blind, tired or hallucinating during the last few days where I went through the Claude Code MCP documentation multiple time or if this OAuth scopes section was added recently, but this solved my issue.

Here is my ~/.claude.json Snowflake managed MCP entry

"snowflake": {
          "type": "http",
          "url": "https://<account-id>.snowflakecomputing.com/api/v2/databases/DB/schemas/SCHEMA/mcp-servers/MCP_SERVER",
          "oauth": {
            "clientId": "<security_integration_oauth_client_id",
            "callbackPort": 8080,
            "scopes": "session:role:mcp_analyst"
          }
        }

(the OAuth client secret is stored in my Claude credentials)
This configuration sets up Claude to open the following Authorization URL and my authentication was successful out of the box.

https://<account-id>.snowflakecomputing.com/oauth/authorize?response_type=code&client_id=...Y%3D&code_challenge=%5B...%5D&code_challenge_method=...&redirect_uri=http%3A%2F%2Flocalhost%3A3118%2Fcallback&state=%5B...%5D&scope=session%3Arole%3Amcp_analyst&resource=https%3A%2F%2F<account-id>.snowflakecomputing.com%2Fapi%2Fv2%2Fdatabases%2FDB%2Fschemas%2FSCHEMA%2Fmcp-servers%2FMCP_SERVER

According to Claude Code Changelog, this OAuth scopes feature was not added recently so I'm not sure why I missed this info during the past few days.

davidlee-ca · 4 months ago

no way, i've been woodshedding for days putting that override together...

davidlee-ca · 4 months ago

You were not hallucinating, scopes argument was not supported when I wrote this up

github-actions[bot] · 4 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.