CDS access control (DCL)
What you'll learn
A DCL role puts row-level authorization inside the CDS model; #CHECK on the view requires a matching role, #NOT_REQUIRED skips it.
- DCL moves row-level authorization into the model, replacing scattered AUTHORITY-CHECK.
- Syntax: `define role ... { grant select on <view> where ( field ) = aspect pfcg_auth( ... ) }`.
- `aspect pfcg_auth` maps a CDS field to a PFCG auth object and its fields.
In the Clean Core model, authorization moves *into* the data model. Instead of scattering AUTHORITY-CHECK statements through ABAP, you declare a Data Control Language (DCL) role — a separate object linked to a CDS view — that constrains which rows a user may read. The view becomes self-protecting: any consumer, whether Open SQL, OData or analytics, inherits the row-level filter automatically.
A DCL role reads `define role ... { grant select on <view> where ( field ) = aspect pfcg_auth( ... ) }`. The `aspect pfcg_auth` clause maps a view field to a classic PFCG authorization object and its fields, so the user's existing authorizations decide which rows pass. For example, granting select where `( companycode ) = aspect pfcg_auth( s_tcode, bukrs, actvt = '03' )` lets a user read only the company codes their authorization permits, with activity 03 (display).
The toggle that wires it together is the view annotation `@AccessControl.authorizationCheck`. Set to `#CHECK`, the view *requires* a matching DCL role — activation succeeds, but the first access errors at runtime if no role exists. Set to `#NOT_REQUIRED`, DCL is skipped entirely, which is appropriate for views you want readable from internal RAP queries that are not end-user-facing. Choosing the wrong value is a classic trap: `#CHECK` with no DCL compiles cleanly and fails only when someone reads the view.
Key points
- DCL moves row-level authorization into the model, replacing scattered AUTHORITY-CHECK.
- Syntax: `define role ... { grant select on <view> where ( field ) = aspect pfcg_auth( ... ) }`.
- `aspect pfcg_auth` maps a CDS field to a PFCG auth object and its fields.
- `@AccessControl.authorizationCheck: #CHECK` requires a matching DCL role.
- `#NOT_REQUIRED` skips DCL — fine for internal, non-end-user-facing views.
Examples
Grants select only on the company codes the user's S_TCODE / BUKRS authorization permits, for display activity 03.
ABAP@EndUserText.label: 'Auth for Orders'
@MappingRole: true
define role ZI_OrderHeader_DCL {
grant select on ZI_OrderHeader
where ( CompanyCode ) = aspect pfcg_auth ( S_TCODE,
BUKRS,
ACTVT = '03' );
}Source notes: clean-core-curriculum §6.5
Ask Claude
Build a prompt from this lesson + your question and open a fresh Claude chat with it pre-filled — handy for adapting a before/after pattern to your own object.