Snowflake Native Apps are flexible applications that are built, deployed, and shared completely within the Snowflake platform. Sharing apps through the Snowflake Marketplace simplifies the security and deployment of the app for both providers and consumers alike.
Among the many capabilities of Native Apps, is the ability to connect to external network endpoints to retrieve information, execute workflows, etc. Due to the justifiably restrictive security policies on Native App providers, sometimes building apps that access external endpoints can be challenging. This guide will walk you through all necessary steps to develop a Snowflake Native App capable of accessing external endpoints and remaining compliant with the Snowflake security policies required for listing an app on the marketplace.
We will focus on two specific use cases not illuminated by existing documentation. One, what if you need to dynamically set configurations of an external access integration? And two, what is the configuration format for secret types other than OAUTH type? The latter is currently not publicly documented.
Key Objects for an External Endpoint Solution
Below we will quickly summarize the Snowflake object types at play in this solution. Note that this is only a quick intro but full documentation is available on Snowflake’s website when linked below.
External Access Integration: An external access integration (EAI) is a Snowflake object that bundles multiple other objects together such as network rules, secrets, and external API integrations. The purpose of bundling these objects together is so that they may then be bound to a stored procedure or UDF. Once the EAI is bound to a stored procedure, the stored procedure is then able to access external network locations using the objects within the EAI. For more information on EAI’s see here.
Secret: A secret is a Snowflake object that safely stores secret information to later be accessed by stored procedures and UDF’s etc. See here for more information.
Reference: A reference is a concept pertaining to Snowflake Native Apps exclusively. Defined in the manifest.yml, references can be thought of as predefined placeholders existing in an application that users can bind objects to. When a reference is bound by a user, the application can then use the reference to access the object bound to it by the user. This functionality allows users to share objects such as secrets with a Native Application without having to worry about the security of the Native App’s secret storing practices among other things. Use of references is required to be used by applications listed on the Snowflake Marketplace when accessing external network locations. For in depth reference documentation see here.
Callback Procedures: A callback procedure in the context of Native App references is a stored procedure defined within the application that Snowflake will call to register (bind) a reference. These procedures are defined in the setup script and referred to in the reference definition. There are two types of callback procedures, Register Callback procedures and Configuration Callback procedures. The register callback simply binds the reference with the configuration callback informs the UI of specific reference configuration and information at time of reference request.
The Reference Registration Workflow
Behind the scenes this is what happens when a reference is requested from streamlit with the register_reference function we will be using:
- Streamlit app requests reference from the user
- Snowflake calls the Configuration Callback procedure to acquire config information for the given reference (if applicable)
- Dialog box opens OVER the top of the Streamlit UI, where user can either bind or configure a new object
- User submits the form in the dialog box
- Snowflake takes inputs from the user and creates objects if necessary, then binds them to the reference using the Register Callback procedure.
Putting It All Together
In this example we will be integrating a dynamically generated EAI and secret reference into our Native App. We will then attach the EAI to a stored procedure we plan to use.
1. Defining References:
Define the references in the manifest.yaml of your application. For this we will define two references.
references:
- secret_example:
label: "Example Secret"
description: "This is where you would describe the secret for the user to understand."
privileges:
- READ
object_type: SECRET
register_callback: config.register_reference
configuration_callback: config.get_config_for_ref
- eai_example:
label: "Example EAI"
description: "This is where you would describe the EAI for the user."
privileges:
- USAGE
object_type: EXTERNAL ACCESS INTEGRATION
register_callback: config.register_reference
configuration_callback: config.get_config_for_ref
required_at_setup: true
2. Creating Callback Procedures:
In the previous step you will notice that there are two properties existing in both references, register_callback and configuration_callback. This property tells Snowflake which procedures to use to bind the reference and to send proper configuration of the reference to the UI respectively.
We will create these procedures in the setup script as shown below. Note that in this example we will use the URL table to pass inputs to the configuration callback procedure.
CREATE OR ALTER VERSIONED SCHEMA CONFIG;
GRANT USAGE ON SCHEMA CONFIG TO APPLICATION ROLE EXAMPLE_APPLICATION_ROLE;
CREATE OR REPLACE PROCEDURE config.register_reference(ref_name STRING, operation STRING, ref_or_alias STRING)
RETURNS STRING
LANGUAGE SQL
AS
$$
BEGIN
CASE (operation)
WHEN 'ADD' THEN
SELECT SYSTEM$SET_REFERENCE(:ref_name, :ref_or_alias);
WHEN 'REMOVE' THEN
SELECT SYSTEM$REMOVE_REFERENCE(:ref_name);
WHEN 'CLEAR' THEN
SELECT SYSTEM$REMOVE_REFERENCE(:ref_name);
ELSE
RETURN 'unknown operation: ' || operation;
END CASE;
RETURN '';
END;
$$;
GRANT USAGE ON PROCEDURE config.register_reference(STRING, STRING, STRING) TO APPLICATION ROLE EXAMPLE_APPLICATION_ROLE;
-- Table to dynamically set the EAI url
CREATE OR REPLACE TABLE CONFIG.URL (
REF_NAME VARCHAR,
URL VARCHAR
);
-- Create configuration callback function for external access integrations and secrets
CREATE OR REPLACE PROCEDURE config.get_config_for_ref(ref_name STRING)
returns string
language python
runtime_version=3.11
packages=('snowflake-snowpark-python')
handler='main'
as $$
from snowflake.snowpark import Session
from snowflake.snowpark.functions import col
import json
def main(session:Session,ref_name:str):
try:
ref_type = ref_name.split('_')[0].lower()
if ref_type == 'secret':
return get_secret_config()
elif ref_type == 'eai':
return get_eai_config(session,ref_name)
else:
return get_error_config('No reference type found in config callback function.')
except Exception as e:
return get_error_config(str(e))
def get_error_config(message):
config = {
"type": "ERROR",
"payload":{
"message": message
}
}
return json.dumps(config)
def get_secret_config():
config = {
"type": "CONFIGURATION",
"payload":{
"type" : "GENERIC_STRING" # Value may be replaced with "PASSWORD" for a username and password type secret
}
}
return json.dumps(config)
def get_eai_config(session,ref_name):
url = session.table('config.url').filter(col('ref_name')==ref_name.upper()).select(col('url')).collect()[0][0]
config = {
"type": "CONFIGURATION",
"payload": {
"host_ports": [url],
"allowed_secrets": "ALL"
}
}
return json.dumps(config)
$$;
GRANT USAGE ON PROCEDURE config.get_config_for_ref(STRING) TO APPLICATION ROLE EXAMPLE_APPLICATION_ROLE;
3. Request a Reference from the UI
The last step is to request a reference from the user through the Streamlit UI. We do this by calling the request_reference function in the snowflake permissions library.
Here we are using a simple button click to trigger the request. There is one complication here however, we must gather the URL from the user and store it in our URL table first. This is only required if the URL needs to be dynamic, otherwise this is not necessary.
import streamlit as st
from snowflake.snowpark.context import get_active_session
from snowflake.snowpark.functions import col
from snowflake.permissions import request_reference
session = get_active_session()
def insert_or_update(ref_name:str, url:str):
ref_name = ref_name.upper()
url_table = session.table('config.url')
existing_url = url_table.filter(col('ref_name')==ref_name).select(col('url')).collect()
if len(existing_url) > 0:
url_table.update({'URL': url},col('ref_name') == ref_name)
else:
session.sql(f"insert into config.url values ('{ref_name}','{url}')").collect()
def configure_secret():
request_reference(f'secret_example')
st.session_state[f'secret_configured'] = True
def configure_eai(ref_name:str):
request_reference(f'eai_example')
st.session_state[f'eai_configured'] = True
st.title('Configuration Example')
url = st.text_input('Enter the desired URL here:')
st.button('Insert URL', on_click=insert_or_update, args=('eai_example', url,))
st.button('Create Secret', on_click=configure_secret)
st.button('Create EAI', on_click=configure_eai, args=('eai_example',))
4. Attach the EAI to a Stored Procedure
Once the user completes the process of binding the variables, the app must then attach the EAI reference to a stored procedure. See a simple example below:
session.sql(f"""
ALTER PROCEDURE UTILITY.EXAMPLE_PROC(VARCHAR) SET
EXTERNAL_ACCESS_INTEGRATIONS = (reference(‘EAI_EXAMPLE'))
SECRETS = ('config' = reference('SECRET_EXAMPLE'))
""").collect()
Securely Accessing External Endpoints in Action
Now let’s run it! After installing the app in our Snowflake environment we should land on the following screen.

Here we will enter our URL for the EAI to use and then click, ‘Insert URL’. After doing so we can click ‘Create Secret’ and the secret binding dialog box will appear. The user can then complete the form in the dialog box and the secret reference will be bound!

Next we will do the same with the ‘Create EAI’ button. The EAI reference will be created and bound!

Behind the scenes our application will then bind this EAI to a UDF or stored procedure. In doing so the procedure or UDF may now access external endpoints!
6. Final Thoughts: Building for Speed Without Sacrificing Sanity
There we have it, a complete end to end guide on using EAI and secret references in Snowflake specifically focused on dynamically setting the EAI configuration and using generic string and password type secrets.
Successfully building Snowflake Native Apps that interact with external endpoints—and still meet Snowflake Marketplace’s security standards—can be complex. But with the right setup, dynamic configuration, and proper use of references, it’s entirely achievable.
At Hakkoda, we specialize in making the complex feel simple without sacrificing secure, complaint solution-building. So whether you’re building your first Snowflake Native App or looking to scale your existing data products securely and efficiently, our team has the experience to help you do it right.
Looking for more expert help building your Snowflake Native App? Let’s talk.