Skip to main content

Snowflake Data Lake + Azure Integration with Programmatic Access Token (PAT) Authentication

Written by Openbridge Support

This guide walks you through connecting your Snowflake warehouse to Openbridge using a Programmatic Access Token (PAT) with Azure Blob Storage as the staging area. PAT authentication is simpler than OAuth — there is no recurring token refresh or manual re-authentication. You generate a token, provide it to Openbridge, and it remains valid until it expires. Token lifetime is controlled by your authentication policy; this guide configures a maximum of 365 days. When the token approaches expiration, you generate a new one.


Prerequisites

Before you begin, make sure you have:

  • An active Snowflake account with ACCOUNTADMIN privileges

  • An Azure account with permissions to create storage accounts, containers, and access your Tenant ID

Openbridge handles the rest automatically once your destination is configured.


Step 1: Configure Your Azure Storage

Openbridge uses an Azure Blob Storage container as a staging area to load data into Snowflake. You will need four pieces of information from Azure.

1a: Create or Select a Storage Account

  1. In the Azure Portal, navigate to Storage accounts.

  2. Select an existing storage account or click Create to create a new one.

  3. Note the exact storage account name.

1b: Create a Container

  1. Open your storage account.

  2. Navigate to Data storage > Containers.

  3. Click + Container.

  4. Enter a container name (e.g., openbridge-snowflake-staging).

  5. Click Create.

1c: Retrieve the Connection String

  1. In your storage account, navigate to Security + networking > Access keys.

  2. Copy the Connection string from Key1.

Save this connection string — you will need it when configuring your destination in Openbridge.


1d: Obtain Your Tenant ID

  1. In the Azure Portal, search for Microsoft Entra ID.

  2. On the Overview page, copy the Tenant ID.

Save this Tenant ID — you will need it in the next step.


Step 2: Run the Openbridge Setup Script

Open a Snowflake worksheet and log in as ACCOUNTADMIN. Copy and customize the script below by replacing the placeholder variables at the top.

Variables to Customize

Variable

Description

Format

db_name

Name for the Openbridge database

UPPERCASE

schema_name

Name for the schema

UPPERCASE

user_name

Username for the Openbridge service account

UPPERCASE

role_name

Name for the Openbridge role

UPPERCASE

stage_name

Name for the external stage

UPPERCASE

warehouse_name

Name for the warehouse

UPPERCASE

warehouse_type

Warehouse type

UPPERCASE

warehouse_size

Warehouse size

UPPERCASE

azure_storage_account

Your Azure storage account name

Exact casing

azure_container_name

Your Azure container name

Exact casing

azure_tenant_id

Your Microsoft Entra Tenant ID

Exact casing

Setup Script

-- ============================================
-- SET THESE VARIABLES BEFORE RUNNING
-- ============================================
SET db_name = 'OPENBRIDGE';
SET schema_name = 'OPENBRIDGE_SCHEMA';
SET user_name = 'OPENBRIDGE_USER';
SET role_name = 'OPENBRIDGE_ROLE';
SET stage_name = 'OPENBRIDGE_STAGE';
SET warehouse_name = 'OPENBRIDGE_WH';
SET warehouse_type = 'STANDARD';
SET warehouse_size = 'XSMALL';
SET azure_storage_account = 'your-storage-account';
SET azure_container_name = 'your-container-name';
SET azure_tenant_id = 'your-tenant-id';

SET default_ns = $db_name || '.' || $schema_name;
SET azure_url = 'azure://' || $azure_storage_account || '.blob.core.windows.net/' || $azure_container_name || '/';

-- ============================================
-- CREATE ROLE
-- ============================================
USE ROLE ACCOUNTADMIN;
CREATE ROLE IF NOT EXISTS IDENTIFIER($role_name);

-- Grant the role to your current user (for testing purposes)
SET current_username = CURRENT_USER();
GRANT ROLE IDENTIFIER($role_name) TO USER IDENTIFIER($current_username);

-- ============================================
-- CREATE WAREHOUSE
-- ============================================
CREATE WAREHOUSE IF NOT EXISTS IDENTIFIER($warehouse_name)
WAREHOUSE_SIZE = $warehouse_size
WAREHOUSE_TYPE = $warehouse_type
AUTO_SUSPEND = 60
AUTO_RESUME = TRUE
INITIALLY_SUSPENDED = TRUE;

