by datastudy.nl

Field notes for teams building on the Databricks Data Intelligence Platform

Engineering

Databricks ABAC context attributes: agent-aware data governance

Databricks ABAC context attributes are Unity Catalog row filter and column mask conditions that bind to the calling OAuth application. Shipped in Beta on August 21, 2026, they let you scope a policy to request.client_id so an agent querying on behalf of a user sees only that user's rows while direct workspace access stays unrestricted.

Databricks ABAC context attributes policy evaluation flow, showing the two request paths direct workspace user query returns full data and agent on behalf of user query via OAuth app returns filtered data, Beta status as of August 2026
Illustrative: Unity Catalog ABAC context attribute policy evaluation for a single table, comparing direct workspace access (full data, no filter) against agent access via OAuth application (filtered data, filter applied). Source: Databricks documentation, Data Today benchmark.

A service principal that can read a table is not the same as an end user who can read that table. Until last week, Databricks Unity Catalog treated the agent and the human as roughly the same principal: if a credential had permission, the query returned whatever rows the credential could see. That is a serious problem for production agents. You want the agent to see only the user's rows, but you also do not want the user to lose access to the full dataset when they run their own SQL.

ABAC context attribute policy evaluation showing direct workspace access returns full data and agent access via OAuth application returns filtered data, based on Databricks Unity Catalog ABAC Beta as of August 2026
Illustrative: ABAC context attribute policy evaluation by request path. Direct workspace user query returns 100 percent of rows, agent query via OAuth app returns filtered subset. Source: Databricks documentation, Data Today benchmark.

Databricks shipped context attributes for attribute-based access control (ABAC) policies in Beta on August 21, 2026. The feature lets you write Unity Catalog row filter and column mask policy conditions that target the context of the request itself: which registered OAuth application is calling (request.client_id) and whether the request runs on behalf of a user (request.is_on_behalf_of). The two new functions, has_context_attribute and has_context_attribute_value, work in the WHEN clause of row filter and column mask policies, so you can write one policy that restricts the data an agent reads on a user's behalf when it connects through a registered OAuth application, while the user can still read the full data when they query it directly in the workspace.

The mechanics are straightforward. A context-aware policy condition asks: is this query coming from a specific OAuth application, and is it acting on behalf of a user? If both are true, the policy attaches a row filter or column mask. If the user queries the table directly, the condition evaluates to false and the policy does not attach.

This is the feature that closes the gap between "the data team can see the table" and "the agent calling this table on behalf of a user can see exactly that user's rows." For a deeper look at the platform layer underneath, read our Databricks Data Intelligence Platform guide.

How does ABAC policy evaluation actually work with context attributes?

Unity Catalog evaluates ABAC policies in two stages: policy evaluation in Unity Catalog, then policy enforcement in the Databricks Runtime.

When a query hits an ABAC-secured table, Unity Catalog uses the securable object's metadata (including governed tag assignments) and the querying user's identity and group memberships to determine which policies apply. It identifies all policies whose scope covers the queried table, checks whether the querying user is in the TO list and not in the EXCEPT list, evaluates table and column conditions against the tags on the queried object (including inherited tags), and if the policy applies, determines the effective row filter or column mask and sends it to the Databricks Runtime as part of the table metadata.

Context attributes layer into that evaluation. The request.client_id is present only on some request paths. It is set for on-behalf-of requests made through an OAuth application, and is absent otherwise. The request.is_on_behalf_of attribute is present with a value of 'true' or 'false', or is absent on unsupported compute paths.

A critical fail-closed behavior governs the whole feature. When a recognized attribute is not present in the request, has_context_attribute returns false; it does not raise an error. You should phrase conditions so that this outcome restricts access rather than grants it. A key that is not a recognized request.* attribute, such as a misspelled key, raises an evaluation error rather than resolving to false. Stick to the exact names request.client_id and request.is_on_behalf_of.

If you disable the ABAC Context Attributes preview while row filter or column mask policies that use these functions still exist, queries against the affected data fail with UC_ABAC_CONTEXT_ATTRIBUTE_FUNCTIONS_DISABLED rather than silently returning no rows. Policy management is unaffected. You can still list, alter, and drop policies. Remove or rewrite context attribute policies before you disable the feature.

ABAC policies require Databricks Runtime 16.4 or above, or serverless compute. If a user attempts to access an ABAC-secured table from an unsupported version, the query fails closed (access is denied) to prevent unprotected data exposure.

How do you write a context-aware policy?

You create an ABAC policy using the Catalog Explorer UI, the CREATE POLICY SQL statement, or the Databricks REST APIs, SDKs, and Terraform. To create a policy, you must have MANAGE on the securable object where the policy is attached (catalog, schema, or table) or own the securable object, and EXECUTE on the UDF that implements the filtering or masking logic.

The has_context_attribute and has_context_attribute_value functions go in the WHEN clause. The TO list specifies which principals are subject to the policy, the EXCEPT list exempts principals from enforcement, and the SCOPE defines which securable objects the policy covers.

Here is a simplified SQL sketch of a context-aware row filter policy that scopes to a specific OAuth application acting on behalf of a user. The UDF user_region_filter enforces a region filter, and the policy applies only when the request comes through a registered OAuth app on behalf of a user.

CREATE FUNCTION catalog.schema.user_region_filter(region STRING)
RETURNS BOOLEAN
RETURN region = current_user_metadata('region');

CREATE POLICY catalog.schema.agent_row_filter_policy
ROW FILTER catalog.schema.user_region_filter(region)
TO (all account users)
EXCEPT (admins, compliance_team)
SCOPE TABLE catalog.schema.customer_orders
WHEN (has_context_attribute_value('request.is_on_behalf_of', 'true')
      AND has_context_attribute_value('request.client_id', '<oauth-app-client-id>'));

