Skip to main content
Restrict which rows each Jedify end-user can see in a Snowflake table using Snowflake’s native row access policies. Jedify connects to Snowflake through a single service user (see Snowflake Data Connector), but it forwards each end-user’s identity to Snowflake on every query — so policies can filter rows per user without giving each user their own Snowflake login.

How it works

Jedify supports two complementary mechanisms for passing the end-user’s identity to a row access policy:
  1. Session variables. Jedify forwards a fixed set of session variables identifying the requester (JEDIFY_USER_EMAIL, JEDIFY_USER_NAME, JEDIFY_USER_ROLE, JEDIFY_USER_SNOWFLAKE_ROLE) on every query. The policy reads them via SESSION_CONTEXT('<NAME>'). Requires SSO, since the values are picked up from the SSO sign-in. See Session context for the full reference.
  2. Snowflake role. Each Jedify user is mapped to a specific Snowflake role, and Jedify switches the session to that role before each query. The policy reads CURRENT_ROLE(). Works with or without SSO — with SSO, Jedify maps your IdP groups to Snowflake roles automatically; without SSO, an admin assigns the role per user.
You can use either approach in isolation or combine them in a single policy.

Session variables and user attributes

For every query run on behalf of a signed-in end-user, Jedify sets a fixed set of session variables in Snowflake that identify the requester. Row access policies read them via SESSION_CONTEXT('<NAME>') and use them to filter rows. See Session context below for the full list of variables Jedify sets.
Variable names are case-sensitive when read. Snowflake stores session variables uppercased, so SESSION_CONTEXT('JEDIFY_USER_EMAIL') returns the value while SESSION_CONTEXT('jedify_user_email') returns NULL. The same applies to GETVARIABLE. The SET statement itself is case-insensitive.
This mechanism relies on values supplied at SSO sign-in. If your users don’t sign in through SSO, attribute values aren’t propagated automatically — use the per-user Snowflake role approach below instead.
If the value you want to filter on isn’t a column on the protected table — for example, a separate table maps users to the allowed values — see Example 3 below for the lookup pattern.

Per-user Snowflake role

Each Jedify user can be mapped to a specific Snowflake role. Before each query, Jedify executes USE ROLE <role> so policies can read CURRENT_ROLE() directly. The Jedify service user must already be granted every role you intend to use (see Snowflake Data Connector). The mapping is configured either:
  • Via SSO — Jedify maps identity-provider groups to Snowflake roles, and each user automatically gets the role corresponding to their group membership at sign-in.
  • Without SSO — an admin assigns a Snowflake role to each user directly in user management.

Session context

Before each query, Jedify sets the following session variables in Snowflake. Reference them inside row access policies via SESSION_CONTEXT('<NAME>') — names must match exactly (uppercase). To simulate a Jedify-driven session when testing a policy in Snowflake, SET the variable yourself before issuing the SELECT. For example:

Example table

The examples below filter the following table. Adapt the database, schema, and role names to your own setup.
We also recommend keeping policies in a dedicated schema:
A table can only have one row access policy at a time. Drop the previous policy before adding a different one:

Example 1: Filter by a custom user attribute

Use this example when each row already carries the identity of the user it belongs to (an email column, an owner column, and so on). The policy compares that column to SESSION_CONTEXT('JEDIFY_USER_EMAIL'), with a bypass for users whose Jedify role is Tenant Admin. The example below filters USER_EVENTS so each end-user only sees rows where the USER_EMAIL column matches their own email. Tenant Admins see everything.

1. Create the row access policy

2. Attach the policy to the table

The ON (...) clause binds the policy’s user_email argument to the table’s USER_EMAIL column. The order must match the policy signature.

3. Verify the policy

Simulate a Jedify session as bob (a regular user) and then as a Tenant Admin:

Example 2: Filter by Snowflake role

Use this example when access groups already correspond to Snowflake roles (for example, one role per department). The policy reads CURRENT_ROLE() instead of a session variable, and Jedify switches into the right role per user via the snowflake_role user attribute.

1. Create the department-scoped roles

2. Grant baseline privileges to each role

Every department role needs the same compute/database/schema/table grants — only the row filter differs.

3. Create the row access policy

This policy lets the Jedify base role see all rows, and restricts each department role to its own rows.

4. Attach the policy to the table

5. Map Jedify users to the right Snowflake role

Map each Jedify user to one of BLUEPEAK_SALES_ROLE, BLUEPEAK_MARKETING_ROLE, or BLUEPEAK_FINANCE_ROLE. Jedify will issue USE ROLE <role> before each query on that user’s behalf.
  • With SSO — in Jedify settings, map each IdP group to its corresponding Snowflake role. Users get the role matching their group on sign-in.
  • Without SSO — an admin assigns the Snowflake role per user in user management.

6. Verify the policy

Example 3: Filter via a user mapping table

Use this example when the table you want to restrict doesn’t carry the user’s identity directly — instead, a separate mapping table links each user (typically by email) to the allowed values (department, region, account list, and so on). Like Example 1, this approach requires SSO so the user’s identity is available as a session variable.

1. Create the mapping table

Keep mapping tables in the same database as the protected table (Snowflake requires this for row access policies that reference them).

2. Grant the querying role access to the mapping table

Snowflake evaluates the policy under the querying role’s privileges, so JEDIFY_ROLE must be able to read the mapping table.

3. Create a memoizable lookup function

Snowflake row access policies do not accept subqueries that reference session variables in the policy body — both EXISTS (SELECT … WHERE … = SESSION_CONTEXT('JEDIFY_USER_EMAIL')) and the equivalent IN form fail with Unsupported subquery type cannot be evaluated inside ROW ACCESS POLICY. The supported pattern is to move the lookup into a memoizable function: the function does the join once per query, the policy just calls it.
Sanity check the function before attaching the policy — it should return the user’s department(s):

4. Create the row access policy

The policy body contains no subquery — just a function call wrapped in ARRAY_CONTAINS.

5. Attach the policy to the table

6. Verify the policy

Because my_departments() returns an array, a user appearing in the mapping table multiple times (mapped to several departments) automatically sees rows for all of their departments.

Choosing between the examples

You can combine these in a single policy — for example, bypass for a designated admin email (as in Example 1) and otherwise filter by CURRENT_ROLE() (Example 2) or by a mapping-table lookup (Example 3).