Connect Snowflake
This page is for your Snowflake administrator. It covers everything run in Snowflake to connect one database to Nexatron. The workspace admin's side (adding the connection, choosing who can use it) is in the Pilot quick start.
Nexatron generates the setup script for each connection, with your names filled
in. Run the copy Nexatron shows you. The statements below show its shape with
placeholders: ANALYTICS is the database, NEXATRON_WH the warehouse,
NEXATRON_SVC the setup user.
When the workspace admin isn't the Snowflake admin
The workspace admin doesn't have to wait for you. When they generate a key in the
connect dialog, Nexatron fills in the script; they can copy it or download it as a
.sql file and send it to you, then save the connection straight away. Until you
run the script, the connection's page says Nexatron can't sign in yet and keeps
the same script there. Once you've run it, they select Check again on that page,
and setup can start.
Two identities
| Identity | What it is | What it does |
|---|---|---|
| Setup identity | A TYPE = SERVICE user that signs in with a key pair, with the role NEXATRON_SETUP | Reads metadata, profiles values and, if you grant it, reads query history, so Nexatron can learn the database. It never answers anyone's question. |
| Each person's own login | The person's own Snowflake user, through OAuth: a Snowflake OAuth security integration, or External OAuth through your Okta or Microsoft Entra ID | Every question runs as the person who asked. Snowflake applies that person's roles, row access policies and masking policies. |
There is no shared login and no "view as". Nexatron can link a person to another Snowflake user only in development and test environments; a production Nexatron refuses it. In production each person signs in with their own login.
What setup reads and what Nexatron keeps
| Setup reads | Nexatron keeps |
|---|---|
Metadata: databases, schemas, tables, views and columns (INFORMATION_SCHEMA), and which row access and masking policies apply (POLICY_REFERENCES) | The catalog metadata |
Values, with SELECT on the tables in scope: row, null and distinct counts, minimum and maximum per column, and the values of text columns with at most 50 distinct values | Those counts, ranges and value lists, so questions can name values ("West", "won") |
Query history, if you grant GOVERNANCE_VIEWER: the last 14 days of successful SELECTs on this database, read in memory | Query shapes with literals removed (except a small value list's own values), to learn common joins and filters |
Nexatron never keeps result rows or query text. From a table with a row access
policy, or a masked column, it keeps nothing beyond counts. Setup can only detect
those policies with SNOWFLAKE.GOVERNANCE_VIEWER (part 4): SELECT alone does
not show them, and without part 4 setup keeps values as the setup role sees them.
Before the grants: a dedicated warehouse
Create the warehouse first; the setup script grants USAGE on it. A resource
monitor caps its credits.
-- SYSADMIN (or a role with CREATE WAREHOUSE)
USE ROLE SYSADMIN;
CREATE WAREHOUSE IF NOT EXISTS NEXATRON_WH
WAREHOUSE_SIZE = XSMALL
AUTO_SUSPEND = 60
AUTO_RESUME = TRUE
INITIALLY_SUSPENDED = TRUE
COMMENT = 'Nexatron setup and questions';
-- ACCOUNTADMIN only: resource monitors
USE ROLE ACCOUNTADMIN;
CREATE RESOURCE MONITOR IF NOT EXISTS NEXATRON_MONITOR
WITH CREDIT_QUOTA = 100
FREQUENCY = MONTHLY
START_TIMESTAMP = IMMEDIATELY
TRIGGERS ON 75 PERCENT DO NOTIFY
ON 100 PERCENT DO SUSPEND
ON 110 PERCENT DO SUSPEND_IMMEDIATE;
ALTER WAREHOUSE NEXATRON_WH SET RESOURCE_MONITOR = NEXATRON_MONITOR;
Pick the credit quota for your account. Resource monitor notifications reach
only users who have turned them on in Snowsight. People's questions run on the
connection's warehouse with their own role, so their roles also need USAGE on it
(see People need their own roles).
The grants, in four parts
Each part names the role that can run it. Parts 1 to 3 are required; part 4 is
optional and recommended. IMPORTED PRIVILEGES ON DATABASE SNOWFLAKE is not
needed: it would expose every ACCOUNT_USAGE view, billing and logins included.
| Part | What | Who can run it |
|---|---|---|
| 1 | Role and service user | USERADMIN, or a role with CREATE ROLE and CREATE USER |
| 2 | Read access to what exists | The role that owns the database and its tables, or SECURITYADMIN; USAGE on the warehouse needs its owner or SECURITYADMIN |
| 3 | Read access to what is created later (future grants) | SECURITYADMIN, or a role with MANAGE GRANTS (in a managed access schema, also its owner) |
| 4 | Query history and policies; people's sign-in | ACCOUNTADMIN |
Part 1: role and service user
USE ROLE USERADMIN;
CREATE ROLE IF NOT EXISTS NEXATRON_SETUP COMMENT = 'Nexatron setup: reads metadata, values and query history; answers no one';
GRANT ROLE NEXATRON_SETUP TO ROLE SYSADMIN;
CREATE USER IF NOT EXISTS NEXATRON_SVC TYPE = SERVICE DEFAULT_ROLE = NEXATRON_SETUP DEFAULT_WAREHOUSE = NEXATRON_WH
COMMENT = 'Nexatron setup identity (key pair)';
-- Nexatron's key goes in the second slot, so the first stays free for a rotation (and the other way round)
ALTER USER NEXATRON_SVC SET RSA_PUBLIC_KEY_2 = '<NEXATRON_PUBLIC_KEY>';
GRANT ROLE NEXATRON_SETUP TO USER NEXATRON_SVC;
Parts 2 and 3: the whole database
-- Part 2: read access to what exists
USE ROLE SECURITYADMIN;
GRANT USAGE ON WAREHOUSE NEXATRON_WH TO ROLE NEXATRON_SETUP;
GRANT USAGE ON DATABASE ANALYTICS TO ROLE NEXATRON_SETUP;
GRANT USAGE ON ALL SCHEMAS IN DATABASE ANALYTICS TO ROLE NEXATRON_SETUP;
GRANT SELECT ON ALL TABLES IN DATABASE ANALYTICS TO ROLE NEXATRON_SETUP;
GRANT SELECT ON ALL VIEWS IN DATABASE ANALYTICS TO ROLE NEXATRON_SETUP;
GRANT SELECT ON ALL MATERIALIZED VIEWS IN DATABASE ANALYTICS TO ROLE NEXATRON_SETUP;
-- Part 3: read access to what is created later
USE ROLE SECURITYADMIN;
GRANT USAGE ON FUTURE SCHEMAS IN DATABASE ANALYTICS TO ROLE NEXATRON_SETUP;
GRANT SELECT ON FUTURE TABLES IN DATABASE ANALYTICS TO ROLE NEXATRON_SETUP;
GRANT SELECT ON FUTURE VIEWS IN DATABASE ANALYTICS TO ROLE NEXATRON_SETUP;
GRANT SELECT ON FUTURE MATERIALIZED VIEWS IN DATABASE ANALYTICS TO ROLE NEXATRON_SETUP;
Parts 2 and 3: named schemas only
Scoping to named schemas is how you give Nexatron one part of one database. This
example covers ANALYTICS.SALES and ANALYTICS.FINANCE:
-- Part 2: read access to what exists
USE ROLE SECURITYADMIN;
GRANT USAGE ON WAREHOUSE NEXATRON_WH TO ROLE NEXATRON_SETUP;
GRANT USAGE ON DATABASE ANALYTICS TO ROLE NEXATRON_SETUP;
GRANT USAGE ON SCHEMA ANALYTICS.SALES TO ROLE NEXATRON_SETUP;
GRANT SELECT ON ALL TABLES IN SCHEMA ANALYTICS.SALES TO ROLE NEXATRON_SETUP;
GRANT SELECT ON ALL VIEWS IN SCHEMA ANALYTICS.SALES TO ROLE NEXATRON_SETUP;
GRANT SELECT ON ALL MATERIALIZED VIEWS IN SCHEMA ANALYTICS.SALES TO ROLE NEXATRON_SETUP;
GRANT USAGE ON SCHEMA ANALYTICS.FINANCE TO ROLE NEXATRON_SETUP;
GRANT SELECT ON ALL TABLES IN SCHEMA ANALYTICS.FINANCE TO ROLE NEXATRON_SETUP;
GRANT SELECT ON ALL VIEWS IN SCHEMA ANALYTICS.FINANCE TO ROLE NEXATRON_SETUP;
GRANT SELECT ON ALL MATERIALIZED VIEWS IN SCHEMA ANALYTICS.FINANCE TO ROLE NEXATRON_SETUP;
-- Part 3: read access to what is created later
USE ROLE SECURITYADMIN;
GRANT SELECT ON FUTURE TABLES IN SCHEMA ANALYTICS.SALES TO ROLE NEXATRON_SETUP;
GRANT SELECT ON FUTURE VIEWS IN SCHEMA ANALYTICS.SALES TO ROLE NEXATRON_SETUP;
GRANT SELECT ON FUTURE MATERIALIZED VIEWS IN SCHEMA ANALYTICS.SALES TO ROLE NEXATRON_SETUP;
GRANT SELECT ON FUTURE TABLES IN SCHEMA ANALYTICS.FINANCE TO ROLE NEXATRON_SETUP;
GRANT SELECT ON FUTURE VIEWS IN SCHEMA ANALYTICS.FINANCE TO ROLE NEXATRON_SETUP;
GRANT SELECT ON FUTURE MATERIALIZED VIEWS IN SCHEMA ANALYTICS.FINANCE TO ROLE NEXATRON_SETUP;
Future grant precedence. If a schema has future grants of its own for an object type, Snowflake ignores the database-level future grants for that type in that schema. For such a schema, add the schema-level future grants above as well.
Part 4: query history and policies (optional, recommended)
USE ROLE ACCOUNTADMIN;
GRANT DATABASE ROLE SNOWFLAKE.GOVERNANCE_VIEWER TO ROLE NEXATRON_SETUP;
GOVERNANCE_VIEWER lets setup see which tables have row access or masking
policies, so it keeps no values from them, and read query and access history, so
it learns the joins and filters people use. Without it setup still runs, without
those. People's sign-in integration, also ACCOUNTADMIN (or a role with
CREATE INTEGRATION), is the next section.
People's sign-in
Choose one. Both give each person their own Snowflake session; neither grants Nexatron data access of its own.
Snowflake OAuth
Nexatron shows this statement under Snowflake sign-in on the connection's page, with the integration name and redirect URI filled in. Copy it from there.
USE ROLE ACCOUNTADMIN;
CREATE SECURITY INTEGRATION IF NOT EXISTS NEXATRON_OAUTH_<CONNECTION_KEY>
TYPE = OAUTH
ENABLED = TRUE
OAUTH_CLIENT = CUSTOM
OAUTH_CLIENT_TYPE = 'CONFIDENTIAL'
OAUTH_REDIRECT_URI = 'https://<NEXATRON_HOST>/connections/<CONNECTION_ID>/snowflake-callback'
OAUTH_ENFORCE_PKCE = TRUE
OAUTH_ISSUE_REFRESH_TOKENS = TRUE
OAUTH_REFRESH_TOKEN_VALIDITY = 7776000
OAUTH_USE_SECONDARY_ROLES = IMPLICIT
BLOCKED_ROLES_LIST = ('ACCOUNTADMIN', 'SECURITYADMIN', 'ORGADMIN');
-- Copy OAUTH_CLIENT_ID and OAUTH_CLIENT_SECRET from this result into Nexatron:
SELECT SYSTEM$SHOW_OAUTH_CLIENT_SECRETS('NEXATRON_OAUTH_<CONNECTION_KEY>');
Paste the client ID and secret into Nexatron's sign-in settings. Every sign-in
uses an authorization code with PKCE. ACCOUNTADMIN, SECURITYADMIN and
ORGADMIN cannot be used through it. A person stays signed in for up to 90 days.
External OAuth (Okta or Microsoft Entra ID)
Your identity provider issues the Snowflake tokens, so people sign in once with the login they already use. That single sign-in is why enterprises usually prefer it. It needs your identity team for the provider side.
In Okta (an API Access Management authorization server):
- Create an authorization server, or use an existing custom one. Set its
Audience to your Snowflake account URL,
https://<ACCOUNT>.snowflakecomputing.com. - Add the scope
session:role-any. The person's default role is used. - Create a web app integration for Nexatron with the Authorization Code and Refresh Token grants, and the redirect URI from Nexatron's sign-in settings.
- Add an access policy rule for that app allowing
session:role-anyandoffline_access(the refresh token). - Make sure the token claim Nexatron reads holds each person's Snowflake
LOGIN_NAME. By default that issub(the Okta username); use a custom claim if the two differ. - Give Nexatron the issuer (
https://<OKTA_DOMAIN>/oauth2/<SERVER_ID>), the client ID and secret, and the claim name.
In Microsoft Entra ID (two app registrations):
- A resource app for Snowflake: under Expose an API, set the Application ID
URI (for example
api://<APP_ID>) and add the delegated scopesession:role-any. - A client app for Nexatron: a web redirect URI from Nexatron's sign-in settings,
a client secret, and the delegated API permission to that scope, with admin
consent. Nexatron asks for
api://<APP_ID>/session:role-any offline_access. - Each person's
upnmust equal their SnowflakeLOGIN_NAME(or choose another claim that does). - The token's audience is the Application ID URI, so it goes in
EXTERNAL_OAUTH_AUDIENCE_LIST. Snowflake always accepts the account URL as well.
Then, in Snowflake (ACCOUNTADMIN, or a role with CREATE INTEGRATION):
USE ROLE ACCOUNTADMIN;
CREATE SECURITY INTEGRATION IF NOT EXISTS NEXATRON_EXT_OAUTH_<CONNECTION_KEY>
TYPE = EXTERNAL_OAUTH
ENABLED = TRUE
EXTERNAL_OAUTH_TYPE = OKTA -- AZURE for Microsoft Entra ID
EXTERNAL_OAUTH_ISSUER = '<ISSUER>'
-- Okta: https://<OKTA_DOMAIN>/oauth2/<SERVER_ID>
-- Entra: https://sts.windows.net/<TENANT_ID>/ (match the token's iss exactly)
EXTERNAL_OAUTH_JWS_KEYS_URL = '<JWKS_URL>'
-- Okta: https://<OKTA_DOMAIN>/oauth2/<SERVER_ID>/v1/keys
-- Entra: https://login.microsoftonline.com/<TENANT_ID>/discovery/v2.0/keys
EXTERNAL_OAUTH_AUDIENCE_LIST = ('<AUDIENCE>')
-- Okta: https://<ACCOUNT>.snowflakecomputing.com Entra: api://<APP_ID>
EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = 'sub' -- 'upn' for Entra
EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'LOGIN_NAME'
EXTERNAL_OAUTH_ANY_ROLE_MODE = 'ENABLE'
EXTERNAL_OAUTH_BLOCKED_ROLES_LIST = ('ACCOUNTADMIN', 'SECURITYADMIN', 'ORGADMIN', 'GLOBALORGADMIN');
Nexatron's sign-in settings generate this statement with your values and the
connection's own integration name (NEXATRON_EXT_OAUTH_ and eight characters of
the connection's id). The values are case-sensitive and must match your provider exactly. Snowflake
checks the token; Nexatron only reads the login name from it to connect as.
People need their own roles
Nexatron sees only what the asking person's own role can see. Grant your business
roles what they should ask about, including USAGE on the connection's warehouse:
USE ROLE SECURITYADMIN;
GRANT USAGE ON WAREHOUSE NEXATRON_WH TO ROLE SALES_ANALYST;
GRANT USAGE ON DATABASE ANALYTICS TO ROLE SALES_ANALYST;
GRANT USAGE ON SCHEMA ANALYTICS.SALES TO ROLE SALES_ANALYST;
GRANT SELECT ON ALL TABLES IN SCHEMA ANALYTICS.SALES TO ROLE SALES_ANALYST;
GRANT SELECT ON FUTURE TABLES IN SCHEMA ANALYTICS.SALES TO ROLE SALES_ANALYST;
GRANT ROLE SALES_ANALYST TO USER <PERSON>;
-- The role a session starts with, and the other granted roles that also apply
USE ROLE USERADMIN; -- or the user's owner
ALTER USER <PERSON> SET DEFAULT_ROLE = SALES_ANALYST DEFAULT_SECONDARY_ROLES = ('ALL');
A session uses the person's DEFAULT_ROLE. With Snowflake OAuth
(OAUTH_USE_SECONDARY_ROLES = IMPLICIT) their default secondary roles apply too,
as in Snowsight. The blocked roles (ACCOUNTADMIN, SECURITYADMIN, ORGADMIN)
are never used through Nexatron, so give people a non-privileged default role.
ALTER USER needs the user's owner (often USERADMIN) or SECURITYADMIN.
Network policy
Allow Nexatron's egress IP addresses for the setup user. Nexatron's connection page
shows them, or Nexatron support provides them for your region; <NEXATRON_EGRESS_IP> is a
placeholder. Network rules live in a schema you choose (SECURITY_DB.RULES here).
-- SECURITYADMIN, or a role with CREATE NETWORK POLICY on the account
-- and CREATE NETWORK RULE on the schema
USE ROLE SECURITYADMIN;
CREATE NETWORK RULE SECURITY_DB.RULES.NEXATRON_EGRESS
MODE = INGRESS
TYPE = IPV4
VALUE_LIST = ('<NEXATRON_EGRESS_IP>', '<NEXATRON_EGRESS_IP>');
CREATE NETWORK POLICY NEXATRON_POLICY
ALLOWED_NETWORK_RULE_LIST = ('SECURITY_DB.RULES.NEXATRON_EGRESS');
ALTER USER NEXATRON_SVC SET NETWORK_POLICY = NEXATRON_POLICY;
People's OAuth sessions also connect from Nexatron's servers. If your account has an account-level network policy, or people have user-level policies, add Nexatron's egress IPs there too, or people's questions are refused. A network policy set on the sign-in security integration overrides both for those sessions.
Rotate the setup key
The user has two key slots. Nexatron's key starts in RSA_PUBLIC_KEY_2, leaving
RSA_PUBLIC_KEY free.
-
Get Nexatron's new public key for the connection and put it in the free slot:
USE ROLE USERADMIN;ALTER USER NEXATRON_SVC SET RSA_PUBLIC_KEY = '<NEW_PUBLIC_KEY>'; -
Switch Nexatron to the new key. Both keys work in the meantime.
-
Remove the old one:
ALTER USER NEXATRON_SVC UNSET RSA_PUBLIC_KEY_2;
Next time, alternate: the new key goes in RSA_PUBLIC_KEY_2, then unset
RSA_PUBLIC_KEY.
To check which key is set, compare fingerprints:
DESC USER NEXATRON_SVC;
-- RSA_PUBLIC_KEY_FP and RSA_PUBLIC_KEY_2_FP show SHA256:<fingerprint>
openssl rsa -pubin -in rsa_key.pub -outform DER | openssl dgst -sha256 -binary | openssl enc -base64
Checklist
-
NEXATRON_WHcreated, resource monitor attached - Parts 1 to 3 run; part 4 run if you want policy detection and query history
- One sign-in integration created, and its values entered in Nexatron
- Business roles have
USAGEon the warehouse, database and schemas, andSELECTon what they ask about - Nexatron's egress IPs allowed for the setup user, and in any account or user network policy
Troubleshooting
| Symptom | Likely cause |
|---|---|
Object does not exist or not authorized | The role lacks USAGE on the database, schema or warehouse, or SELECT on the object. For tables created after setup: a schema-level future grant overrides the database-level one, so grant on that schema too. For a person, check their own role, not NEXATRON_SETUP. |
JWT token is invalid for the setup user | The key Nexatron uses is in neither slot (compare fingerprints with DESC USER), or the clock on the signing side is skewed: Snowflake rejects a token received more than 60 seconds after it was issued. SYSTEM$GET_LOGIN_FAILURE_DETAILS('<UUID>') gives the exact reason. |
Incoming request with IP/Token ... is not allowed | A network policy does not include Nexatron's egress IPs. |
| A person's sign-in or question fails with a role error | Their default role is one of the blocked roles, or is not granted to them. |
| External OAuth: user not found | The mapping claim does not equal the person's LOGIN_NAME, or the issuer or audience does not match the token exactly. |
| Setup keeps no values from some tables | Those tables have row access or masking policies. This is expected. |