> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/connector-configuration/sap/sap-reference.md).

# SAP S/4HANA reference

What the SAP S/4HANA connector reads from SAP and how OpenIAM stores it — the role-content searches, the filter syntax, the roles and groups each SAP object becomes, the shipped metadata types and syn

Companion to [SAP S/4HANA connector](/connector-configuration/sap.md), which covers installing and configuring it. This page is the lookup material: what each search reads, what OpenIAM stores it as, and what a synchronization takes away again.

## Role-content searches

A group search picks what to read from a prefix on the sync query, written `<prefix>:<role pattern>`. ROLE syncs use the same prefixes. Without a prefix the search behaves as `role:`.

| Prefix                   | Reads from SAP                                                                                                                   | Returns per role                                                                                                                                    |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `role:` *(or no prefix)* | `AGR_DEFINE`, `AGR_TEXTS`, `AGR_AGRS`                                                                                            | `name`, `description`, `PARENT_ROLE` for derived roles, and `ROLE_TYPE` — one of `SINGLE`, `COMPOSITE`, `MASTER` or `DERIVED`                       |
| `roleauth:`              | `AGR_1251`, org levels from `AGR_1252`, texts from `TOBJT`, `AUTHX`, `DD04T`, `TSTCT`, `TACTT`, `T001`, `T001W`, `T024E`, `T024` | `AUTHORIZATIONS`, one value per entry: `object:<OBJ>;auth:<AUTH>;field:<FIELD>;low:<LOW>;high:<HIGH>;objectText:…;fieldText:…;valueText:…`          |
| `tcode:`                 | `AGR_1251`, `S_TCODE` / `TCD` rows only; texts from `TSTCT`                                                                      | `TCODES` and `TCODE_TEXTS`                                                                                                                          |
| `composite:`             | `AGR_AGRS`                                                                                                                       | `CHILD_ROLES`                                                                                                                                       |
| `menu:`                  | `AGR_TCODES`, texts from `TSTCT`                                                                                                 | `MENU_ITEMS`, one entry each: `kind:<KIND>;name:<NAME>;text:<TEXT>` — `TCD` for a transaction, otherwise the repository object type, such as `WDYA` |
| `profile:`, `group:`     | unchanged                                                                                                                        | unchanged                                                                                                                                           |

{% hint style="info" %}
**Transaction codes come from `AGR_1251`, not `AGR_TCODES`.** `AGR_1251` holds the `S_TCODE` authorization, which is what SAP actually enforces; `AGR_TCODES` is only the role menu. The two differ whenever a menu lists a transaction the role cannot run, or a role grants one its menu never shows. `menu:` reads the menu precisely because it answers a different question.
{% endhint %}

## Filter syntax

* **Only `*` is a wildcard** — `Z_*`, `/SCWM/*`, or `*` for every role.
* **`_` is a literal character.** `Z_*` selects roles beginning `Z_`, not every role beginning with `Z`.
* **The older `AGR_NAME LIKE '%SCWM%'` form still works**; `%` is read as `*`.

## How the searches behave

* **Organizational-level placeholders are resolved.** A value such as `$BUKRS` is replaced with the role's own values from `AGR_1252`. A placeholder with no value maintained comes back unchanged, so a `$WERKS` left in the output means SAP has nothing to fill it with.
* **Rows flagged deleted in `AGR_1251` are skipped.**
* **Description tables are optional.** If SAP refuses a read, the description is left empty and the search continues; a lost connection is still a failure. An empty description is therefore not evidence that a text table was unreadable.
* **Role names are trimmed.** SAP role names are 30-character padded fields, and the padding is removed so that a later sync matches the role it created.

## What OpenIAM stores

Each SAP role becomes an OpenIAM role, and each authorization value becomes one OpenIAM **group** that roles link to. A role therefore shows exactly which values it grants — change access on company code 1000, say — rather than only its name.

| SAP object                       | Stored as                                                                      | Name format                                                                                  | Metadata type             |
| -------------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | ------------------------- |
| Single role                      | Role                                                                           | the SAP role name                                                                            | `SAP_ROLE`                |
| Composite role                   | Role, with its single roles as child roles                                     | the SAP role name                                                                            | `SAP_COMPOSITE_ROLE`      |
| Master role                      | Role                                                                           | the SAP role name                                                                            | `SAP_MASTER_ROLE`         |
| Derived role                     | Role, with `PARENT_ROLE` naming its master                                     | the SAP role name                                                                            | `SAP_DERIVED_ROLE`        |
| Authorization value (`AGR_1251`) | Group linked to the role                                                       | `OBJECT:FIELD=VALUE`, such as `F_BKPF_BUK:ACTVT=02`; a range as `F_BKPF_BUK:BUKRS=1000-1999` | `SAP_AUTHORIZATION_GROUP` |
| Transaction (`S_TCODE`)          | Group linked to the role                                                       | `S_TCODE:TCD=FB60`                                                                           | `SAP_TCODE_GROUP`         |
| Menu item (`AGR_TCODES`)         | Group linked to the role                                                       | `MENU:TCD=FB60`, `MENU:WDYA=POWL`                                                            | `SAP_MENU_GROUP`          |
| A user's role assignment         | Role membership, carrying SAP's `FROM_DAT` and `TO_DAT` as start and end dates | —                                                                                            | —                         |

Five things follow from that model:

