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:
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:
| Part | Example | Meaning |
|---|---|---|
xsappname | aicore!b164 | the application (identifier) |
object | scenarios | business object / domain |
path | batches | sub-resource or functional path |
verb | write | the 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 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.
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.
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.
No shadow rows. No whitelist to satisfy. The scope is first-class because the engine was built to be.
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 Duties | SAP GRC AC 12.0 | smartGRC |
|---|---|---|
| Engine assumption | SAP transactions & auth objects | Any entitlement (object + activity), source-agnostic |
| New surface (e.g. BTP) | Custom ABAP adapter + shadow-row disguise | Connector config; scope is first-class |
| Coverage | SAP-centric; others bolted on | SAP + non-SAP + BTP + AI / service, one model |
| Hybrid conflict (BTP × SAP) | Hard to express | A single cross-system rule |
| Footprint | Heavy ABAP add-on, upgrade weight | Lightweight service, low footprint |
| Onboarding a surface | A development project | Add a connector |
| Full request → provision → audit | Broad and mature | Focused 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.
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 |
|---|---|
| Subaccount | System (connector) |
| Role collection | Composite role |
| Role | Single role |
| Scope | Object = 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.
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.
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 stakesDefine 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 moatReport 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 nativeThe 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.
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.
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.
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.
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 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.
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 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
Intelligent SoD Reporting
How AI turns SAP access risk into audit-grade evidence. From 4 000 flags to a defensible shortlist.
Monitor an AI agent in SAP
Exception-based review for machine-speed activity. Whitelist + blacklist policy per account, real-time alerts.
IAM vs GRC: what is the difference
Modular integration angle - where IAM ends and GRC begins, and how they pair for hybrid estates.