The Field Access Restrictions feature provides granular, user-level control over field visibility and modification rights for data operations performed through the Cloud Events API. This security layer allows administrators to restrict read and/or write access to specific fields on a per-user basis, ensuring sensitive data is protected while maintaining API functionality.
Namespace: Origo.PTE.CloudEvents Main Table: Cloud Events Field Access (Table 65304) Management Page: Cloud Events Field Accesses (Page 65309) Management Codeunit: Cloud Events Field Access (Codeunit 65350)
The field access restriction system consists of four primary objects:
Data.Records.Get and Data.Records.Set message typesThe system supports four types of field access restrictions:
| Restriction Type | Value | Caption | Description | Blocks Read | Blocks Write |
|---|---|---|---|---|---|
| Both | 0 | Both | Most restrictive - blocks both read and write operations | ✓ | ✓ |
| Read | 1 | Read | Blocks read operations only - field will not appear in GET responses | ✓ | ✗ |
| Write | 2 | Write | Blocks write operations only - field can be read but not modified | ✗ | ✓ |
| Bypass | 3 | Bypass | Write Guard bypass - field is excluded from all restriction checks; the ChangeLog Write Guard allows writes to this field regardless of Change Log coverage | ✗ | ✗ |
Both Restriction:
Data.Records.Get responsesData.Records.Set are rejected with an errorRead Restriction:
Data.Records.Get responsesData.Records.SetWrite Restriction:
Data.Records.Get responsesData.Records.Set are rejected with an errorBypass:
Data.Records.Get responses (no read restriction)Data.Records.Set (no write restriction)The system supports two wildcard values to apply restrictions broadly without creating per-field or per-table entries:
| Wildcard | Meaning | Validation rule |
|---|---|---|
| Field No. = 0 | All fields in the specified table | Table No. must be a valid table (or 0) |
| Table No. = 0 | All tables for the user | Field No. is forced to 0 (cannot specify a field without a table) |
When checking whether a field is restricted, the system evaluates entries in this order:
The first match wins. If no entry is found at any level, the field is unrestricted.
Example: A user has:
Resolution:
<All Fields>The IsFieldWriteGuardBypassed check follows the same fallback chain:
A Bypass entry at the all-tables level exempts every field in every table from the Write Guard.
The page is divided into two sections:
Integration Points: 3 locations in DataRecordsGetImpl.Codeunit.al
Behavior:
FieldRestrictionMgt.IsFieldReadRestricted(TableNo, FieldNo)fields objectExample Scenario:
Given restrictions:
Request:
{
"specversion": "1.0",
"type": "Data.Records.Get",
"subject": "Customer",
"data": "{\"fieldNumbers\":[1,2,5]}"
}
Response (without restrictions):
{
"status": "Success",
"result": [
{
"id": "...",
"primaryKey": { "No_": "10000" },
"fields": {
"No_": "10000",
"Name": "Adatum Corporation",
"Address": "192 Market Square"
}
}
]
}
Response (with restrictions applied):
{
"status": "Success",
"result": [
{
"id": "...",
"primaryKey": { "No_": "10000" },
"fields": {
"No_": "10000"
}
}
]
}
Integration Points:
DataRecordsSetProcess.Codeunit.al (GetFieldsAsList method)Behavior:
FieldRestrictionMgt.IsFieldWriteRestricted(TableNo, FieldNo)Example Scenario:
Given restrictions:
Request:
{
"specversion": "1.0",
"type": "Data.Records.Set",
"subject": "Customer",
"data": {
"data": [
{
"primaryKey": { "No_": "TEST001" },
"fields": {
"Name": "New Customer Name",
"Address": "123 Main Street"
}
}
]
}
}
Response (with write restriction):
{
"status": "Error",
"message": "Invalid field \"Name\" in fields object. Field does not exist in the target table. Valid field names: No_, Address, City, ..."
}
Note: The error message indicates the field is invalid because it's been filtered out of the valid field list due to the write restriction. The trailing Valid field names: ... enumeration lists the JSON keys actually accepted for the current caller (after both schema normalisation and any field-access restrictions). When the supplied key normalises to a real field name — for example sending "No." for a field BC exposes as "No_" — the error is prefixed with Did you mean "No_"? to make self-correction trivial.
Primary Key: User Security ID + Table No. + Field No.
Fields:
| Field No. | Field Name | Type | Description |
|---|---|---|---|
| 1 | User Security ID | Guid | Identifies the user or AAD application |
| 2 | Table No. | Integer | Target table number |
| 3 | Field No. | Integer | Target field number |
| 10 | Restriction Type | Enum | Type of restriction (Both, Read, Write, Bypass) |
| 20 | User Name | Text[250] | User's friendly name (auto-populated, read-only) |
| 21 | Table Name | Text[250] | Table's caption (FlowField, read-only) |
| 22 | Field Name | Text[30] | Field's name (auto-populated, read-only) |
Methods:
procedure IsFieldRestricted(UserSecurityId: Guid; TableNo: Integer; FieldNo: Integer; RestrictType: Enum "Cloud Events Restriction Type"): Boolean
Checks if a specific field is restricted for a user based on restriction type. Uses the three-level fallback chain: specific field → all-fields wildcard (Field 0) → all-tables wildcard (Table 0, Field 0).
procedure GetRestrictedFields(UserSecurityId: Guid; TableNo: Integer; RestrictType: Enum "Cloud Events Restriction Type"): List of [Integer]
Returns a list of all restricted field numbers for a table and restriction type. Includes entries from both the specific table and the all-tables wildcard (Table 0). Bypass entries are excluded from this list.
procedure IsFieldWriteGuardBypassed(TableNo: Integer; FieldNo: Integer): Boolean
Checks whether a Bypass entry exists for the given table/field combination (field-scoped, ignores User Security ID). Uses the three-level fallback: specific field → all-fields wildcard (Field 0) → all-tables wildcard (Table 0, Field 0).
Public Methods:
procedure IsFieldReadRestricted(TableNo: Integer; FieldNo: Integer): Boolean
Checks if a field is read-restricted for the current user (UserSecurityId()). Returns true if restriction type is Read or Both.
procedure IsFieldWriteRestricted(TableNo: Integer; FieldNo: Integer): Boolean
Checks if a field is write-restricted for the current user (UserSecurityId()). Returns true if restriction type is Write or Both.
procedure IsFieldWriteGuardBypassed(TableNo: Integer; FieldNo: Integer): Boolean
Checks whether a Bypass entry exists for the given table/field combination (field-scoped, all users). The ChangeLog Write Guard checks this before evaluating Change Log coverage.
Scenario: External integration should access customer records but not see credit card information.
Setup:
Result: Integration can read and write customer data, but Credit Card No. field is never exposed in GET responses and cannot be modified via SET operations.
Scenario: Integration needs to see customer balances but should never modify them (calculated fields).
Setup:
Result: Integration can read Balance (LCY) in GET responses but cannot modify it through SET operations.
Scenario: Integration should be able to update internal notes but not read them (privacy compliance).
Setup:
Result: Integration cannot see Internal Notes in GET responses but can update them via SET operations.
Scenario: An integration needs to write a specific field via Data.Records.Set but activating the Change Log for that field is not feasible or desirable. The ChangeLog Write Guard is set to Blocked.
Setup:
Result: The ChangeLog Write Guard allows writes to this field regardless of whether it is covered by the Change Log. No read or write restrictions are applied — the Bypass entry solely affects the Write Guard evaluation.
Scenario: Hide all SystemModifiedAt/SystemModifiedBy fields from specific integration users.
Setup: Create Both restrictions for multiple tables and fields:
Result: System audit fields are completely hidden from the integration user.
Scenario: Completely block a user from reading or writing any data via the Cloud Events API.
Setup:
Result: The user cannot read any field from any table via Data.Records.Get, and all Data.Records.Set operations are rejected. This is equivalent to a full API lockout for the user without removing their BC user account.
Scenario: An integration user should be able to query data from any table but must never modify records.
Setup:
Result: The user can read all fields from all tables via Data.Records.Get but any Data.Records.Set operation is rejected.
Users managing field restrictions need:
UserSecurityId() or SystemCreatedBy in message queue recordsSymptom: Field not appearing in Data.Records.Get response
Possible Causes:
Diagnosis: Check Cloud Events Field Accesses page for the user in question.
Symptom: Data.Records.Set returns error "Invalid field"
Possible Causes:
Diagnosis: Check Cloud Events Field Accesses page for the user in question.
The page includes an action "Delete All for User":
For programmatic setup of restrictions:
var
FieldAccess: Record "Cloud Events Field Access";
begin
FieldAccess.Init();
FieldAccess."User Security ID" := IntegrationUserSecurityId;
FieldAccess."Table No." := Database::Customer;
FieldAccess."Field No." := 2; // Name field
FieldAccess."Restriction Type" := FieldAccess."Restriction Type"::Read;
FieldAccess.Insert(true); // Validates and populates User Name, Field Name
end;
Data.Records.Get (Read Enforcement):
// Pseudo-code from DataRecordsGetImpl
foreach Field in RequestedFields do begin
if not FieldRestrictionMgt.IsFieldReadRestricted(TableNo, Field."No.") then
AddFieldToJson(ResponseJson, Field);
// Restricted fields are silently omitted
end;
Data.Records.Set (Write Enforcement):
// Pseudo-code from DataRecordsSetProcess
local procedure GetFieldsAsList(TableId: Integer; FieldList: List of [Text])
begin
foreach Field in Table do begin
if not FieldRestrictionMgt.IsFieldWriteRestricted(TableId, Field."No.") then
FieldList.Add(Field.FieldName);
end;
// Restricted fields are excluded from valid field list
// Later validation rejects fields not in valid field list
end;
Field restrictions use the calling user's Security ID:
UserSecurityId() of the web service callerSystemCreatedBy field of the message queue recordThe CE User/App Buffer (Table 65305) combines:
This allows restrictions to be applied to both human users and application service principals.
The Cloud Events Restriction Type enum is marked as Extensible = true:
enumextension 50100 "My Restriction Types" extends "Cloud Events Restriction Type"
{
value(50100; "Custom Restriction")
{
Caption = 'Custom Restriction';
}
}
Note: Custom restriction types require custom logic implementation as the core system only recognizes Both, Read, and Write.
Currently, the system does not publish events when restrictions are applied. Consider adding integration events if you need to:
Field Access Restrictions provide fine-grained security control for Cloud Events API operations by:
This feature enables administrators to meet compliance requirements, protect sensitive data, and implement principle of least privilege while maintaining API flexibility.
© Origo – Cloud Events Base Extension