6.3 Row-Level Security via XPath Constraints

Key Takeaways

  • Row-level security via XPath constraints restricts which specific records a Module Role can view or modify by injecting predicates directly into generated SQL WHERE clauses at the database level.
  • The system token '[%CurrentUser%]' resolves at runtime to the authenticated user's GUID, enabling dynamic ownership security rules such as '[System.owner = '[%CurrentUser%]']'.
  • Multi-tenant data isolation is implemented by constraining business entities through associations to a Tenant entity matching the current user's tenant reference.
  • Multiple XPath access rules defined for the same Module Role on an entity are combined using logical OR operators, expanding access additively rather than restricting it.
  • Complex association traversals in XPath security rules generate multi-table SQL joins on every query; foreign key associations and filtered attributes must be indexed to prevent severe performance bottlenecks.
Last updated: September 2026

6.3 Row-Level Security via XPath Constraints

Exam Focus: XPath constraints on entity access rules provide row-level security. The Intermediate Developer exam rigorously tests your ability to construct ownership constraints using system tokens like [%CurrentUser%], design multi-tenant data isolation architectures, predict query results when multiple XPath rules combine, and identify performance bottlenecks caused by deep association traversal in security filters.

While attribute-level security (Section 6.2) governs which columns a user can inspect or alter, row-level security dictates which specific records (rows) a user has permission to view, update, or delete. In Mendix, row-level security is enforced at the data retrieval layer by appending XPath constraints defined on Entity Access rules directly to the database query.


The Architecture of Row-Level XPath Constraints

When a user requests data—whether through a page data grid, a reference selector dropdown, or a microflow with Apply entity access = Yes—the Mendix Runtime does not retrieve the entire database table and filter it in server memory. Doing so would expose data to memory dumps and devastate performance.

Instead, the Mendix Object Relational Mapping (ORM) engine translates the entity's active XPath security constraints into native SQL WHERE clause conditions:

CLIENT REQUEST: Retrieve Invoices for Grid
       │
       ▼
MENDIX RUNTIME ENGINE (Evaluates Entity Access Rule)
  ├── Base Query: SELECT * FROM billing$invoice
  ├── Active XPath Rule for Role 'Clerk': [Region = 'NorthAmerica']
  └── SQL Injection Translation:
        SELECT * FROM billing$invoice 
        WHERE (billing$invoice.region = 'NorthAmerica')
       │
       ▼
DATABASE ENGINE (PostgreSQL / SQL Server)
  └── Returns ONLY North American records; other rows never leave disk.

Because security filtering occurs inside the database engine, unauthorized records are physically excluded from network payloads and runtime memory. A malicious user cannot inspect browser developer tools or intercept network traffic to read unpermitted rows.


User Ownership Constraints & System Tokens

The most pervasive row-level security requirement in enterprise software is data ownership: users should only see records they created, or records assigned directly to them.

1. The Built-in System.owner Constraint

When an entity in the domain model has the property Store 'owner' toggled to Yes, the Mendix Runtime automatically populates the System.owner system association with the System.User record who created the object.

To restrict access so users can only view and edit their own created records:

[System.owner = '[%CurrentUser%]']
  • Token Evaluation: [%CurrentUser%] is a dynamic runtime system token that evaluates to the unique database identifier (GUID / ID) of the currently authenticated user's session.
  • Syntax Requirement: In Mendix XPath constraints, system tokens must be enclosed in single quotes when comparing against associations or string fields: '[%CurrentUser%]'.

2. Associated Domain Account / Employee Constraints

In sophisticated enterprise domains, business entities associate with specialized domain entities (such as Employee or CustomerAccount) rather than System.User:

[HR.ExpenseReport_Employee/HR.Employee/HR.Employee_Account = '[%CurrentUser%]']

In this rule, the runtime traverses from ExpenseReport through the Employee entity to its linked Account (which specializes System.User) and matches against [%CurrentUser%]. A staff member opening an expense report dashboard will only see their own submitted claims.

Commonly Tested XPath Security System Tokens

TokenEvaluated ValuePractical Security Use Case
[%CurrentUser%]GUID of the active authenticated userUser record ownership, manager assignment, personal task queues
[%CurrentDateTime%]Exact server timestamp of query executionTime-bounded access (e.g., [ExpirationDate >= '[%CurrentDateTime%]'])
[%BeginOfCurrentDay%]Midnight (00:00:00) of current server dayDaily operational views (e.g., shifts starting today)
[%BeginOfCurrentMonth%]First day (00:00:00) of current server monthMonthly quotas, billing statements, periodic auditing
Loading diagram...
Multi-Tenant Data Isolation via Association-Based XPath Constraints

