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.Documentation Index
Fetch the complete documentation index at: https://docs.jedify.com/llms.txt
Use this file to discover all available pages before exploring further.
How it works
Jedify supports two complementary mechanisms for passing the end-user’s identity to a row access policy:- 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 viaSESSION_CONTEXT('<NAME>'). Requires SSO, since the values are picked up from the SSO sign-in. See Session context for the full reference. - 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.
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 viaSESSION_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.
Per-user Snowflake role
Each Jedify user can be mapped to a specific Snowflake role. Before each query, Jedify executesUSE 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 viaSESSION_CONTEXT('<NAME>') — names must match exactly (uppercase).
| Variable | Description |
|---|---|
JEDIFY_USER_ID | Jedify’s internal identifier for the signed-in user. |
JEDIFY_USER_EMAIL | The signed-in user’s email address. |
JEDIFY_USER_NAME | The signed-in user’s display name. |
JEDIFY_USER_ROLE | The user’s Jedify role. One of User, Data expert, or Tenant Admin (see Role-Based Access Control for what each grants in Jedify). Compare with exact case in policy logic. |
JEDIFY_USER_SNOWFLAKE_ROLE | The Snowflake role Jedify activates with USE ROLE before the query. Derived from the user’s IdP group, mapped to a Snowflake role in Jedify’s settings (see Example 2). NULL when no mapping applies — in that case the query runs as Jedify’s default service role. Inside a policy, read the actual session role with CURRENT_ROLE(); this variable is useful for auditing or debugging the intended mapping. |
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.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 toSESSION_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
TheON (...) 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 asbob (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 readsCURRENT_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 ofBLUEPEAK_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, soJEDIFY_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 — bothEXISTS (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.
4. Create the row access policy
The policy body contains no subquery — just a function call wrapped inARRAY_CONTAINS.
5. Attach the policy to the table
6. Verify the policy
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
| Session variable, direct (Example 1) | Snowflake role (Example 2) | Mapping table (Example 3) | |
|---|---|---|---|
| New Snowflake objects | None | One role per group, plus baseline grants | Mapping table + memoizable function |
| Identity carried into the policy | SESSION_CONTEXT('JEDIFY_USER_EMAIL') compared to a column on the protected table | CURRENT_ROLE() | SESSION_CONTEXT('JEDIFY_USER_EMAIL') looked up in a separate mapping table |
| Requires SSO | Yes | No — SSO is optional and automates the user-to-role mapping via IdP groups | Yes |
| Works if users also query Snowflake directly outside Jedify | No | Yes | No |
| Best for | Protected table already carries a user-identity column | Existing role-based access models | User mapping lives in a separate table |
CURRENT_ROLE() (Example 2) or by a mapping-table lookup (Example 3).