Skip to content
Guide

Role Presets

Publish recommended, non-granting permission bundles an administrator may adopt when composing a tenant Role.

Offer administrators a reusable permission bundle without granting anyone access automatically.

Publish a responsibility bundle

Implement SDK RolePresetContribution::rolePresets() under the App's contribution locations. Return RolePreset values with a stable key, revision, recommended assignment scope, audience, risk, and existing permission keys. The Assets example below separates tenant definition reading from Legal Entity operations.

Keep the permission set small enough to represent one responsibility. Match every permission's assignment scope and subject population; do not add a broad capability merely to make a menu visible. Refresh discovery after introducing the contribution class.

Confirm the result

The preset is available during role composition, but installation and preset discovery grant no user access. An administrator must create/compose and assign a role. Verify the resulting role's actual API permissions using Test an App.

Composition and maintenance

A Role Preset is a named recommendation: "for this job, these permissions are a sensible starting set." It grants nothing. An access administrator may select it while creating or cloning a Role, and the resulting Role is tenant-owned.

The App Catalog's initial-access dialog is a second adoption surface. For the pending App it lists only non-technical, non-deprecated presets owned by that App and recommended for tenant or current-Legal-Entity scope. Operating-Unit presets remain in the ordinary Access flow.

The real shape, from packages/assets:

Code example
PHP
final class AssetManagementRolePresets implements \Nexia\Permission\Contracts\RolePresetContribution
{
    public static function rolePresets(): array
    {
        return [\Nexia\Permission\RolePreset::fromArray([
            'key' => 'assets.tenant_definition_reader',
            'app_key' => 'assets',
            'version' => 1,
            'name' => 'Asset Definition Reader',
            'description' => 'Reads tenant-wide asset types, classifications, and active policy definitions used by LegalEntity operations.',
            'recommended_scope' => \Nexia\Permission\AssignmentScope::Tenant->value,
            'type' => \Nexia\Permission\PresetType::Capability->value,
            'audience' => \Nexia\Permission\PermissionDefinition::AUDIENCE_INTERNAL,
            'risk' => \Nexia\Permission\PermissionDefinition::RISK_STANDARD,
            'permissions' => [
                'assets.asset_type.read',
                'assets.asset_category.read',
                'assets.asset_policy.read',
            ],
            'deprecated' => false,
            'replacement_key' => null,
        ])];
    }
}

This expands the first preset in packages/assets/src/Contribution/AssetManagementRolePresets.php and returns SDK RolePreset values; the production helper shares field construction.

Field reference

KeyTypeBehavior
keystringStable, App-prefixed preset identity
app_keystringOwning App
versionintBump when the recommended set changes meaningfully
namestringHuman-facing preset name
descriptionstringWhat the job does; shown during Role composition
recommended_scopeAssignmentScope valuetenant, legal_entity, or operating_unit
audiencestringPermissionDefinition::AUDIENCE_INTERNAL for staff-facing presets
riskstringstandard, elevated, or privileged
permissionslist of stringPermission keys, all owned by this App
deprecatedboolHide from new selection while existing Roles keep working
replacement_keystring, nullWhere to go instead when deprecated
typePresetType valuejob, capability, or technical

Set risk honestly — it is the signal an administrator uses to decide whether a preset needs review. In packages/assets, the preset that reads asset definitions is RISK_STANDARD and the one that maintains the same definitions is RISK_PRIVILEGED.

Choose type by what the bundle represents:

TypeMeans
jobA whole role a person holds
capabilityOne coherent ability, combined with others
technicalIntegration or service access, not a human job

Boundaries

A preset never grants by itself. It does not confer authority merely because the App ships or the catalog discovers it. An explicit adoption workflow may materialize and assign a preset without making the preset itself granting. The App Catalog's initial-access dialog is such a workflow: after an authorized administrator selects non-technical, non-deprecated presets and users, Core creates tenant-owned Roles and audited Grants at each selected scope. Protected presets that the actor cannot self-approve are materialized without a Grant and continue through the protected-access approval flow.

A preset is not the Permission Catalog. The catalog remains the source of truth for what is grantable; a preset is a curated subset. Never list a permission that no catalog contributor publishes — it cannot be granted, and the preset silently under-delivers.

Presets do not update Roles retroactively. Bumping version changes what new selections get. Roles already composed from an earlier version keep their permissions. If a permission becomes dangerous, retire the permission itself with nexia-access:retire-permission, not just the preset.

Only your own permissions. A preset lists keys owned by its App. Bundling another App's permissions crosses the App boundary and will not resolve.

Keep them small

A preset with sixty permissions is a copy of the catalog and tells an administrator nothing. Aim for one job, and prefer several small capability presets that compose over one exhaustive job preset.

packages/assets separates reading tenant definitions from maintaining them, so the read bundle can be granted widely and the maintenance bundle narrowly. That separation is the value.

Source of truth: docs/developers/content/en/platform-extensions/role-presets.md