← Back to blog
cloud_sync SoD · SAP BTP · Hybrid Access

SoD is outgrowing classic SAP. Here is what we built for it.

Access no longer lives only in SAP transactions. It lives in BTP scopes, non-SAP entitlements, and the service and AI identities that call your APIs. smartGRC treats every one of them as a first-class citizen of Segregation of Duties - no disguises.

eventPublished Sept 4, 2026 schedule10 min read codeTechnical section included
First, the model

How access actually works in SAP BTP

In classic SAP, a person's rights come from roles that bundle transactions and authorization objects. In SAP BTP the building blocks are different - and understanding them is the whole game. Authorizations in a BTP subaccount are managed by XSUAA, and they form a chain:

BTP authorization chain (XSUAA)
USER human or service ROLE COLLECTION the assignment unit ROLE template instance per app SCOPE verb on resource ← where the real permission sits

A user is assigned one or more role collections - the unit an administrator actually hands out, loosely comparable to a composite role. A role collection contains roles (instances of role templates that live inside an application). Each role grants a set of scopes - and the scope is where the real permission sits.

A scope is a string of the form xsappname.object.path.verb. It is not a transaction - it is a verb on a resource path, published by an application's API. For example, aicore!b164.scenarios.batches.write breaks down as:

PartExampleMeaning
xsappnameaicore!b164the application (identifier)
objectscenariosbusiness object / domain
pathbatchessub-resource or functional path
verbwritethe operation allowed

So the unit of access in BTP is an API-level permission - "may write batches in this app" - not "may run transaction X". That single difference is why the traditional lens struggles.

Why the old lens fails

Why the tcode / Fiori-object model doesn't fit

For twenty years, Segregation of Duties in SAP meant transactions and authorization objects: a conflict is a pair of transactions one person should never hold together, and the rule engines were built entirely around that shape. A Fiori app doesn't change the underlying model either - it still resolves down to catalogs, transaction codes and the same authorization objects.

BTP has none of those anchors. There is no transaction code, no S_TCODE, no dynpro authorization object to match on. The unit is a scope - an app-native string describing a verb on a resource. A transaction-bound engine has literally nothing to grab: its entire vocabulary (transaction, authorization object, activity) does not exist on this surface.

So the classic approach has two options - ignore BTP altogether, or force each scope into a transaction shape it was never in. Which brings us to the workaround.

The tell

When you have to disguise a scope as a transaction

The common way to bring BTP into a transaction-bound engine is to make the scope look like a transaction. Excellent engineering has been published doing exactly that: a custom adapter maps XSUAA users, role collections, roles and scopes into the engine's structures, and - because the engine's action-level analysis only recognises a hardcoded whitelist of resource types (SAP transactions, services) - emits a second, shadow row that dresses each scope up as a transaction so the analysis can see it at all.

It works, and it is clever. But the shadow row is the tell: the engine was never designed to reason about anything that isn't an SAP transaction, so every new access model has to be translated back into one.

If a new surface only becomes visible to SoD by pretending to be a transaction, the model is fighting you.
What we have

An entitlement-model-agnostic SoD engine

smartGRC starts from a different assumption. Its risk engine is not wired to SAP transaction codes - it reasons about entitlements generically: an object and an activity, whatever system they came from. That single design choice is what makes the rest clean:

A BTP scope maps to a native entitlement, not a costumed transaction. An SAP transaction is one kind of entitlement; an XSUAA scope is another; a non-SAP permission is a third. They sit side by side in the same analysis - so a Segregation of Duties conflict can span BTP × SAP × non-SAP in a single rule. That hybrid conflict - for example, someone who can administer the BTP application that feeds a process and approve the outcome in S/4HANA - is exactly the kind an estate-spanning SoD picture needs, and exactly the kind a transaction-only engine struggles to express.