When a user queries the table directly in the workspace, request.is_on_behalf_of is absent or false, the WHEN clause evaluates to false, and the policy does not attach. The user sees the full table. When the agent queries the table on the user's behalf through the registered OAuth application, both context conditions evaluate to true, the policy attaches, and the runtime applies user_region_filter as a secure view on top of the table scan.

The Databricks Runtime query planner translates the effective row filter or column mask into a secure view on top of the table scans that enforce filtering and masking during query execution. This is the same enforcement mechanism used for table-level row filters and column masks.

Only one distinct row filter can be applied at query time for a given table and user. Similarly, only one distinct column mask per column can resolve at runtime for a given column and user. This prevents ambiguous results. If multiple distinct filters or masks apply to the same user and table (or column), Databricks blocks access and returns an error: INVALID_PARAMETER_VALUE.UC_ABAC_MULTIPLE_ROW_FILTERS or COLUMN_MASKS_FEATURE_NOT_SUPPORTED.MULTIPLE_MASKS. Access stays blocked until you resolve the conflict.

Databricks automatically casts both the input and output of column mask functions resolved from ABAC policies. The input column value is cast to match the mask function's parameter type, and the function output is cast to match the target column's data type.

When is direct service principal access not enough?

The traditional approach to agent data access on Databricks has been to give a service principal SELECT on the table and let it figure out row-level scoping in application code. That works for a prototype. It falls apart in production.

The core problem is that a service principal does not have a user identity. It cannot enforce row-level security based on the human making the request without you building that logic yourself, which means your data lakehouse is not enforcing policy at the data layer. The agent sees every row it has permission to see, and you have to trust that the agent's application logic correctly filters down to what the human should see. That is a governance gap and an audit risk.

Context attributes let you push the policy down to the data layer where it belongs. The agent's OAuth application becomes a first-class input to policy evaluation. You can write a policy that says: when this specific OAuth application calls on behalf of a user, apply this row filter. The user's direct workspace access stays untouched.

The table below summarizes how context attributes change the enforcement model.

Scenario Principal Policy condition Effective filter User sees
Direct workspace query User request.is_on_behalf_of absent or false Policy does not attach Full table
Agent via OAuth app Service principal request.client_id matches and request.is_on_behalf_of true Policy attaches, row filter UDF applies User's rows only
Unsupported compute path User or SP request.is_on_behalf_of absent Policy does not attach Query fails closed

The fail-closed behavior on unsupported compute is the right design. The alternative is silent data leakage to an agent running on an old cluster.

What does this cost and what are the limits?

Context attributes are in Beta. There is no separate line-item charge for the context attribute functions themselves. The cost is in the compute you already run. ABAC policy evaluation happens in Unity Catalog and is priced as part of your serverless infrastructure. Policy enforcement happens in the Databricks Runtime as a secure view on top of your table scan, so the cost is the compute you already pay for.

The real cost consideration is operational, not billing. Every context-aware policy you add is another condition that Unity Catalog must evaluate at query time. For most workloads, this is negligible. For a large number of overlapping policies on hot tables, you want to profile the overhead before you deploy at scale.

The hard limits are structural. You cannot have multiple distinct row filters resolve to different values for the same user and table at query time. Databricks blocks the query with an error until you resolve the conflict. The same applies to column masks. You also cannot use row filters or column masks with certain operations. Those operations fail rather than bypass enforcement. To run them, the principal must be listed in the EXCEPT clause of every ABAC policy that applies to the table. Exempt principals are not subject to the policy, so Databricks does not need to enforce it and can safely allow the operation.

request.client_id is set only for on-behalf-of requests made through a registered OAuth application. It is absent on other compute paths. request.is_on_behalf_of is present with a value of 'true' or 'false', or is absent on unsupported compute paths. Those are the two attributes available in this Beta.

What should you do with it and what should you avoid?

Start with one table, one OAuth application, and one row filter policy. The feature is in Beta, and the blast radius of a misconfigured policy is the entire query path for that table.

Do scope your policy to a specific request.client_id. The point is to bind enforcement to a known, registered OAuth application, not to catch all agent traffic. If you write a condition that only checks request.is_on_behalf_of and ignores the client ID, you are relying on every calling application to be well-behaved, which is a weaker posture.

Do use the EXCEPT clause for principals that need unfiltered access for operations incompatible with row filters and column masks. Compliance teams, backup service principals, and certain OPTIMIZE or VACUUM operations need to bypass enforcement. List them in EXCEPT.

Do monitor for INVALID_PARAMETER_VALUE.UC_ABAC_MULTIPLE_ROW_FILTERS and COLUMN_MASKS_FEATURE_NOT_SUPPORTED.MULTIPLE_MASKS errors. These indicate policy conflicts that block access until you resolve them. A query that worked yesterday might break today if a second team adds an overlapping policy.

Do not disable the ABAC Context Attributes preview while policies that use these functions still exist. Queries against the affected data fail with UC_ABAC_CONTEXT_ATTRIBUTE_FUNCTIONS_DISABLED. Remove or rewrite context attribute policies before you disable the feature.

Do not expect context attributes to replace your entire authorization model. They are a scoping mechanism for row-level and column-level policies, not a substitute for role-based access control. If you need exclusive access where a user assumes a role and drops their accumulated permissions, use RBAC, which reached general availability on August 19, 2026.

The security model is now request-aware

Databricks has spent two years building ABAC to govern data by tags, user identity, and group membership. Context attributes add the missing dimension: the request itself. You can now write a Unity Catalog policy that knows whether a query comes from a human in a notebook or an agent acting on a user's behalf. That is the difference between granting access to a table and governing access to a table. For governed agent workloads, this is the feature that makes production access possible.

Sources