GRANT USAGE ON WAREHOUSE IDENTIFIER($warehouse_name) TO ROLE IDENTIFIER($role_name);

-- ============================================
-- CREATE DATABASE AND SCHEMA
-- ============================================
CREATE DATABASE IF NOT EXISTS IDENTIFIER($db_name);
GRANT USAGE ON DATABASE IDENTIFIER($db_name) TO ROLE IDENTIFIER($role_name);

USE DATABASE IDENTIFIER($db_name);
CREATE SCHEMA IF NOT EXISTS IDENTIFIER($schema_name);

GRANT ALL PRIVILEGES ON SCHEMA IDENTIFIER($schema_name) TO ROLE IDENTIFIER($role_name);
GRANT CREATE TABLE, CREATE VIEW, CREATE STAGE, CREATE FILE FORMAT ON SCHEMA IDENTIFIER($schema_name) TO ROLE IDENTIFIER($role_name);
USE SCHEMA IDENTIFIER($default_ns);

-- ============================================
-- CREATE USER
-- Service users cannot have passwords — authentication
-- is handled exclusively via the PAT created in Step 4.
-- ============================================
CREATE USER IF NOT EXISTS IDENTIFIER($user_name)
TYPE = SERVICE
DEFAULT_ROLE = $role_name
DEFAULT_WAREHOUSE = $warehouse_name
DEFAULT_NAMESPACE = $default_ns;

GRANT ROLE IDENTIFIER($role_name) TO USER IDENTIFIER($user_name);

