Oracle ERP Cloud Data Security Policies: API Impact for Integration Users
TL;DR
- Bottom line: Oracle ERP Cloud data security policies silently filter REST API responses at the database layer -- an integration user missing a data role or security context assignment will receive empty result sets or partial data with no error, making this the #1 cause of "missing data" in Oracle ERP Cloud integrations.
- Key limit: Users are denied access to all data by default; every data dimension (business unit, ledger, legal entity, inventory org) must be explicitly granted through data roles combining job roles with security profiles.
- Watch out for: A job role alone grants functional access (menu/page visibility) but zero data visibility -- you must pair it with a data role or explicit data access set assignment to see any records via API.
- Best for: Diagnosing incomplete API responses, configuring integration users for cross-business-unit data access, and understanding why Financials REST API endpoints return fewer records than expected.
- Authentication: Multi Token Over SSL (Basic Auth, SAML 2.0 Bearer, or JWT over HTTPS); authentication succeeds even when data security blocks all records -- you get HTTP 200 with empty results, not a 401/403. [src3]
System Profile
This card covers Oracle Fusion Cloud ERP (Releases 25A through 25D, covering 2025-2026) and how its data security framework affects REST API responses for integration users. The data security model applies uniformly across all Oracle Fusion Cloud ERP modules including Financials (GL, AP, AR, FA), Procurement, Project Portfolio Management, and Supply Chain Management. This card does NOT cover Oracle HCM Cloud security profiles, Oracle Integration Cloud adapter-level security, or OCI IAM policies.
| Property | Value |
|---|---|
| Vendor | Oracle |
| System | Oracle Fusion Cloud ERP (Release 25A-25D) |
| API Surface | REST (fscmRestApi) |
| Current API Version | 11.13.18.05 (Release 25A) |
| Editions Covered | All editions (data security is consistent across editions) |
| Deployment | Cloud |
| API Docs | Oracle Financials REST API |
| Status | GA |
API Surfaces & Capabilities
Oracle ERP Cloud exposes multiple API surfaces. Data security policies apply to all of them -- REST, SOAP, FBDI file imports, and BIP report extracts all respect the same underlying data security grants.
| API Surface | Protocol | Best For | Data Security Enforced? | Security Mechanism | Notes |
|---|---|---|---|---|---|
| REST (fscmRestApi) | HTTPS/JSON | Individual CRUD, queries, real-time | Yes | DB-layer WHERE clauses via ADF security | Primary integration surface |
| SOAP (composite services) | HTTPS/XML | Legacy integrations | Yes | Same OPSS/data security framework | Being phased out |
| FBDI (File-Based Data Import) | CSV via UCM | Bulk imports, data migration | Partially | Validates on write; user needs target BU access | Bypasses read-side filtering |
| BIP Reports | HTTPS/XML-CSV | Bulk data extracts, scheduled reporting | Yes | Report data security parameters | Ledger/BU parameters required |
| Business Events | REST/webhook | Event-driven, outbound notifications | Yes | Events fire only for data the user can access | Payload scope matches user scope |
Rate Limits & Quotas
Per-Request Limits
| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Default page size | 25 records | REST API collection responses | Configurable via limit parameter |
| Max page size | 500 records | REST API collection responses | Use offset for pagination beyond 500 |
| Max request body size | 50 MB | REST API POST/PATCH | Split larger payloads |
| FBDI file size | 250 MB | File-Based Data Import | Split across multiple files for larger loads |
Rolling / Daily Limits
| Limit Type | Value | Window | Notes |
|---|---|---|---|
| REST API calls | No published per-day cap | N/A | Oracle uses fair-use throttling |
| FBDI import jobs | No published cap | N/A | Throttled by ESS queue depth |
| BIP report executions | Configurable by admin | Per-tenant | Default concurrent limit configurable |
| Concurrent long-running requests | Managed by ESS | Per-tenant | ESS work manager thread pool limits |
Data Security Processing Overhead
| Security Dimension | Performance Impact | Mitigation |
|---|---|---|
| Business unit grants (< 5 BUs) | Negligible | Standard configuration |
| Business unit grants (> 20 BUs) | Noticeable query slowdown | Use "All Values" grant where audit allows |
| Cross-module security joins | Moderate (ledger + BU + legal entity) | Pre-build data roles with combined grants |
| Custom policies with complex SQL | Significant | Avoid subqueries; use indexed columns |
Authentication
Data security is independent of authentication method. All three supported auth flows respect the same data security policies.
| Flow | Use When | Token Lifetime | Refresh? | Notes |
|---|---|---|---|---|
| Basic Auth over SSL | Testing, simple integrations | Session-based (default 8h) | No | Easiest to set up |
| SAML 2.0 Bearer Token | Enterprise SSO, federated identity | Configurable (1-2h) | Yes (via IdP) | Requires SAML IdP configuration |
| JWT Token | Server-to-server, modern integrations | Configurable (1-2h) | New JWT per request | Recommended for production |
| OAuth 2.0 (via OCI IAM) | Cloud-native integrations | Access: 1h | Yes | Requires OCI IAM domain federation |
Authentication Gotchas
- Authentication succeeds even when data security blocks ALL data -- you get HTTP 200 with an empty
itemsarray, not a 401 or 403. This is the most common misdiagnosis. [src1] - Basic Auth credentials are tied to a specific Fusion user -- switching from Basic to JWT does not change data visibility unless you also change the underlying user. [src3]
- Session timeout can be changed by the Fusion administrator -- do not hardcode session duration assumptions. [src3]
Constraints
- Default-deny model: Users are denied access to all data by default. Every business unit, ledger, legal entity, and inventory organization must be explicitly granted through data roles or data access set assignments. [src1]
- Database-layer enforcement: Data security policies generate SQL WHERE clauses injected at the ADF database access layer. No REST API parameter, header, or flag can bypass data security filtering. [src1]
- Job role != data access: A job role grants functional privileges. A data role inherits the job role and adds a security profile restricting which DATA the user sees. Assigning only the job role gives zero data visibility. [src5]
- Independent security dimensions: Business unit access, ledger access (via data access sets), legal entity access, and inventory organization access are separate dimensions. Granting BU access does not automatically grant the corresponding ledger or legal entity. [src1]
- No cascading grants: Granting access to a parent organization does not cascade to child organizations. Each unit in each dimension must be individually granted or use an "All Values" grant. [src1]
- Session-scoped security: Data security grants are evaluated at session creation. Changes require the user to re-authenticate before new grants take effect. [src4]
Integration Pattern Decision Tree
START -- Integration user gets empty/incomplete data from Oracle ERP Cloud REST API
|
+-- Is authentication succeeding? (HTTP 200 returned?)
| +-- NO (401/403) --> Fix authentication credentials; NOT a data security issue
| +-- YES (200 with empty or partial results) --> Data security filtering is the cause
| |
| +-- Check 1: Does the integration user have a DATA ROLE (not just a job role)?
| | +-- NO --> Create a data role that inherits the job role + security profile
| | +-- YES --> Continue
| |
| +-- Check 2: Correct security context assignments?
| | +-- For Financials (AP/AR): BU assigned? Ledger via Data Access Set? Legal Entity?
| | +-- For Procurement: Procurement BU? Requisitioning BU?
| | +-- For Inventory/SCM: Inventory Organization? Manufacturing Plant?
| | +-- NO --> Add missing security context values
| | +-- YES --> Continue
| |
| +-- Check 3: Session refreshed after grant changes?
| | +-- NO --> Force new session (re-authenticate)
| | +-- YES --> Continue
| |
| +-- Check 4: Custom data security policies with restrictive conditions?
| | +-- YES --> Review instance set SQL WHERE clauses in Security Console
| | +-- NO --> Check module-specific feature opt-in requirements
| |
| +-- Check 5: Data visible in UI when logged in as integration user?
| +-- NO --> Data security configuration issue (fix in Security Console)
| +-- YES --> REST API-specific privilege requirements (check API duty roles)
Quick Reference
Data Security Components and Their Relationships
| Component | Definition | Scope | API Impact |
|---|---|---|---|
| Privilege | Single action on a business object | Per-object/action | Determines which CRUD operations succeed |
| Duty Role | Bundle of related privileges | Per-module | Must include REST API-specific duty roles |
| Job Role | Business role with multiple duty roles | Cross-module | Grants functional access but NOT data access alone |
| Data Role | Job role + security profile | Data-scoped | Controls which records API responses include |
| Security Profile | Defines which data a role can see | Per-dimension | WHERE-clause generator for DB queries |
| Data Access Set | GL-specific: which ledgers a user can access | GL module | Required separately from BU access for GL API calls |
| Security Context | Category of securable values (BU, Ledger, etc.) | Per-module | Each context is an independent filter dimension |
| Instance Set | SQL condition defining which records match | Per-grant | Directly translates to API response filtering |
| Grant | Authorization linking role + privilege + instance set | Per-user/role | The actual enforcement mechanism |
Security Context Dimensions by Module
| Module | Security Context | Typical Grant | API Resource Affected |
|---|---|---|---|
| General Ledger | Data Access Set (Ledger) | Specific ledgers or "All Ledgers" | /journals, /accountingPeriods |
| Accounts Payable | Business Unit | Specific BUs or "All BUs" | /invoices, /payments, /suppliers |
| Accounts Receivable | Business Unit | Specific BUs or "All BUs" | /receivablesInvoices, /receipts |
| Fixed Assets | Asset Book | Specific books | /assets, /assetBooks |
| Procurement | Procurement BU + Requisitioning BU | Specific BUs | /purchaseOrders, /requisitions |
| Inventory | Inventory Organization | Specific orgs | /inventoryItems, /inventoryTransactions |
| Project | Project Organization | Specific orgs | /projects, /projectTasks |
Step-by-Step Integration Guide
1. Verify integration user's current security assignments
Query the data securities REST endpoint to see what access the integration user currently has. [src7]
curl -u "INTEGRATION_USER:password" \
-X GET "https://your-instance.fa.us2.oraclecloud.com/fscmRestApi/resources/11.13.18.05/dataSecurities?q=UserName=INTEGRATION_USER" \
-H "Content-Type: application/vnd.oracle.adf.resourcecollection+json"
Verify: Response items array contains entries for each required security context. If empty, the user has no data access grants.
2. Assign the correct job role with API duty roles
Navigate to Security Console and assign the job role that includes the necessary REST API duty roles. [src2]
Navigation: Setup and Maintenance > Security Console > Users
1. Search for integration user
2. Click "Edit" > "Roles" tab
3. Add required job role (e.g., "Accounts Payable Manager")
4. Verify the job role includes REST API duty roles
Verify: In Security Console > Roles > search for the job role > "Privilege" tab, confirm REST-related privileges are present.
3. Create or assign a data role with security profile
The data role pairs the job role with a security profile to scope data visibility. [src1, src5]
Navigation: Setup and Maintenance > Manage Data Access for Users
1. Search for the integration user
2. Click "Add Data Access"
3. Select the role (e.g., "Accounts Payable Manager")
4. Select the security context (e.g., "Business Unit")
5. Select the value(s) (e.g., "US Operations BU", "EU Operations BU")
6. Save
Verify: curl the invoices endpoint and confirm records from the assigned BU appear.
4. Assign Data Access Sets for General Ledger
GL access requires separate Data Access Set assignment -- BU grants do not cascade to ledger access. [src1]
Navigation: Setup and Maintenance > Manage Data Access Set Assignments
1. Search for integration user
2. Add data access set (e.g., "US Primary Ledger Access Set")
3. Set access privileges: Read-Only or Read/Write
4. Save
Verify: Query the journals endpoint -- records from the assigned ledger should appear.
5. Force session refresh and validate
Data security changes require a fresh session. Re-authenticate after making grant changes. [src4]
curl -u "INTEGRATION_USER:password" \
-X GET "https://your-instance.fa.us2.oraclecloud.com/fscmRestApi/resources/11.13.18.05/invoices?limit=5&fields=InvoiceId,InvoiceNumber,BusinessUnit" \
-H "Content-Type: application/vnd.oracle.adf.resourcecollection+json" \
-H "Cache-Control: no-cache"
Verify: Response items array contains records with BusinessUnit values matching your assigned BUs.
Code Examples
Python: Diagnose data security grants for an integration user
# Input: Oracle Fusion Cloud base URL, integration user credentials
# Output: Dictionary of security context assignments per module
import requests
from requests.auth import HTTPBasicAuth
FUSION_BASE = "https://your-instance.fa.us2.oraclecloud.com"
API_PATH = "/fscmRestApi/resources/11.13.18.05"
USERNAME = "INTEGRATION_USER"
PASSWORD = "secure_password"
def get_data_security_assignments(username):
url = f"{FUSION_BASE}{API_PATH}/dataSecurities"
params = {"q": f"UserName={username}", "limit": "500"}
headers = {"Content-Type": "application/vnd.oracle.adf.resourcecollection+json"}
resp = requests.get(url, params=params,
auth=HTTPBasicAuth(USERNAME, PASSWORD),
headers=headers, timeout=30)
resp.raise_for_status()
return resp.json().get("items", [])
def diagnose_missing_data(username):
assignments = get_data_security_assignments(username)
contexts = {}
for a in assignments:
ctx = a.get("SecurityContext", "Unknown")
if ctx not in contexts:
contexts[ctx] = []
contexts[ctx].append(a.get("SecurityContextValue", "N/A"))
required = ["BusinessUnit", "Ledger", "LegalEntity"]
for r in required:
if r not in contexts:
print(f"WARNING: No {r} assignment found for {username}")
else:
print(f"OK: {r} -> {contexts[r]}")
return contexts
cURL: Quick test for data visibility per module
# Input: Valid credentials for the integration user
# Output: Record counts per module to verify data security grants
FUSION_BASE="https://your-instance.fa.us2.oraclecloud.com"
API="$FUSION_BASE/fscmRestApi/resources/11.13.18.05"
AUTH="INTEGRATION_USER:password"
echo "=== AP Invoices ==="
curl -s -u "$AUTH" "$API/invoices?limit=1&totalResults=true" \
-H "Content-Type: application/vnd.oracle.adf.resourcecollection+json" \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(f'Total: {d.get(\"totalResults\",\"N/A\")}')"
echo "=== GL Journals ==="
curl -s -u "$AUTH" "$API/journals?limit=1&totalResults=true" \
-H "Content-Type: application/vnd.oracle.adf.resourcecollection+json" \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(f'Total: {d.get(\"totalResults\",\"N/A\")}')"
# If any module returns Total: 0, the integration user
# is missing data security grants for that module
Data Mapping
Security Context to API Resource Mapping
| Security Context | Grant Type | API Resources Filtered | How to Check Assignment |
|---|---|---|---|
| Business Unit (AP) | Manage Data Access for Users | /invoices, /payments, /suppliers | GET /dataSecurities?q=SecurityContext=BusinessUnit |
| Business Unit (AR) | Manage Data Access for Users | /receivablesInvoices, /receipts | GET /dataSecurities?q=SecurityContext=BusinessUnit |
| Data Access Set (GL) | Manage Data Access Set Assignments | /journals, /accountingPeriods | Separate admin page; not in /dataSecurities |
| Legal Entity | Manage Data Access for Users | /legalEntities, tax resources | GET /dataSecurities?q=SecurityContext=LegalEntity |
| Asset Book | Manage Data Access for Users | /assets, /assetBooks | GET /dataSecurities?q=SecurityContext=AssetBook |
| Inventory Organization | Manage Inventory Org Data Access | /inventoryItems, /inventoryTransactions | Separate admin page for SCM |
| Procurement BU | Manage Data Access for Users | /purchaseOrders, /requisitions | GET /dataSecurities?q=SecurityContext=ProcurementBU |
Data Type Gotchas
- Business Unit IDs in data security assignments are internal numeric IDs, not human-readable BU names. Use
BusinessUnitIdfield for comparison, notBusinessUnit. [src1] - Data Access Set assignments for GL are managed through a different admin page and do NOT appear in the /dataSecurities REST endpoint. [src1]
- Security context values are case-sensitive in some Oracle Fusion releases. Ensure grant values match exactly what the system stores. [src5]
Error Handling & Failure Points
Common Error Codes
| Code | Meaning | Cause | Resolution |
|---|---|---|---|
| HTTP 200 + empty items | Data security filtering | User has no grants for requested dimension | Add data role / security context assignment |
| HTTP 200 + partial results | Partial data security grants | Grants for some BUs/ledgers but not all | Add missing security context values |
| HTTP 403 | Functional privilege denied | User lacks duty role / privilege for resource | Add required job role with API duty roles |
| HTTP 401 | Authentication failure | Invalid credentials or expired session | Re-authenticate; check password expiry |
| JBO-27122 | SQL data security error | Custom policy has invalid SQL in instance set | Fix instance set WHERE clause in Security Console |
| APJ-1 | Application privilege error | User role missing specific object privilege | Add missing privilege to duty/job role |
Failure Points in Production
- Silent data loss in API responses: API returns HTTP 200 with fewer records than expected because integration user lacks grants for certain BUs. No error, no warning. Fix:
Compare API totalResults against known-good count; alert on discrepancy. [src1] - Data access drift after org restructuring: When new BUs are added, integration user data roles are not automatically updated. Fix:
Include integration user access in org change management process. [src1] - GL journal extraction missing ledgers: GL uses Data Access Sets configured separately from BU access. Integration teams configure BU but forget GL-specific assignment. Fix:
Always configure Data Access Sets when integration touches GL data. [src1] - FBDI import succeeds but API read fails: User can import via FBDI but cannot read back via REST because read-side grant missing. Fix:
Ensure read and write grants match for all data dimensions. [src2] - Security grants not effective after assignment: Data security changes require session refresh. Fix:
After any change, invalidate existing API sessions by re-authenticating. [src4] - Custom policy performance degradation: Custom instance set SQL with non-indexed columns causes query slowdown. Fix:
Audit policies for performance; use indexed columns, avoid correlated subqueries. [src1]
Anti-Patterns
Wrong: Granting only a job role and expecting API data access
# WRONG -- job role alone gives functional access but zero data visibility
Setup steps (incorrect):
1. Create integration user
2. Assign job role: "Accounts Payable Manager"
3. Call /invoices API
4. Result: HTTP 200, items: [] (empty -- no error!)
Correct: Grant a data role that combines job role with security profile
# CORRECT -- data role = job role + security profile (data dimension)
Setup steps (correct):
1. Create integration user
2. Assign job role: "Accounts Payable Manager"
3. Navigate to: Manage Data Access for Users
4. Add data access: Role = AP Manager, Context = Business Unit, Value = "US Operations"
5. Call /invoices API
6. Result: HTTP 200, items: [invoices from US Operations BU]
Wrong: Assuming Business Unit access includes Ledger access
# WRONG -- BU and Ledger are independent security dimensions
Steps (incorrect):
1. Assign data access: BU = "US Operations" for AP Manager role
2. Call /journals API (General Ledger)
3. Result: HTTP 200, items: [] (empty -- ledger not granted!)
Correct: Configure each security dimension independently
# CORRECT -- grant BU access AND Data Access Set for GL separately
Steps (correct):
1. Assign data access: BU = "US Operations" for AP Manager role
2. ALSO: Manage Data Access Set Assignments > add "US Primary Ledger" for GL role
3. Call /journals API
4. Result: HTTP 200, items: [journal entries from US Primary Ledger]
Wrong: Using a super-user integration account with all-access grants
# WRONG -- violates least privilege, creates audit risk
Steps (incorrect):
1. Create integration user "INT_SUPER_USER"
2. Grant "All Values" for every security context
3. Use for all integrations regardless of scope
Correct: Create purpose-specific integration users with scoped access
# CORRECT -- each integration has its own user with minimum required access
Steps (correct):
1. Create "INT_AP_US" for US AP integration (AP Manager + BU = "US Operations" only)
2. Create "INT_GL_GLOBAL" for GL consolidation (GL Accountant + All Ledgers)
3. Create "INT_PO_EU" for EU procurement (Buyer + Procurement BU = "EU Procurement")
Common Pitfalls
- Confusing functional security with data security: Functional security controls which screens/actions; data security controls which records. The API equivalent: functional security determines 200 vs 403; data security determines whether the 200 has data in it. Fix:
Always configure both functional AND data security for integration users. [src1, src5] - Not testing with the integration user account: Developers test with their admin account (broad access) then deploy using the integration user (restricted). Fix:
Always test using actual integration user credentials. [src4] - Forgetting to refresh sessions after security changes: Grants are evaluated at session creation time. Fix:
After modifying data access, always re-authenticate before testing. [src4] - Ignoring cross-module security dependencies: Some operations span modules. Fix:
Map all security dimensions touched by each integration flow and grant all of them. [src1] - Using "All Values" grants without justification: Bypasses data security, creates audit findings. Fix:
Document business justification for every "All Values" grant. [src5] - Not monitoring for organizational changes: New BUs/ledgers do not automatically grant integration user access. Fix:
Integrate security access reviews into org change management. [src1]
Diagnostic Commands
# Check integration user's data security assignments
curl -s -u "INT_USER:password" \
"https://your-instance.fa.us2.oraclecloud.com/fscmRestApi/resources/11.13.18.05/dataSecurities" \
-H "Content-Type: application/vnd.oracle.adf.resourcecollection+json" \
| python3 -m json.tool
# Test AP invoice visibility (should return records if BU access granted)
curl -s -u "INT_USER:password" \
"https://your-instance.fa.us2.oraclecloud.com/fscmRestApi/resources/11.13.18.05/invoices?limit=1&totalResults=true" \
-H "Content-Type: application/vnd.oracle.adf.resourcecollection+json"
# Test GL journal visibility (requires separate Data Access Set)
curl -s -u "INT_USER:password" \
"https://your-instance.fa.us2.oraclecloud.com/fscmRestApi/resources/11.13.18.05/journals?limit=1&totalResults=true" \
-H "Content-Type: application/vnd.oracle.adf.resourcecollection+json"
# Verify which business units the user can see
curl -s -u "INT_USER:password" \
"https://your-instance.fa.us2.oraclecloud.com/fscmRestApi/resources/11.13.18.05/businessUnits?limit=500&totalResults=true" \
-H "Content-Type: application/vnd.oracle.adf.resourcecollection+json"
# Describe an API resource to check available fields and privileges
curl -s -u "INT_USER:password" \
"https://your-instance.fa.us2.oraclecloud.com/fscmRestApi/resources/11.13.18.05/invoices/describe" \
-H "Content-Type: application/vnd.oracle.adf.resourcecollection+json"
Version History & Compatibility
| Release | Date | Status | Data Security Changes | Notes |
|---|---|---|---|---|
| 25D | 2025-11 | Current | Enhanced data sovereignty controls | AI analytics for security audit |
| 25C | 2025-08 | Supported | No breaking changes | Minor security UI improvements |
| 25B | 2025-05 | Supported | No breaking changes | -- |
| 25A | 2025-02 | Supported | Data securities REST endpoint added | First release with programmatic security query |
| 24D | 2024-11 | Supported | Improved security context management UI | -- |
| 24C | 2024-08 | Supported | No breaking changes | -- |
When to Use / When Not to Use
| Use When | Don't Use When | Use Instead |
|---|---|---|
| Integration user returns empty API results despite valid auth | User gets HTTP 401/403 | Standard auth troubleshooting |
| Need to scope integration data to specific business units | Need to control which REST endpoints are accessible | Functional security (job roles and API duty roles) |
| Configuring new integration user for cross-module access | Setting up OIC adapter connections | OIC adapter security configuration |
| Auditing what data an integration can see vs should see | Troubleshooting API performance unrelated to security | API performance tuning |
Important Caveats
- Data security policy enforcement is consistent across all Oracle Fusion Cloud ERP editions -- no edition-specific differences in how data security filters API responses.
- Sandbox environments have separate security configurations from production. Data access grants do not replicate automatically between environments.
- Data security policies generate SQL WHERE clauses at runtime. Complex custom policies with non-indexed conditions can cause significant performance degradation on high-volume API calls.
- The /dataSecurities REST endpoint (Release 25A+) returns BU and context assignments but does NOT return Data Access Set assignments for GL -- those must be checked via UI or BIP report.
- Oracle's quarterly release cycle may introduce new security contexts. Integration users may need additional grants when new modules are enabled. Always review release notes for security changes.