Authorization is not optional
A RAP object without authorization checks is a data breach waiting for a curious user. In the ABAP Cloud world — where objects are exposed as OData to browsers everywhere — access control isn't a phase-two concern. It's part of the object.
RAP gives you two layers: instance authorization in the behavior (can this user touch this object?) and access control (DCL) on the CDS views (which rows can they even see?). You usually need both.
Layer 1: instance authorization in the BDEF
define behavior for ZI_SalesOrder_TP
persistent table zsalesorder
lock master
authorization master ( instance )
{
create;
update;
delete;
}
authorization master ( instance ) switches on per-instance checks. The framework then calls your get_instance_authorizations method for every operation, and you decide:
METHOD get_instance_authorizations.
READ ENTITIES OF zi_salesorder_tp IN LOCAL MODE
ENTITY SalesOrder
FIELDS ( CreatedBy ) WITH CORRESPONDING #( keys )
RESULT DATA(orders).
LOOP AT orders INTO DATA(order).
IF order-CreatedBy <> cl_abap_context_info=>get_user_technical_name( ).
APPEND VALUE #( %tky = order-%tky
%update = if_abap_behv=>auth-unauthorized
%delete = if_abap_behv=>auth-unauthorized )
TO RESULT.
ENDIF.
ENDLOOP.
ENDMETHOD.
Authorization methods answer one question per operation: allowed or not, for this instance, for this user. Keep them fast and side-effect free — they run constantly.
Layer 2: DCL on the CDS views
Instance authorization controls operations. But the list report still shows rows the user can't touch — confusing at best. Data Control Language (DCL) filters at the CDS level:
@EndUserText.label: 'Sales order access control'
@MappingRole: true
define role ZI_SalesOrder_TP {
grant select on ZI_SalesOrder_TP
where CreatedBy = aspect pfcg_auth( S_SALES, SALESORG,
actvt = '03' );
}
DCL applies wherever the CDS view is read — Fiori, EML, analytics. It's the row-level filter that makes unauthorized data invisible, not just untouchable. The @MappingRole: true annotation connects it to PFCG roles, so admins manage access in the usual role maintenance.
Global vs instance authorization
Not every check needs an instance. "Can this user create orders at all?" doesn't depend on a specific order — that's a global authorization, checked once per operation type. "Can they change this order?" is instance-level.
- Global: role membership, general activity permission. Cheap, cached, checked first.
- Instance: ownership, status, organizational assignment. Per-row, evaluated on demand.
Use global checks to fail fast on the obvious cases, instance checks for the data-dependent ones.
Authorization pitfalls
- Testing with a developer user. Your SAP_ALL developer sees everything — authorization bugs surface only with real business users. Test with restricted users early.
- Forgetting DCL. Instance auth without DCL means users see rows they can't open. Confusing UX and an information leak.
- Authorization in draft. Draft instances need authorization too — users shouldn't edit drafts they can't activate.
- Performance. Instance authorization runs per instance per operation. One efficient read, simple comparisons — never select loops.
The developer-user trap is the number one authorization bug in RAP projects. If it "works for me but fails for the business user," check your authorization implementation before anything else.
How do you test authorization — dedicated test users, or learned the hard way in QA? Tell me in the comments.