Connecting to Snowflake
Prerequisites
- PuppyGraph version 1.0 or higher.
- The Snowflake instance is accessible over the network from the PuppyGraph instance.
Overview
PuppyGraph supports connecting to Snowflake in three ways:
- Connecting with key-pair authentication
- Connecting with OAuth 2.0 client credentials
- Connecting with a JDBC connection string
Snowflake query impersonation can be enabled on top of these connection
methods. PuppyGraph still connects to Snowflake through one service account,
but before sending SQL queries to Snowflake it establishes the current user's
identity on the connection through a stored procedure you provide, in one of
two modes: proxyUser calls a proxy-user procedure with the SSO user's name,
and sessionClaims calls a claim-set procedure with claims taken from the
user's verified token, one Snowflake session variable per claim. Your access
controls then read that session state. See
Query impersonation for SSO users.
Connecting with key-pair authentication
See Querying Snowflake Data as a Graph for a complete demo. The demo includes setting up the connection to a Snowflake database with key-pair authentication.
Connecting with OAuth 2.0 client credentials
This option is suitable if your Snowflake instance already has an OAuth 2.0 integration.
Configuration
| Configuration | Explanation |
|---|---|
| Snowflake Auth Type | OAuth (client credentials) |
| Snowflake Server URL | https://<account_identifier>.snowflakecomputing.com |
| Snowflake Database Name | Name of the Snowflake database to connect to. |
| Snowflake Warehouse Name | Name of the Snowflake warehouse to connect to. |
| OAuth Client ID | The client ID issued by the OAuth 2.0 identity provider. |
| OAuth Client Secret | The client secret issued by the OAuth 2.0 identity provider. |
| OAuth Token Request URL | The token endpoint URL of the OAuth 2.0 identity provider. |
| OAuth Scope (optional) | The OAuth 2.0 scope to request. Required only if the identity provider enforces scope. |
Connecting with a JDBC connection string
If you prefer to supply the full connection string manually, choose JDBC authentication as the Auth Type and provide a JDBC URL. The example below configures OAuth 2.0 client credentials:
jdbc:snowflake://<account_identifier>.snowflakecomputing.com/?
authenticator=oauth_client_credentials
&oauthClientId=<client_id>
&oauthClientSecret=<client_secret>
&oauthTokenRequestUrl=<token_endpoint_url>
&oauthScope=<scope>
&db=<DATABASE>
&warehouse=<WAREHOUSE>
&role=<ROLE>
Username and password are not used when JDBC authentication is selected.
Query impersonation for SSO users
Use Snowflake query impersonation when the same PuppyGraph graph should return
different Snowflake rows for different SSO users. In mode proxyUser the
pattern is:
- PuppyGraph authenticates the user through SSO.
- PuppyGraph reads the configured SSO user claim, such as
preferred_username. - Before sending SQL queries to Snowflake, PuppyGraph calls the configured proxy-user stored procedure with that user value.
- Snowflake evaluates the query under the user context set by that procedure and returns the corresponding result.
In mode sessionClaims steps 1 to 3 differ: the user authenticates with a
bearer token from a trusted issuer, PuppyGraph projects the claims the catalog
lists out of that verified token, and before every scan it calls the configured
claim-set procedure with them so Snowflake sets one session variable per claim.
See Session claims.
For a complete runnable example with Keycloak, Snowflake, and validation queries, see Setting Up Snowflake User Impersonation for SSO.
Snowflake requirements
Prepare these objects and privileges in Snowflake before enabling the catalog:
| Requirement | Details |
|---|---|
| Service account | The Snowflake user that PuppyGraph uses to connect. It can authenticate with key-pair authentication, OAuth, or a manually supplied JDBC URL. |
| Proxy-user stored procedure | In mode proxyUser, the Snowflake stored procedure configured by identityPropagation.proxyUserProcedure. It accepts one string parameter: the current PuppyGraph SSO user value. The procedure should set the Snowflake user context used by your access-control logic. |
| Claim-set stored procedure | In mode sessionClaims, the procedure configured by identityPropagation.claimSetProcedure. It accepts one VARCHAR holding a JSON object such as {"set": {"TENANT_ID": "t-42"}, "unset": ["TENANT_ID", "ADVISOR_ID"]} (unset lists every allow-listed variable, set the ones the token carries), must UNSET every listed variable before it SETs the present ones, and returns a JSON array naming the variables it set. |
| Procedure privilege | The service account's role needs USAGE on the configured stored procedure (Snowflake's procedure privilege; there is no EXECUTE grant) and USAGE on the database and schema that contain it, never ownership. |
| Table privileges | The service account must be able to query the Snowflake tables referenced by the graph schema. Scope SELECT to exactly those tables: policies narrow what the service account can see, so a table without a policy is fully visible through it. |
| Warehouse privilege | The service account must be able to use the configured warehouse. |
| Snowflake access controls | Snowflake policies, secure views, or equivalent controls should read the session state the configured procedure sets: the proxy-user variable in mode proxyUser, the claim variables (GETVARIABLE('TENANT_ID') for claim tenant_id) in mode sessionClaims. |
For example, if PuppyGraph should call:
then the procedure must accept the current user value as its only argument and must be executable by the service account.
PuppyGraph requirements
In mode proxyUser, enable SSO for PuppyGraph and choose the claim that should
be passed to Snowflake (in mode sessionClaims this setting plays no part:
users present a trusted issuer's bearer token, and the catalog's claims list
selects what is projected):
With this configuration, if the SSO token contains
preferred_username: alice, PuppyGraph passes alice to the Snowflake
procedure.
Schema configuration
Add an identityPropagation block to the Snowflake catalog, beside jdbc,
with mode set to proxyUser and the fully qualified Snowflake proxy-user
stored procedure name as proxyUserProcedure. Schemas from earlier releases
carry the same setting as jdbc.queryImpersonation.proxyUserProcedure; they
keep working and read as mode proxyUser.
Use the identifier form that matches how the Snowflake procedure was created. Snowflake resolves unquoted identifiers in uppercase, so a procedure created with regular unquoted identifiers can be configured without double quotes:
If a customer omits double quotes for a procedure created with regular
unquoted identifiers, the configuration still works because Snowflake resolves
each identifier in uppercase. Double quotes are needed only when Snowflake must
receive the exact quoted identifier, for example because the procedure was
created with case-sensitive, mixed-case, lowercase, or special-character
identifiers. Because the schema value is a JSON string, each double quote that
should be sent to Snowflake must be escaped as \". If the configured value
does not match the Snowflake identifier, Snowflake cannot find the procedure.
{
"catalog": [
{
"name": "snowflake_data",
"type": "snowflake",
"jdbc": {
"username": "<service_account_username>",
"jdbcUri": "jdbc:snowflake://<account_identifier>.snowflakecomputing.com/?db=<DATABASE>&warehouse=<WAREHOUSE>&private_key_file=/home/keys/snowflake_rsa_key.p8&private_key_file_pwd=<private_key_password>",
"driverClass": "net.snowflake.client.jdbc.SnowflakeDriver"
},
"identityPropagation": {
"mode": "proxyUser",
"proxyUserProcedure": "\"PUPPYGRAPH_SECURITY\".\"UTIL\".\"SET_PROXY_USER\""
}
}
]
}
Metadata caching (jdbc.enableMetaCache) can stay at its default with either
mode: Snowflake policies filter rows, not metadata, so table and column
metadata is the same for every user. jdbc.enableDataCache cannot be "true"
with sessionClaims.
After the schema is uploaded, sign in through SSO before running data queries. Local PuppyGraph users do not have an SSO identity to pass to Snowflake, so queries against an impersonation-enabled Snowflake catalog are rejected.
Session claims
Mode sessionClaims passes the claims of the user's verified JWT to Snowflake
as session variables instead of one proxy-user name. The user presents a
trusted issuer's token as a bearer token on the HTTP API, the REST Cypher
endpoint, Bolt or the Gremlin WebSocket (a browser SSO session does not carry
the claims yet); PuppyGraph verifies it against the issuer registered with
POST /api/trusted-issuers, keeps only the claims listed on the catalog, and
before every scan calls the claim-set procedure on the connection that runs
it. Each claim becomes the session variable UPPER(claim), so a policy reads
GETVARIABLE('TENANT_ID') for the tenant_id claim. A query whose user lacks
a required claim fails with error IDP-02 before any scan; an optional claim
the user lacks is simply not set.
"identityPropagation": {
"mode": "sessionClaims",
"claimSetProcedure": "\"PUPPYGRAPH_SECURITY\".\"UTIL\".\"SET_SESSION_CLAIMS\"",
"claims": [
{ "claim": "tenant_id", "required": true },
{ "claim": "advisor_id", "required": false }
]
}
Claim names must map onto distinct valid variable names
(^[A-Z_][A-Z0-9_]*$ after upper-casing), registered JWT claims such as iss
and exp cannot be listed, and a catalog lists between 1 and 16 claims. For
the procedure contract and a worked example, see
Setting Up Snowflake User Impersonation for SSO.