-- ============================================
-- CREATE AZURE STORAGE INTEGRATION AND STAGE
-- (AZURE_TENANT_ID, STORAGE_ALLOWED_LOCATIONS, and URL
-- do not support session variable substitution)
-- ============================================
DECLARE
tenant_id VARCHAR DEFAULT $azure_tenant_id;
azure_uri VARCHAR DEFAULT $azure_url;
stage VARCHAR DEFAULT $stage_name;
sql_str VARCHAR;
BEGIN
sql_str := 'CREATE OR REPLACE STORAGE INTEGRATION openbridge_azure TYPE = EXTERNAL_STAGE STORAGE_PROVIDER = ''AZURE'' ENABLED = TRUE AZURE_TENANT_ID = ''' || :tenant_id || ''' STORAGE_ALLOWED_LOCATIONS = (''' || :azure_uri || ''')';
EXECUTE IMMEDIATE :sql_str;
sql_str := 'CREATE STAGE IF NOT EXISTS ' || :stage || ' STORAGE_INTEGRATION = openbridge_azure URL = ''' || :azure_uri || ''' FILE_FORMAT = (TYPE = ''PARQUET'')';
EXECUTE IMMEDIATE :sql_str;
END;

GRANT ALL PRIVILEGES ON STAGE IDENTIFIER($stage_name) TO ROLE IDENTIFIER($role_name);
GRANT USAGE ON INTEGRATION openbridge_azure TO ROLE IDENTIFIER($role_name);

-- ============================================
-- CREATE NETWORK POLICY
-- ============================================
USE ROLE ACCOUNTADMIN;

-- These are the Openbridge production IP addresses.
-- Current IPs: https://docs.openbridge.com/en/articles/11822520-snowflake-warehouse-with-oauth-authentication
-- If these IPs ever change, update the network rule:
-- ALTER NETWORK RULE openbridge_network_rule
-- SET VALUE_LIST = ('NEW_IP_1/32', 'NEW_IP_2/32');
CREATE NETWORK RULE IF NOT EXISTS openbridge_network_rule
TYPE = IPV4
MODE = INGRESS
VALUE_LIST = ('52.2.68.68/32', '52.54.227.22/32');

CREATE NETWORK POLICY IF NOT EXISTS openbridge_network_policy
ALLOWED_NETWORK_RULE_LIST = ('openbridge_network_rule');

ALTER USER IDENTIFIER($user_name)
SET NETWORK_POLICY = openbridge_network_policy;

-- ============================================
-- CREATE AUTHENTICATION POLICY FOR PAT
-- ============================================
CREATE AUTHENTICATION POLICY IF NOT EXISTS openbridge_pat_policy
PAT_POLICY = (
NETWORK_POLICY_EVALUATION = ENFORCED_REQUIRED,
MAX_EXPIRY_IN_DAYS = 365
);

ALTER USER IDENTIFIER($user_name)
SET AUTHENTICATION POLICY openbridge_pat_policy;

-- ============================================
-- GRANT PAT MANAGEMENT TO OPENBRIDGE ROLE
-- ============================================
GRANT MODIFY PROGRAMMATIC AUTHENTICATION METHODS ON USER IDENTIFIER($user_name)
TO ROLE IDENTIFIER($role_name);

-- Test 1: Create a table
CREATE OR REPLACE TABLE test_table (
id INT AUTOINCREMENT PRIMARY KEY,
name STRING,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP()
);

-- Test 2: Insert data into the table
INSERT INTO test_table (name) VALUES
('Alice'),
('Bob'),
('Charlie');

-- Test 3: Query data from the table
SELECT * FROM test_table;

-- Test 4: Update data in the table
UPDATE test_table
SET name = 'Alice Updated'
WHERE name = 'Alice';

-- Test 5: Delete data from the table
DELETE FROM test_table
WHERE name = 'Bob';

-- Test 6: Drop the table
DROP TABLE test_table;


Need full ownership? The script above grants usage and specific privileges, which is safe for shared databases. If this is a dedicated Openbridge database and you want the Openbridge role to have full control, replace the database/schema grants with:

GRANT OWNERSHIP ON DATABASE IDENTIFIER($db_name) TO ROLE IDENTIFIER($role_name);
GRANT OWNERSHIP ON SCHEMA IDENTIFIER($schema_name) TO ROLE IDENTIFIER($role_name);


GRANT OWNERSHIP transfers full control of the database and schema to the Openbridge role, which can revoke access for other roles. Only use it for a dedicated Openbridge database.


Step 3: Grant Snowflake Access to Your Azure Container

The storage integration created in Step 2 generates a service principal that Snowflake uses to access your Azure container. You need to grant this service principal the required permissions.


3a: Retrieve the Snowflake Service Principal

Run the following in your Snowflake worksheet:

DESC STORAGE INTEGRATION openbridge_azure;

From the output, copy these two values:

Property

Description

AZURE_CONSENT_URL

URL to grant Snowflake access to your Azure tenant

AZURE_MULTI_TENANT_APP_NAME

Snowflake's application name in your Azure tenant

3b: Grant Consent to Snowflake

  1. Paste the AZURE_CONSENT_URL into your browser.

  2. Log in with an Azure account that has administrative permissions.

  3. Click Accept to grant Snowflake access to your Azure tenant.

3c: Assign Storage Permissions to the Snowflake Service Principal

  1. In the Azure Portal, navigate to Storage accounts and select your storage account.

  2. Click Access Control (IAM).

  3. Click Add > Add role assignment.

  4. Select the role Storage Blob Data Contributor.

  5. Click Next.

  6. Under Assign access to, select User, group, or service principal.

  7. Click Select members.

  8. Search for the AZURE_MULTI_TENANT_APP_NAME value from Step 3a — use only the first 10–12 characters of the name. Searching the full string often returns no results.

  9. Select the Snowflake application and click Select.

  10. Click Review + assign.

Azure service principal activation may take up to one hour before storage operations succeed. If you encounter access errors immediately after setup, wait and retry.


If you ever recreate the storage integration in Snowflake, it will generate a new service principal. You would need to repeat this step with the new values.


Step 4: Generate a Programmatic Access Token

The setup script in Step 2 granted PAT management privileges to your Openbridge role. Switch to that role and generate the token.

Replace <YOUR_ROLE_NAME> and <YOUR_USER_NAME> below with the values you set in
Step 2:

SE ROLE <YOUR_ROLE_NAME>;

ALTER USER <YOUR_USER_NAME>
ADD PROGRAMMATIC ACCESS TOKEN openbridge_pat
DAYS_TO_EXPIRY = 365
ROLE_RESTRICTION = <YOUR_ROLE_NAME>;


For example, if you used the default values from Step 2:

ALTER USER OPENBRIDGE_USER
ADD PROGRAMMATIC ACCESS TOKEN openbridge_pat
DAYS_TO_EXPIRY = 365
ROLE_RESTRICTION = OPENBRIDGE_ROLE;

Important: This command returns the token only once. Copy and save it in a secure location immediately. You will not be able to retrieve it again.


Step 5: Find Your Snowflake Account Identifier

  1. Log in to your Snowflake account.

  2. Click the account selector in the bottom-left corner.

  3. Hover over your account and click the link icon to copy your Account Identifier.

Your Account Identifier should be in the format ORGNAME-ACCOUNTNAME (e.g., MYORG-MYACCOUNT).


If you are unsure of your Account Identifier, run the following in a Snowflake worksheet:

SELECT CURRENT_ORGANIZATION_NAME() || '-' || CURRENT_ACCOUNT_NAME();

Use the result as your Account Identifier.


Step 6: Configure Your Destination in Openbridge

  1. In the Openbridge app, navigate to your Snowflake destination settings.

  2. Enter the following details:

Field

Value

Account Identifier

From Step 5

Username

The user_name value from Step 2 (e.g., OPENBRIDGE_USER)

Programmatic Access Token

The token from Step 4

Database

The db_name value from Step 2 (e.g., OPENBRIDGE)

Schema

The schema_name value from Step 2 (e.g., OPENBRIDGE_SCHEMA)

Warehouse

The warehouse_name value from Step 2 (e.g., OPENBRIDGE_WH)

Stage

The stage_name value from Step 2 (e.g., OPENBRIDGE_STAGE)

Role

The role_name value from Step 2 (e.g., OPENBRIDGE_ROLE)

Container Name

Your Azure container name

Connection String

The connection string from Step 1c

  1. Save the destination.


Token Renewal

Your Programmatic Access Token expires based on the DAYS_TO_EXPIRY value set during generation (up to 365 days). Before it expires, revoke the old token, generate a new one, and update it in your Openbridge destination settings.

Check token expiration

SHOW PROGRAMMATIC ACCESS TOKENS FOR USER <YOUR_USER_NAME>;

Revoke the expiring token

ALTER USER <YOUR_USER_NAME>
REMOVE PROGRAMMATIC ACCESS TOKEN openbridge_pat;

Generate a new token

USE ROLE <YOUR_ROLE_NAME>;

ALTER USER <YOUR_USER_NAME>
ADD PROGRAMMATIC ACCESS TOKEN openbridge_pat
DAYS_TO_EXPIRY = 365
ROLE_RESTRICTION = <YOUR_ROLE_NAME>;


Important: This command returns the token only once. Copy and save it immediately.


Update Openbridge

Edit your destination in the Openbridge app and replace the token. All other fields are prepopulated.

Replace <YOUR_USER_NAME> and <YOUR_ROLE_NAME> with the values from Step 2 (e.g., OPENBRIDGE_USER, OPENBRIDGE_ROLE).


Troubleshooting

"Authentication policy does not allow programmatic access tokens"

If your account has an existing authentication policy that restricts authentication methods, you need to add PAT as an allowed method:

ALTER AUTHENTICATION POLICY your_existing_policy
SET AUTHENTICATION_METHODS = ('OAUTH', 'PASSWORD', 'PROGRAMMATIC_ACCESS_TOKEN');

"Network policy required"

The authentication policy requires a network policy. Verify the network policy from Step 2 was created and applied to the user successfully:

DESCRIBE USER OPENBRIDGE_USER;

Look for NETWORK_POLICY in the output. If empty, re-run the network policy section from Step 2.


Token is not working after policy change

If an admin changed the MAX_EXPIRY_IN_DAYS to a value shorter than your token's remaining lifetime, the token is automatically invalidated. Generate a new token with Step 4.


Snowflake cannot access your Azure container

If Snowflake fails to access your Azure container after completing all steps:

  1. Verify you completed the consent flow using the AZURE_CONSENT_URL from DESC STORAGE INTEGRATION openbridge_azure.

  2. Confirm the Snowflake service principal has the Storage Blob Data Contributor role on your storage account.

  3. Azure service principal activation can take up to one hour. Wait and retry if you just completed the setup.

  4. Check that the storage account name, container name, and tenant ID in the storage integration match your actual Azure values exactly.

Did this answer your question?