Two engine shapes
TRANSACTION-BOUND ENGINE SAP tcode Fiori catalog BTP scope non-SAP shadow row disguises as tcode ENGINE reasons about transactions + auth objects only SoD conflicts tcode pairs only ENTITLEMENT-AGNOSTIC ENGINE SAP tcode Fiori catalog BTP scope non-SAP ENGINE object + activity, source-agnostic - all first-class SoD conflicts BTP × SAP × non-SAP "Look like a tcode or become invisible." "Be what you are. Engine handles the rest."

No shadow rows. No whitelist to satisfy. The scope is first-class because the engine was built to be.

smartGRC vs SAP GRC AC

Two tools, two shapes of the problem

To be fair to Access Control: this isn't AC done wrong, it is AC asked to do something outside its shape. SAP GRC AC is a full governance suite - request, approve, provision, analyse and audit - deeply wired into classic SAP. For the classic SAP request-to-audit lifecycle it is mature and hard to beat, and that breadth is real.

smartGRC is deliberately narrower and differently built: a focused, model-agnostic SoD engine. Where the two overlap - analysing access for Segregation of Duties across a modern, hybrid, increasingly non-SAP estate - the design choices pull apart:

Segregation of DutiesSAP GRC AC 12.0smartGRC
Engine assumptionSAP transactions & auth objectsAny entitlement (object + activity), source-agnostic
New surface (e.g. BTP)Custom ABAP adapter + shadow-row disguiseConnector config; scope is first-class
CoverageSAP-centric; others bolted onSAP + non-SAP + BTP + AI / service, one model
Hybrid conflict (BTP × SAP)Hard to expressA single cross-system rule
FootprintHeavy ABAP add-on, upgrade weightLightweight service, low footprint
Onboarding a surfaceA development projectAdd a connector
Full request → provision → auditBroad and matureFocused on SoD; pairs with IAM / IAG for provisioning

The honest line: if the job is the end-to-end SAP request-to-audit lifecycle on classic SAP, AC is a heavyweight for a reason. If the job is Segregation of Duties across a hybrid estate - done lightly, without disguising every new surface as a transaction - smartGRC is built for that shape.

▚ Technical details for developers

How it works, in theory

The mechanism, not a build spec: how the BTP authorization data is read, how a scope maps into the SoD model, and why no shadow-row disguise is needed. The XSUAA calls below are the standard authorization model; the mapping is the part that differs from a GRC AC adapter.

1 · The read path (a REST connector). A new system type "BTP (XSUAA)" sits in the systems catalogue next to SAP ACC / S/4HANA. The connector authenticates with OAuth2 client-credentials against the subaccount token endpoint, then traverses:

GET /Users?filter=userName eq "..." and origin eq "..."   (SCIM)   -> user + groups[]
GET /Groups?attributes=id,displayName                     (SCIM)   -> role collections
GET /sap/rest/authorization/v2/rolecollections/<name>               -> role_references[]
GET /sap/rest/authorization/v2/apps/<app>/roletemplates/<t>/roles/<r> -> scopes[].name

Flatten to one row per scope: user → role collection → role → scope

2 · Parse the scope. Split xsappname.object.path.verb on the last dot so multi-segment paths survive:

aicore!b164.scenarios.batches.write
   object   = aicore!b164.scenarios.batches
   activity = write

3 · Map into smartGRC's model. Straight, no disguises:

BTP (XSUAA)smartGRC entitlement model
SubaccountSystem (connector)
Role collectionComposite role
RoleSingle role
ScopeObject = xsappname.object.path · Activity = verb

4 · Why no shadow row. The engine does not gate action-level analysis behind a hardcoded resource-type whitelist, so an object/activity pair sourced from a scope is analysed directly - the same code path as an SAP tcode, no S_TCODE/TCD stand-in. One representation, one row per scope.