Multi-Tenant Data Isolation Patterns

A common architectural pattern tested on the Intermediate exam is multi-tenancy—where a single deployed Mendix application and shared relational database serve multiple distinct corporate clients (tenants) without allowing one tenant to see another's data.

Implementation Blueprint:

  1. Tenant Entity: Create a Tenant entity representing the organization or subscriber.
  2. User Association: Create an association from Administration.Account to Tenant (Account_Tenant, 1-to-Many).
  3. Entity Association: Every business entity requiring isolation (e.g., Invoice, Customer, Contract) maintains an association to Tenant (e.g., Invoice_Tenant).
  4. The Tenant XPath Access Rule:
[Billing.Invoice_Tenant = '[%CurrentUser%]/Administration.Account_Tenant/Billing.Tenant']

How the Runtime Enforces Tenant Isolation:

When User John from Acme Corp logs in, his Account_Tenant reference points to Tenant_Acme (GUID 101). Whenever John opens an invoice list, the Mendix Runtime resolves John's tenant reference and appends WHERE invoice.tenant_id = 101 to the SQL query. Even if John modifies client-side parameters to request invoice ID 999 (belonging to Beta Corp), the database query returns null because the tenant ID check fails.


Combining Multiple XPath Constraints: The Logical OR Rule

A critical rule frequently tested on the exam is how the Mendix Runtime handles multiple access rules on the same entity for the same role:

The Cardinal Rule of Multiple XPath Rules: Multiple access rules defined for the same Module Role on an entity are always combined using a logical OR operator, never AND.

Architectural Example:

Suppose the OperationsManager role has two access rules defined on the PurchaseOrder entity:

  • Rule 1 Constraint: [Department = 'Operations'] (Grants Read/Write)
  • Rule 2 Constraint: [TotalAmount < 10000] (Grants Read/Write)

Generated Runtime Query:

WHERE (Department = 'Operations') OR (TotalAmount < 10000)

Consequence: The user can access:

  1. Any purchase order in the Operations department, regardless of cost.
  2. Any purchase order under $10,000 across any department (Sales, IT, HR).

If the business requirement was to allow access only to purchase orders that belong to Operations and cost under $10,000, configuring two separate rules is a catastrophic failure. The developer must write a single access rule using the and operator:

[Department = 'Operations' and TotalAmount < 10000]

Similarly, if a user is assigned multiple User Roles, the runtime takes the union (OR) of all access rules across all assigned roles. Access rules can only expand access; they cannot subtract or restrict privileges granted by another rule.


Performance Impact & Database Indexing Strategies

Because row-level XPath constraints execute on every single database query touching that entity, inefficient constraints can severely degrade application performance.

1. The Cost of Deep Association Traversal

Consider this XPath security constraint on an AuditLog entity:

[AuditLog_Ticket/Support.Ticket/Ticket_Department/Org.Department/Department_Manager = '[%CurrentUser%]']

To evaluate this constraint, the database engine must execute a SQL query joining five relational tables (auditlog, ticket, department, account, and association mapping tables). If the AuditLog table contains 5 million rows, querying 20 items for a dashboard grid will trigger massive database CPU overhead and sequential table scans.

2. Optimization Blueprint for Security XPath:

  • Keep Association Depth Minimal: Limit association traversals in XPath security rules to 1 or 2 hops. Where deep traversals are unavoidable, consider denormalizing a direct reference (e.g., associating AuditLog directly to Manager upon creation).
  • Mandatory Indexing: Any attribute or foreign key association evaluated inside an XPath security rule must have a database index defined in the Domain Model. In the example [Region = 'NorthAmerica'], the Region attribute on the entity must be indexed.
  • Avoid Sub-queries in Security Constraints: Avoid using [count(...) > 0] or [not(...)] expressions inside security rules whenever possible, as they translate into expensive SQL correlated sub-queries or NOT EXISTS clauses.
Test Your Knowledge

An entity has two separate access rules defined for the Manager role. Rule 1 has the XPath constraint [Department = 'Sales'], while Rule 2 has the XPath constraint [Region = 'NorthAmerica']. How does the Mendix Runtime evaluate these constraints when a Manager retrieves records?

A
B
C
D
Test Your Knowledge

In a multi-tenant application where multiple corporate clients share a single database, which XPath constraint pattern best enforces complete data isolation for the Invoice entity based on the logged-in user's account?

A
B
C
D
Test Your Knowledge

What is a major performance consideration when designing row-level XPath security constraints that traverse multiple entity associations?

A
B
C
D