* **Groups are shared.** The same value held by many roles is one group linked to all of them, so a group's members answer the question "which roles grant this".
* **Group descriptions come from SAP's own texts.** A transaction group takes its transaction text (*Enter Incoming Invoices*); an authorization group takes object text — field text: value text (*Accounting Document — Activity: Change*).
* **Menu groups are not access.** They record what a user sees in the SAP menu and are kept apart from `S_TCODE` groups deliberately. Reading a menu group as a grant overstates what the role can do.
* **SAP's open end date `31.12.9999` is stored as no end date.** Assignments that have already ended in SAP arrive expired rather than absent.
* **Roles held only through a composite are not direct memberships.** They reach the user through the composite's child roles, so the same access is not counted twice.

## Metadata types

The database migration adds seven types with fixed IDs — the same on PostgreSQL, MySQL, MSSQL and Oracle — so the shipped scripts work on every install.

| Type ID                   | Name                   | Grouping   | Synced to the managed system |
| ------------------------- | ---------------------- | ---------- | ---------------------------- |
| `SAP_ROLE`                | SAP-Role               | Role type  | Yes                          |
| `SAP_COMPOSITE_ROLE`      | SAP-Composite-Role     | Role type  | Yes                          |
| `SAP_MASTER_ROLE`         | SAP-Master-Role        | Role type  | Yes                          |
| `SAP_DERIVED_ROLE`        | SAP-Derived-Role       | Role type  | Yes                          |
| `SAP_AUTHORIZATION_GROUP` | SAP-Authorization-Type | Group type | No                           |
| `SAP_TCODE_GROUP`         | SAP-TCode-Type         | Group type | No                           |
| `SAP_MENU_GROUP`          | SAP-MenuRole-Type      | Group type | No                           |

The three group types are not synced to the managed system because those groups only describe SAP access. They are never provisioned back to SAP.

## Shipped synchronizations

A fresh install has five SAP synchronizations, all on managed system `200`, active, with no schedule and no provisioning back to SAP.

| Synchronization             | Query               | Transformation script                                   | Attributes script                             |
| --------------------------- | ------------------- | ------------------------------------------------------- | --------------------------------------------- |
| SAP Role Sync               | `role:*`            | `role/sap/SAPRoleSampleTransformationScript`            | `role/sap/SAPRoleSyncAttributes`              |
| SAP Composite Role Sync     | `composite:*`       | `role/sap/SAPCompositeRoleLinkTransformationScript`     | `role/sap/SAPCompositeRoleSyncAttributes`     |
| SAP Role Authorization Sync | `roleauth:*`        | `role/sap/SAPRoleAuthorizationLinkTransformationScript` | `role/sap/SAPRoleAuthorizationSyncAttributes` |
| SAP Role Menu Sync          | `menu:*`            | `role/sap/SAPRoleMenuLinkTransformationScript`          | `role/sap/SAPRoleMenuSyncAttributes`          |
| SAP User Sync               | `USERNAME LIKE '%'` | `user/sap/SAPUserSampleTransformation`                  | `user/sap/SAPUserSyncAttributes`              |

All script paths sit under `/sync/`. The role syncs validate with `role/sap/SAPRoleSampleValidationScript`, the user sync with `user/sap/SAPUserSampleValidation`. Role syncs match on role name (`NAME = name`); the user sync matches on login (`PRINCIPAL = USERNAME`).

The SAP EWM, TM, Custom EWM and Custom TM group syncs also ship by default.

{% hint style="warning" %}
**Run the role sync first.** The other three role syncs only link roles it has created, so running them against an empty catalog links nothing — and reports no error while doing it. The three link syncs can then run in any order. **Run the user sync last**, so that the roles it assigns already carry their content.
{% endhint %}

## What a synchronization removes

Every sync also removes what SAP no longer has, so access taken away in SAP disappears from OpenIAM on the next run. Groups and roles are **unlinked, never deleted**.

| Synchronization             | Removes when SAP no longer has it              |
| --------------------------- | ---------------------------------------------- |
| SAP Composite Role Sync     | a single role's link to its composite          |
| SAP Role Authorization Sync | a role's link to an `OBJECT:FIELD=VALUE` group |
| SAP Role Menu Sync          | a role's link to a `MENU:` group               |
| SAP User Sync               | a user's SAP role                              |

Worked through: role `Z_AP_CLERK` held `F_BKPF_BUK:ACTVT=02`, change access. SAP removes it, leaving the role able only to display. On the next Role Authorization Sync OpenIAM unlinks that group, and the role stops showing change access.

### What removal will not do

These rules exist so that a failed read is never mistaken for revoked access.

* **Only roles and groups on the sync's own managed system are touched.**
* **Only groups the sync itself named are unlinked** — `OBJECT:FIELD=VALUE` and `MENU:` groups. Anything else, including older object-only groups, is left alone.
* **Nothing is removed for an object SAP sent no data for**, so an empty or failed read cannot wipe access.
* **Composite links are removed only when every child role SAP lists already exists in OpenIAM**, so a partially loaded catalog does not unpick composites.
* **Groups for unresolved placeholders are never unlinked** — a group named `…=$WERKS` stays.
* **The user sync trusts a count, not an absence.** A role count of `0` removes all of a user's SAP roles; a count that does not match the number of roles read removes nothing and logs a warning.

## Known limitations

* **Deleted or emptied composites keep their links.** A composite that SAP deletes, or one left with no single roles, is no longer returned by the search — so its links stay until someone removes them by hand.
* **No master-to-derived link.** A derived role carries `PARENT_ROLE` as an attribute; the relationship is not modeled.
* **`USOBT_C` is not read**, so there is no data on which authorization checks a transaction performs.
* **User groups (`USGRP`) can be searched but not assigned.** Assigning one to a user is not implemented.
* **Roles cannot be created or deleted in SAP from OpenIAM.**


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/connector-configuration/sap/sap-reference.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
