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
In the Azure Portal, navigate to Storage accounts.
Select an existing storage account or click Create to create a new one.
Note the exact storage account name.
1b: Create a Container
Open your storage account.
Navigate to Data storage > Containers.
Click + Container.
Enter a container name (e.g.,
openbridge-snowflake-staging).Click Create.
1c: Retrieve the Connection String
In your storage account, navigate to Security + networking > Access keys.
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
In the Azure Portal, search for Microsoft Entra ID.
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 |
| Name for the Openbridge database | UPPERCASE |
| Name for the schema | UPPERCASE |
| Username for the Openbridge service account | UPPERCASE |
| Name for the Openbridge role | UPPERCASE |
| Name for the external stage | UPPERCASE |
| Name for the warehouse | UPPERCASE |
| Warehouse type | UPPERCASE |
| Warehouse size | UPPERCASE |
| Your Azure storage account name | Exact casing |
| Your Azure container name | Exact casing |
| 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 |
| URL to grant Snowflake access to your Azure tenant |
| Snowflake's application name in your Azure tenant |
3b: Grant Consent to Snowflake
Paste the
AZURE_CONSENT_URLinto your browser.Log in with an Azure account that has administrative permissions.
Click Accept to grant Snowflake access to your Azure tenant.
3c: Assign Storage Permissions to the Snowflake Service Principal
In the Azure Portal, navigate to Storage accounts and select your storage account.
Click Access Control (IAM).
Click Add > Add role assignment.
Select the role Storage Blob Data Contributor.
Click Next.
Under Assign access to, select User, group, or service principal.
Click Select members.
Search for the
AZURE_MULTI_TENANT_APP_NAMEvalue from Step 3a — use only the first 10–12 characters of the name. Searching the full string often returns no results.Select the Snowflake application and click Select.
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
Log in to your Snowflake account.
Click the account selector in the bottom-left corner.
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
In the Openbridge app, navigate to your Snowflake destination settings.
Enter the following details:
Field | Value |
Account Identifier | From Step 5 |
Username | The |
Programmatic Access Token | The token from Step 4 |
Database | The |
Schema | The |
Warehouse | The |
Stage | The |
Role | The |
Container Name | Your Azure container name |
Connection String | The connection string from Step 1c |
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:
Verify you completed the consent flow using the
AZURE_CONSENT_URLfromDESC STORAGE INTEGRATION openbridge_azure.Confirm the Snowflake service principal has the Storage Blob Data Contributor role on your storage account.
Azure service principal activation can take up to one hour. Wait and retry if you just completed the setup.
Check that the storage account name, container name, and tenant ID in the storage integration match your actual Azure values exactly.
