Skip to content

Permission Levels ​

The SDK knows four kinds of ability. Each answers a different question and is enforced in a different place.

TypeAnswersDeclared onEnforced
AccessMay this actor open it?an artifact class: app, dialog, value help, card, dashboard, report, resource, tile, analytic tile, chartper request (403); the artifact also disappears from navigation, search and the Launchpad
ActMay this actor run it?an action classwhen the action is dispatched (403)
SeeMay this actor see this control?the app manifest (sap.ui.viewModifications)when the manifest is served: the control is hidden
ReadMay this actor read this entity set?the entity set's source classat the OData boundary (403, or the $expand is dropped)

Access, Act and Read are enforced on the server. See only shapes the screen.

Declaring abilities ​

Every ability belongs to exactly one role, and that role is declared on the module with #[Role]. The registry refuses to load an ability whose role was never declared. It also refuses two abilities of the same type with the same name in one app.

php
use LaravelUi5\Sdk\Security\Attributes\Access;
use LaravelUi5\Sdk\Security\Attributes\Act;
use LaravelUi5\Sdk\Security\Attributes\Role;

#[Role(AcmeRole::Accounting, 'Books invoices and closes periods.')]
class AccountingModule extends AbstractUi5Module { /* … */ }

#[Access(ability: 'invoicing', role: AcmeRole::Accounting, note: 'Open the invoicing app.')]
class InvoicingApp extends AbstractUi5App { /* … */ }

#[Act('closePeriod', AcmeRole::Accounting, note: 'Close an accounting period.')]
class ClosePeriodAction extends AbstractUi5Action { /* … */ }

AcmeRole stands for your own backed enum; a plain string works too, and so does the SDK's SdkRole. #[Access], #[Act] and #[Read] all take the same three arguments: the ability, its role and a note. #[Role] takes the role, a note and an optional scope (Role Scope).

ui5:sync writes the abilities into the catalog and links each one to its role. Granting someone the role grants them its abilities (Time-Aware Grants).

Access ​

Access gates opening an artifact. A request without the ability answers 403, and navigation, the command palette, Launchpad tiles and Weave doorways leave the artifact out. An app without #[Access] is open to every signed-in partner; the Launchpad is one. If not everyone may use a capability, it becomes its own app (Capability Mini-Apps).

Access does not gate the app's OData endpoint. Reading data is gated by Read.

Act ​

Act exists only on actions. The dispatch checks it twice, in the middleware and in the action's form request (authorize() of AbstractSdkFormRequest), and both checks answer 403 (Mutating Actions).

Inside the shell, LaravelUi5.can('act/closePeriod') tells the UI whether to offer the button. The shell's context carries Act abilities only, so can('see/…') and can('access/…') answer false. Outside the shell, can() always answers true. Never rely on it for security; the server decides.

See ​

See is declared in the manifest (View Visibility). When the SDK serves the manifest, it sets each gated control's visible from the actor's abilities and hides the control by default. See hides; it doesn't protect. The action behind a hidden button still needs its Act.

Read ​

#[Read] sits on an entity set and decides whether the actor may read it at all. Which rows they then see is scoping. Both are covered on The Read Gate.

Where to go next ​