Access Snowflake
Control Snowflake access through Keycard using Okta groups, JWT authentication, and policy-based authorization for AI agents.
In this tutorial, you’ll set up end-to-end access control for Snowflake using Keycard. Your AI agents will query Snowflake through a service account, but Keycard governs who can access the Snowflake MCP based on Okta group membership, even if those users don’t have direct Snowflake accounts.
Architecture
Section titled “Architecture”Snowflake has a single service user with multiple roles. Keycard acts as the policy layer: it grants different scopes based on Okta group membership, which determines what the user can do in Snowflake. Users don’t need individual Snowflake accounts; Keycard decides who gets through and with what permissions.
What you’ll build
Section titled “What you’ll build”By the end of this tutorial, you’ll have:
- Okta configured as an identity provider with a
data-analystsgroup - Keycard policies that grant write access to analysts; everyone else gets read-only
- Snowflake configured with read-only and read-write roles, accessed via a single service user
- An MCP server that connects AI agents to Snowflake with permissions matching their Okta groups
Prerequisites
Section titled “Prerequisites”Before starting, you’ll need:
- A Keycard account (sign up free). After signing up, go to Zone Settings to find your zone ID (you’ll need this throughout the tutorial)
- An Okta account with admin access, or sign up for the free Integrator plan
- Claude Code installed
- A Snowflake account with
ACCOUNTADMINrole (required for creating security integrations) - Docker and Docker Compose installed
- Clone the tutorial repository:
Terminal window git clone https://github.com/keycardai/tutorial-snowflake-mcp.gitcd tutorial-snowflake-mcpcp .env.example .env
Find your Snowflake account URL
Section titled “Find your Snowflake account URL”To find your Snowflake account URL:
- Sign in to Snowflake
- Click your account name in the bottom-left corner
- Hover over your account and click the link icon to copy the account URL
The URL looks like https://abc12345.us-east-1.snowflakecomputing.com.
Prepare your environment file
Section titled “Prepare your environment file”Open .env in your editor. You’ll fill in values as you progress through the tutorial, but start by adding these now:
# Keycard zone (from Zone Settings in Keycard Console)KEYCARD_ZONE_URL=https://<ZONE-ID>.keycard.cloud
# Snowflake connectionSNOWFLAKE_ACCOUNT_URL=<YOUR-SNOWFLAKE-ACCOUNT-URL>SNOWFLAKE_DATABASE=GREENDALESNOWFLAKE_WAREHOUSE=COMPUTE_WHThe remaining values (KEYCARD_CLIENT_ID and KEYCARD_CLIENT_SECRET) will be added in Part 2 when you create the application.
Part 1: Configure Okta as an Identity Provider
Section titled “Part 1: Configure Okta as an Identity Provider”First, we’ll connect Okta to Keycard so users can authenticate with their existing corporate credentials.
-
Create an OIDC application in Okta
In Okta Admin Console, navigate to Applications > Applications and click Create App Integration.
Select OIDC - OpenID Connect and Web Application, then click Next.
Configure the application:
Field Value App integration name Keycard Grant type Authorization Code, Refresh Token Sign-in redirect URI https://<ZONE-ID>.keycard.cloud/oauth/2/redirectSign-out redirect URI https://<ZONE-ID>.keycard.cloud/openid/connect/redirect/logoutControlled access Allow everyone in your organization to access Click Save.
-
Configure Okta to send group claims
While still on the Sign On tab, scroll to Advanced Settings and expand advanced options.
Under Group Claims, click Edit and configure:
Field Value Groups claim type Filter Groups claim filter Name: groups, Filter: Matches regex, Value:.*This sends all group memberships in the ID token. For production, narrow the regex to only the groups Keycard needs.
-
Create an Okta group for analysts
In Okta Admin Console, navigate to Directory > Groups and create a group:
Group Name Description data-analystsFull read-write access to Snowflake data Add users who need write access to this group. Users not in
data-analystsautomatically get read-only access (no separate group needed). -
Add Okta as a provider in Keycard
In Keycard Console, navigate to Providers and click Add Provider.
Field Value Name Okta Issuer URL https://<YOUR-OKTA-DOMAIN>(e.g.,https://acme.okta.com)Client ID From step 1 Client Secret From step 1 Click Create Provider.
After creating the provider, click into its settings. Under Advanced Settings, add
groupsto Additional Scopes. This ensures Keycard requests group claims from Okta during authentication. -
Enable Okta for zone sign-in
In Keycard Console, navigate to Zone Settings and scroll to Zone sign in configuration.
Toggle Use an external Identity Provider on and select Okta from the dropdown.
Click Save Changes.
Users can now sign in to your Keycard zone using their Okta credentials.
Part 2: Configure Keycard Resources and Application
Section titled “Part 2: Configure Keycard Resources and Application”Now we’ll register everything in Keycard: the Snowflake API as a resource, the MCP server as a resource, and an application that ties them together.
-
Create the Snowflake API resource
In Keycard Console, navigate to Resources and click Add Resource > Add Manually.
Field Value Resource Name Snowflake API Resource Identifier <YOUR-SNOWFLAKE-ACCOUNT-URL>Credential Provider Zone Provider This resource represents the Snowflake API that the MCP server will call on behalf of users.
-
Create the Snowflake MCP resource
Click Add Resource > Add Manually again, this time to register the MCP server that users will authenticate against.
Field Value Resource Name Snowflake MCP Resource Identifier http://localhost:3100/Credential Provider Zone Provider -
Create the Snowflake MCP application
Navigate to Applications and click Add Application > Add Manually.
Field Value Name Snowflake MCP Identifier http://localhost:3100/Click Create Application.
-
Configure the application resources
On the application details page:
Under Provides, click Add Provided Resource and select Snowflake MCP (the resource your application exposes).
Under Dependency, click Add Dependency and select Snowflake API (the resource the application accesses on behalf of users).
-
Generate client credentials
On the application details page, go to the Application Credentials tab and click Add Credential. In the modal, select Client ID & Secret.
-
Create an access policy
Navigate to Policies > All Policies and click Create Policy.
Name it Snowflake MCP, then switch to the Cedar tab and add the following policy:
// Allow any user to access the MCP serverpermit (principal is Keycard::User,action,resource)when{(resource has identifier) &&((resource.identifier) == "http://localhost:3100/")};// Allow any user to access Snowflake, unless requesting READWRITE_ROLEpermit (principal is Keycard::User,action,resource)when{(((resource has identifier) && (context has scopes)) &&((resource.identifier) == "<YOUR-SNOWFLAKE-ACCOUNT-URL>")) &&(!((context.scopes).containsAny(["session:role:READWRITE_ROLE"])))};// Allow data-analysts group members to access Snowflake with READWRITE_ROLEpermit (principal is Keycard::User,action,resource)when{((((((resource has identifier) && (context has scopes)) &&(context has subject_claims)) &&((context.subject_claims) has groups)) &&((resource.identifier) == "<YOUR-SNOWFLAKE-ACCOUNT-URL>")) &&((context.scopes).containsAny(["session:role:READWRITE_ROLE"]))) &&(((context.subject_claims).groups).contains("data-analysts"))};Click Validate to check the policy syntax, then click Publish Policy to save it.
-
Create and activate a policy set
Go back to Policies (this lands you on Policy Sets) and click New Policy Set.
Name it Snowflake Access and add two policies:
- default-app-delegation (the preconfigured policy that enables token exchange)
- Snowflake MCP (the policy you just created)
Click Publish as Candidate to create a version. This lands you on the candidate page where you can click Activate to make it live.
Part 3: Configure Snowflake for Keycard JWTs
Section titled “Part 3: Configure Snowflake for Keycard JWTs”Snowflake needs to trust Keycard as an OAuth authorization server. We’ll create a single service user for the MCP server. Keycard handles user identity and access control, so individual Snowflake accounts aren’t needed.
-
Create the MCP service user
In Snowflake, click + Create in the top-left and select SQL File.
In the top-right of the worksheet, select
ACCOUNTADMINas your role andCOMPUTE_WHas your warehouse.Run the following SQL to create a service user and two roles for the MCP server. Replace
<YOUR-KEYCARD-APPLICATION-ID>with your Application ID from the Keycard Console application details page:BEGIN-- Create roles with different permission levelsCREATE ROLE READONLY_ROLE;CREATE ROLE READWRITE_ROLE;-- Create service user and grant both rolesCREATE USER MCP_SERVICE_USERTYPE = SERVICELOGIN_NAME = '<YOUR-KEYCARD-APPLICATION-ID>'DEFAULT_ROLE = READONLY_ROLECOMMENT = 'Service account for Keycard MCP server';GRANT ROLE READONLY_ROLE TO USER MCP_SERVICE_USER;GRANT ROLE READWRITE_ROLE TO USER MCP_SERVICE_USER;END; -
Create an OAuth security integration
Configure Snowflake to accept Keycard-issued JWTs:
CREATE SECURITY INTEGRATION keycard_oauthTYPE = EXTERNAL_OAUTHENABLED = TRUEEXTERNAL_OAUTH_TYPE = CUSTOMEXTERNAL_OAUTH_ISSUER = 'https://<ZONE-ID>.keycard.cloud'EXTERNAL_OAUTH_JWS_KEYS_URL = 'https://<ZONE-ID>.keycard.cloud/openidconnect/jwks'EXTERNAL_OAUTH_AUDIENCE_LIST = ('<YOUR-SNOWFLAKE-ACCOUNT-URL>')EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = 'client_id'EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'LOGIN_NAME'EXTERNAL_OAUTH_SCOPE_MAPPING_ATTRIBUTE = 'scope'EXTERNAL_OAUTH_SCOPE_DELIMITER = ' 'EXTERNAL_OAUTH_ANY_ROLE_MODE = 'ENABLE'; -
Seed sample data
Create a database, schema, and sample data:
BEGINCREATE DATABASE GREENDALE;CREATE SCHEMA GREENDALE.ENROLLMENT;USE DATABASE GREENDALE;USE SCHEMA ENROLLMENT;CREATE TABLE STUDENTS (ID INT AUTOINCREMENT PRIMARY KEY,NAME VARCHAR(100),EMAIL VARCHAR(100),MAJOR VARCHAR(50),GPA DECIMAL(3,2),ENROLLED_DATE DATE);INSERT INTO STUDENTS (NAME, EMAIL, MAJOR, GPA, ENROLLED_DATE) VALUES('Troy Barnes', 'troy.barnes@greendale.edu', 'Air Conditioning Repair', 3.2, '2009-09-01'),('Abed Nadir', 'abed.nadir@greendale.edu', 'Film Studies', 3.8, '2009-09-01'),('Jeff Winger', 'jeff.winger@greendale.edu', 'Undeclared', 2.9, '2009-09-01'),('Britta Perry', 'britta.perry@greendale.edu', 'Psychology', 3.1, '2009-09-01'),('Annie Edison', 'annie.edison@greendale.edu', 'Healthcare Administration', 4.0, '2009-09-01'),('Shirley Bennett', 'shirley.bennett@greendale.edu', 'Business', 3.5, '2009-09-01'),('Pierce Hawthorne', 'pierce.hawthorne@greendale.edu', 'Undeclared', 2.1, '2009-09-01');-- READONLY_ROLE: read-only accessGRANT USAGE ON WAREHOUSE COMPUTE_WH TO ROLE READONLY_ROLE;GRANT USAGE ON DATABASE GREENDALE TO ROLE READONLY_ROLE;GRANT USAGE ON SCHEMA GREENDALE.ENROLLMENT TO ROLE READONLY_ROLE;GRANT SELECT ON ALL TABLES IN SCHEMA GREENDALE.ENROLLMENT TO ROLE READONLY_ROLE;-- READWRITE_ROLE: read-write accessGRANT USAGE ON WAREHOUSE COMPUTE_WH TO ROLE READWRITE_ROLE;GRANT USAGE ON DATABASE GREENDALE TO ROLE READWRITE_ROLE;GRANT USAGE ON SCHEMA GREENDALE.ENROLLMENT TO ROLE READWRITE_ROLE;GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA GREENDALE.ENROLLMENT TO ROLE READWRITE_ROLE;END;
Part 4: Run the Snowflake MCP Server
Section titled “Part 4: Run the Snowflake MCP Server”In the tutorial-snowflake-mcp directory you cloned during prerequisites, run the pre-built MCP server. The server uses the MCP service account you created, but Keycard validates each user’s identity and group membership before allowing access.
-
Run with Docker
Terminal window docker compose upThe MCP server is now running at
http://localhost:3100/mcp. -
Add the MCP server to Claude Code
In a new terminal, add the Snowflake MCP server to Claude Code:
Terminal window claude mcp add --transport http snowflake-mcp http://localhost:3100/mcp -
Authenticate with the MCP server
Start Claude Code:
Terminal window claudeType
/mcpand select the snowflake-mcp server. This will open your browser and take you through the Keycard authentication flow (backed by Okta). -
Test read-only access
Sign in as a user who is not in the
data-analystsgroup.Ask Claude to read data:
List all students at GreendaleThis should succeed: the user has
READONLY_ROLEaccess.Now ask Claude to write data:
Add a new student named Ben Chang with email ben.chang@greendale.edu, major Spanish, GPA 2.5This should fail:
READONLY_ROLEdoesn’t have INSERT permissions. -
Test read-write access
Add yourself to the
data-analystsgroup in Okta, then sign out of Keycard to refresh your session:https://<ZONE-ID>.keycard.cloud/logoutIn Claude Code, re-authenticate by typing
/mcp, selecting snowflake-mcp, and completing the login flow again.Ask Claude to write data:
Add a new student named Ben Chang with email ben.chang@greendale.edu, major Spanish, GPA 2.5This should succeed: the user has
READWRITE_ROLEaccess with INSERT permissions.Verify the insert worked:
Show me all students including Ben Chang
Next steps
Section titled “Next steps”You now have Snowflake connected through Keycard with Okta-based identity and group-based policies. From here, you can:
- Deploy to higher environments with workload identity federation to eliminate client secrets
- Create per-operation roles (e.g.,
INSERT_ROLE,UPDATE_ROLE,DELETE_ROLE) for even more granular access control - Add more granular policies (e.g., restrict specific warehouses or databases)
- Expand the MCP server with additional tools (schema inspection, write operations)
- Set up audit log export to track all Snowflake access
- Configure additional identity providers alongside Okta