5 · Engine vs connector vs content. The engine is unchanged (already source-agnostic - that's the whole point). New work is the connector (OAuth2 CC + SCIM + Authorization v2 REST client, fully documented by public XSUAA APIs) and the ruleset (defining BTP SoD functions and hybrid BTP×SAP conflicts worth shipping as a starter set).

Same pipeline as every other source: connector imports entitlements → analysis → the existing Access risks / Investigations views. Evidence already fits: Object = app.object.path, Activity = verb.

Where the real work is

Three problems - and only the middle one is the moat

Everything above makes it sound like a connector story. It isn't. Bringing BTP into Segregation of Duties splits into three problems, and they are not equal: two are engineering, one is judgement. The middle one is where the advantage actually lives.

1

Connect and pull the data

Authenticate against XSUAA, walk user → role collection → role → scope, land one row per scope. Bounded engineering - XSUAA APIs are public and documented.

Engineering · table stakes
2

Define what is actually risky on BTP

Not a coding problem. Which scope combinations are genuinely toxic? Is a given subaccount-admin scope, paired with a specific approval in S/4, a real conflict or just noise? Getting this right is domain knowledge - the ruleset itself becomes the differentiator.

Judgement · the moat
3

Report and investigate it

Surface conflicts, drill to evidence, track to closure. Once a scope is a first-class entitlement, this is what smartGRC already does natively - the same Access risks and Investigations views every other source flows into.

Engineering · already native

The connector is table stakes and the reporting is already ours. The scarce thing is knowing which BTP entitlement combinations are worth flagging in the first place - a ruleset that reflects how BTP actually grants power, not a translation of an SAP one. That is content, not code, and it is the part that has to be earned rather than shipped.

A connector anyone can write. A BTP risk model only someone who knows BTP can define. The content is the moat.

So what does "toxic on BTP" actually look like? Three illustrative conflicts a BTP-aware ruleset would carry - types worth defining, not a shipped rule pack. None of them exists in a transaction-based ruleset, because none of them is a transaction.

BTP-native · privilege self-grant
Manage role collections (Security administrator) + Any privileged business scope

Whoever assigns role collections can assign one to themselves. Control over entitlements and use of those entitlements collapse into a single identity - the most BTP-specific break there is, and completely invisible to a tcode-based ruleset because "grant yourself power" has no transaction code.

BTP-native · configure & use an interface
Manage destinations / connectivity + Run the integration that uses them

One person can point a live outbound connection - target URL and stored credentials - wherever they like, then trigger the flow that sends data through it. Define-and-execute with no second pair of eyes, on exactly the surface that moves data out of the estate.

Hybrid · BTP × S/4HANA
BTP Administer the automation / AI scenario that proposes a posting + S/4 Approve or post that document

Configure the automated maker on BTP and be the human checker in S/4 - the cross-system version of a maker-checker collapse. Expressible only if a scope and a transaction can sit in the same rule, which is the whole point of a source-agnostic engine.

These are the conflicts that decide whether BTP SoD is real or theatre. Writing them well takes someone who knows how BTP grants power - which is precisely why the ruleset, not the connector, is where the value concentrates.

The bigger picture

The same model covers service and AI identities

XSUAA does not only issue tokens to people. Client-credentials bindings authenticate application-to-application - the service accounts and AI agents that call BTP APIs. Because smartGRC treats non-human identities the same way it treats users - SoD analysis, sensitive-access flagging, and continuous monitoring on the accounts, not just the humans - BTP scopes and AI/service identities are the same frontier, handled by the same model. The SAP Audit Log gives the activity trail to close the loop.

The future of SoD isn't a better disguise.

It is an engine that treats an SAP transaction, a BTP scope, and a non-SAP entitlement as what they are - first-class, side by side, in one hybrid analysis. That is the bet smartGRC is built on.

See it live

See the hybrid SoD model in the smartGRC demo

A BTP scope, an SAP transaction, and a non-SAP entitlement - all sitting side by side in one analysis. No disguises. Try the workflow in the live demo.


Related reading