Summary
defineApplicationRole() does not provide a way to grant an app access to only a selected set of fields on an object.
Instead, field permissions appear to behave as deny-list overrides of an object-level baseline:
- An object permission is required before the app can access that object’s records.
- Once object read/update access is granted, every unspecified field is readable/updatable.
- Setting
canReadFieldValue: true / canUpdateFieldValue: true for selected fields does not create an allowlist.
- To restrict the app to only three fields, I would need to add explicit
false permissions for every other existing field.
This is both surprising and poor DX for application roles, where least privilege should be the default and easy to maintain.
Version
twenty-sdk: 2.23.0
twenty-client-sdk: 2.23.0
twenty-server: 2.24.1
Reproduction
I defined a default application role intended to allow read/write access to Company records, but only to address, companyLatitude, and companyLongitude:
import {
defineApplicationRole,
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define'
export default defineApplicationRole({
universalIdentifier: '...',
label: 'Restricted app role',
description: 'Should access only three Company fields',
canReadAllObjectRecords: false,
canUpdateAllObjectRecords: false,
canSoftDeleteAllObjectRecords: false,
canDestroyAllObjectRecords: false,
canUpdateAllSettings: false,
canBeAssignedToAgents: false,
canBeAssignedToUsers: false,
canBeAssignedToApiKeys: false,
objectPermissions: [
{
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
canReadObjectRecords: true,
canUpdateObjectRecords: true,
canSoftDeleteObjectRecords: false,
canDestroyObjectRecords: false,
},
],
fieldPermissions: [
{
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
fieldUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.address
.universalIdentifier,
canReadFieldValue: true,
canUpdateFieldValue: true,
},
{
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
fieldUniversalIdentifier: 'companyLatitude universal identifier',
canReadFieldValue: true,
canUpdateFieldValue: true,
},
{
objectUniversalIdentifier:
STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.universalIdentifier,
fieldUniversalIdentifier: 'companyLongitude universal identifier',
canReadFieldValue: true,
canUpdateFieldValue: true,
},
],
permissionFlagUniversalIdentifiers: [],
})
I tested this using both:
- The core API client in an app logic function.
- An app front component.
Actual behavior
The app can read and update all Company fields.
If I remove the objectPermissions entry and retain the fieldPermissions, the app cannot access Company records at all.
The apparent workaround is to enumerate every Company field that must not be accessible and set both values to false, which is cumbersome and, in some cases, not even possible—for example, when an app is not aware of the full server schema.
Expected behavior
There should be a supported way to express:
This app may read/update Company records, but it may only read/update these named fields.
For example, one of:
- An allowlist mode for field permissions.
- Default-deny field access when an application role declares field permissions for an object.
- An explicit object-permission option such as
defaultFieldAccess: 'none'.
- Separate application-role semantics that are secure-by-default, while retaining current behavior for user-assigned roles.
Why this matters: least privilege and DX
The current model creates a bad developer experience and makes least-privilege configurations fragile.
An app author must:
- Grant object-level record access, because field permissions alone do not permit record access.
- Discover and enumerate every other field on the object.
- Add an explicit
false permission for each one.
- Repeat that work whenever Twenty adds a standard field, the workspace adds a custom field, or another app extends the object.
That is error-prone and does not remain least-privilege over time: newly added fields are accessible by default unless the app is updated to deny them.
The app-role documentation says the app token and typed API client are restricted to the role’s permissions, and recommends declaring only the permissions functions need. That wording reasonably suggests that declaring three field permissions should grant access to those three fields—not grant broad access to every unlisted field.
For application code handling potentially sensitive CRM data, a field allowlist is the safer and more natural declaration.
Evidence
The documentation describes defineApplicationRole() as controlling access for app logic functions and front components, and recommends least privilege:
https://docs.twenty.com/developers/extend/apps/config/application#default-function-role
The permissions FAQ describes field permissions as overrides of object-level permissions:
https://docs.twenty.com/user-guide/permissions-access/how-tos/permissions-faq#how-do-permission-overrides-work
The current implementation is consistent with deny-list semantics, but that leaves no future-safe allowlist mechanism for app roles.
Request
Please consider adding a field allowlist/default-deny option for defineApplicationRole() (or changing its field-permission semantics), and clarify the documentation in the meantime.
Summary
defineApplicationRole()does not provide a way to grant an app access to only a selected set of fields on an object.Instead, field permissions appear to behave as deny-list overrides of an object-level baseline:
canReadFieldValue: true/canUpdateFieldValue: truefor selected fields does not create an allowlist.falsepermissions for every other existing field.This is both surprising and poor DX for application roles, where least privilege should be the default and easy to maintain.
Version
twenty-sdk:2.23.0twenty-client-sdk:2.23.0twenty-server:2.24.1Reproduction
I defined a default application role intended to allow read/write access to Company records, but only to
address,companyLatitude, andcompanyLongitude:I tested this using both:
Actual behavior
The app can read and update all Company fields.
If I remove the
objectPermissionsentry and retain thefieldPermissions, the app cannot access Company records at all.The apparent workaround is to enumerate every Company field that must not be accessible and set both values to false, which is cumbersome and, in some cases, not even possible—for example, when an app is not aware of the full server schema.
Expected behavior
There should be a supported way to express:
For example, one of:
defaultFieldAccess: 'none'.Why this matters: least privilege and DX
The current model creates a bad developer experience and makes least-privilege configurations fragile.
An app author must:
falsepermission for each one.That is error-prone and does not remain least-privilege over time: newly added fields are accessible by default unless the app is updated to deny them.
The app-role documentation says the app token and typed API client are restricted to the role’s permissions, and recommends declaring only the permissions functions need. That wording reasonably suggests that declaring three field permissions should grant access to those three fields—not grant broad access to every unlisted field.
For application code handling potentially sensitive CRM data, a field allowlist is the safer and more natural declaration.
Evidence
The documentation describes
defineApplicationRole()as controlling access for app logic functions and front components, and recommends least privilege:https://docs.twenty.com/developers/extend/apps/config/application#default-function-role
The permissions FAQ describes field permissions as overrides of object-level permissions:
https://docs.twenty.com/user-guide/permissions-access/how-tos/permissions-faq#how-do-permission-overrides-work
The current implementation is consistent with deny-list semantics, but that leaves no future-safe allowlist mechanism for app roles.
Request
Please consider adding a field allowlist/default-deny option for
defineApplicationRole()(or changing its field-permission semantics), and clarify the documentation in the meantime.