SAP SuccessFactors Hardening Guide
HCM security for permission groups, integration center, and data protection
Overview
SAP SuccessFactors is a global enterprise HCM with deep SAP ecosystem integration. OData and SOAP APIs, OAuth client configurations, and SAP Business Technology Platform connections handle employee master data, payroll, and performance records across multinationals. Sub-processor data flows create complex third-party risk.
Intended Audience
- Security engineers managing HCM systems
- SAP administrators configuring SuccessFactors
- GRC professionals assessing HR compliance
- Third-party risk managers evaluating SAP integrations
How to Use This Guide
- L1 (Baseline): Essential controls for all organizations
- L2 (Hardened): Enhanced controls for security-sensitive environments
- L3 (Maximum Security): Strictest controls for regulated industries
Scope
This guide covers SAP SuccessFactors security configurations including authentication, access controls, and integration security.
Table of Contents
1. Authentication & Access Controls
1.1 Configure SSO with MFA
Profile Level: L1 (Baseline) NIST 800-53: IA-2(1)
ClickOps Implementation
Step 1: Configure SAML SSO
- Navigate to: Admin Center → Company Settings → Single Sign On
- Configure IdP metadata
- Enable: Enforce SSO
Step 2: Configure IDP-Initiated SSO
- Map SAML assertions to SF users
- Configure attribute mapping
- Enable session management
Code Implementation
Code Pack: Terraform
# Configure a trusted Identity Provider for SAML SSO
resource "btp_subaccount_trust_configuration" "corporate_idp" {
subaccount_id = var.btp_subaccount_id
name = var.idp_name
description = "HTH: Corporate IdP for SuccessFactors SSO with MFA enforcement"
origin = "corporate-idp"
identity_provider = var.idp_metadata_url
# Enforce SSO -- disable password fallback
status = var.enforce_sso ? "active" : "active"
}
# L2+: Create a dedicated IAS tenant subscription for advanced SSO controls
resource "btp_subaccount_subscription" "identity_authentication" {
count = var.profile_level >= 2 ? 1 : 0
subaccount_id = var.btp_subaccount_id
app_name = "identity"
plan_name = "application"
parameters = jsonencode({
cloud_service = {
name = "sap-successfactors"
}
})
}
# L3: Enforce certificate-based authentication for admin access
resource "btp_subaccount_service_instance" "x509_auth" {
count = var.profile_level >= 3 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "hth-sf-x509-auth"
serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
parameters = jsonencode({
xsappname = "hth-sf-admin-x509"
tenant-mode = "dedicated"
credential-types = ["x509"]
oauth2-configuration = {
token-validity = 3600
}
})
}
data "btp_subaccount_service_plan" "xsuaa_application" {
subaccount_id = var.btp_subaccount_id
name = "application"
offering_name = "xsuaa"
}
1.2 Role-Based Permissions (RBP)
Profile Level: L1 (Baseline) NIST 800-53: AC-3, AC-6
ClickOps Implementation
Step 1: Define Permission Roles
| Role | Permissions |
|---|---|
| System Admin | Full access (limit users) |
| HR Admin | Employee data management |
| Manager | Team access only |
| Employee | Self-service only |
Step 2: Configure Permission Groups
- Navigate to: Admin Center → Manage Permission Roles
- Create permission groups
- Assign target populations
Code Implementation
Code Pack: Terraform
# Create a role collection for SuccessFactors System Administrators (minimal users)
resource "btp_subaccount_role_collection" "sf_system_admin" {
subaccount_id = var.btp_subaccount_id
name = "HTH SF System Admin"
description = "HTH: Restricted system admin role -- limit to essential personnel only"
roles {
name = "Subaccount Administrator"
role_template_app_id = "cis-local!b2"
role_template_name = "Subaccount_Admin"
}
}
# Assign system admin role to explicitly listed users only
resource "btp_subaccount_role_collection_assignment" "sf_admin_users" {
for_each = toset(var.admin_users)
subaccount_id = var.btp_subaccount_id
role_collection_name = btp_subaccount_role_collection.sf_system_admin.name
user_name = each.value
origin = "corporate-idp"
}
# Create a role collection for HR Administrators
resource "btp_subaccount_role_collection" "sf_hr_admin" {
subaccount_id = var.btp_subaccount_id
name = "HTH SF HR Admin"
description = "HTH: HR admin role -- employee data management only, no system config"
roles {
name = "Subaccount Viewer"
role_template_app_id = "cis-local!b2"
role_template_name = "Subaccount_Viewer"
}
}
# Assign HR admin role to explicitly listed users
resource "btp_subaccount_role_collection_assignment" "sf_hr_admin_users" {
for_each = toset(var.hr_admin_users)
subaccount_id = var.btp_subaccount_id
role_collection_name = btp_subaccount_role_collection.sf_hr_admin.name
user_name = each.value
origin = "corporate-idp"
}
# L2+: Create a read-only auditor role for separation of duties
resource "btp_subaccount_role_collection" "sf_auditor" {
count = var.profile_level >= 2 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "HTH SF Auditor"
description = "HTH: Read-only auditor role for compliance review -- no write access"
roles {
name = "Subaccount Viewer"
role_template_app_id = "cis-local!b2"
role_template_name = "Subaccount_Viewer"
}
}
2. API Security
2.1 Secure OData API Access
Profile Level: L1 (Baseline) NIST 800-53: IA-5
Description
Harden OData API integrations.
Rationale
Attack Scenario: Compromised OAuth client accesses Compound Employee API; sub-processor data flows expose global workforce data.
Implementation
Step 1: Create Integration Users
- Navigate to: Admin Center → Manage OAuth2 Client Applications
- Create dedicated OAuth clients per integration
- Assign minimum required permissions
Step 2: Configure API Permissions
- Limit OData entity access
- Configure field-level restrictions
- Enable audit logging
Code Implementation
Code Pack: Terraform
# Create a dedicated XSUAA service instance for OData API integration
resource "btp_subaccount_service_instance" "sf_odata_oauth" {
subaccount_id = var.btp_subaccount_id
name = "hth-sf-odata-${var.oauth_client_name}"
serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
parameters = jsonencode({
xsappname = var.oauth_client_name
tenant-mode = "dedicated"
scopes = [
{
name = "$XSAPPNAME.employee.read"
description = "Read employee data via OData"
}
]
role-templates = [
{
name = "ODataReader"
description = "HTH: Minimum-privilege OData API reader"
scope-references = [
"$XSAPPNAME.employee.read"
]
}
]
oauth2-configuration = {
token-validity = var.access_token_validity_seconds
refresh-token-validity = var.refresh_token_validity_seconds
credential-types = ["binding-secret"]
}
})
}
# Create a service binding (credentials) for the OAuth client
resource "btp_subaccount_service_binding" "sf_odata_binding" {
subaccount_id = var.btp_subaccount_id
name = "hth-sf-odata-binding"
service_instance_id = btp_subaccount_service_instance.sf_odata_oauth.id
}
# L2+: Create an IP-restricted destination for OData API calls
resource "btp_subaccount_service_instance" "sf_destination" {
count = var.profile_level >= 2 && length(var.api_allowed_ip_cidrs) > 0 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "hth-sf-api-destination"
serviceplan_id = data.btp_subaccount_service_plan.destination_lite.id
parameters = jsonencode({
HTML5Runtime_enabled = false
init_data = {
subaccount = {
destinations = [
{
Name = "HTH-SuccessFactors-OData"
Type = "HTTP"
URL = "https://api.successfactors.com/odata/v2"
Authentication = "OAuth2SAMLBearerAssertion"
ProxyType = "Internet"
"ip.filter.allowedCIDRs" = join(",", var.api_allowed_ip_cidrs)
}
]
}
}
})
}
data "btp_subaccount_service_plan" "destination_lite" {
subaccount_id = var.btp_subaccount_id
name = "lite"
offering_name = "destination"
}
# L3: Enforce mTLS for all API client connections
resource "btp_subaccount_service_instance" "sf_odata_mtls" {
count = var.profile_level >= 3 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "hth-sf-odata-mtls"
serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
parameters = jsonencode({
xsappname = "${var.oauth_client_name}-mtls"
tenant-mode = "dedicated"
credential-types = ["x509"]
oauth2-configuration = {
token-validity = var.access_token_validity_seconds
refresh-token-validity = var.refresh_token_validity_seconds
credential-types = ["x509"]
}
})
}
2.2 OAuth Token Management
Profile Level: L1 (Baseline) NIST 800-53: IA-5(13)
Implementation
| Token Type | Expiration |
|---|---|
| Access Token | 1 hour |
| Refresh Token | 24 hours (L1) / 8 hours (L2) |
Code Implementation
Code Pack: Terraform
# Token management is primarily handled through the XSUAA service instance
# parameters in control 2.1. This file enforces token lifetime governance
# through a dedicated service instance with strict expiration policies.
# L1: Standard token governance service instance
resource "btp_subaccount_service_instance" "sf_token_governance" {
subaccount_id = var.btp_subaccount_id
name = "hth-sf-token-governance"
serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
parameters = jsonencode({
xsappname = "hth-sf-token-gov"
tenant-mode = "dedicated"
oauth2-configuration = {
# L1: Access token = 1 hour, Refresh token = 24 hours
token-validity = var.access_token_validity_seconds
refresh-token-validity = var.refresh_token_validity_seconds
# Disable client credentials grant to prevent unattended token minting
grant-types = [
"authorization_code",
"refresh_token"
]
redirect-uris = []
}
})
}
# L2+: Enforce tighter refresh token lifetime (8 hours)
resource "btp_subaccount_service_instance" "sf_token_governance_l2" {
count = var.profile_level >= 2 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "hth-sf-token-governance-l2"
serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
parameters = jsonencode({
xsappname = "hth-sf-token-gov-l2"
tenant-mode = "dedicated"
oauth2-configuration = {
# L2: Access token = 1 hour, Refresh token = 8 hours
token-validity = 3600
refresh-token-validity = 28800
grant-types = [
"authorization_code",
"refresh_token"
]
redirect-uris = []
}
})
}
# L3: Disable refresh tokens entirely -- require re-authentication
resource "btp_subaccount_service_instance" "sf_token_governance_l3" {
count = var.profile_level >= 3 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "hth-sf-token-governance-l3"
serviceplan_id = data.btp_subaccount_service_plan.xsuaa_application.id
parameters = jsonencode({
xsappname = "hth-sf-token-gov-l3"
tenant-mode = "dedicated"
oauth2-configuration = {
# L3: Access token = 30 minutes, no refresh tokens
token-validity = 1800
grant-types = [
"authorization_code"
]
redirect-uris = []
}
})
}
3. Data Security
3.1 Configure Data Privacy
Profile Level: L1 (Baseline) NIST 800-53: SC-28
ClickOps Implementation
Step 1: Enable Data Protection
- Navigate to: Admin Center → Data Protection & Privacy
- Configure:
- Personal data handling
- Consent management
- Data retention
Step 2: Field-Level Security
- Configure sensitive field masking
- Restrict SSN/Tax ID visibility
- Enable audit for sensitive data access
Code Implementation
Code Pack: Terraform
# Enable the Data Privacy Integration service for SuccessFactors
resource "btp_subaccount_entitlement" "data_privacy" {
subaccount_id = var.btp_subaccount_id
service_name = "data-privacy-integration-service"
plan_name = "standard"
}
resource "btp_subaccount_service_instance" "data_privacy" {
subaccount_id = var.btp_subaccount_id
name = "hth-sf-data-privacy"
serviceplan_id = data.btp_subaccount_service_plan.dpi_standard.id
parameters = jsonencode({
xs-security = {
xsappname = "hth-sf-dpi"
tenant-mode = "dedicated"
}
retention = {
# Data retention period after employee termination
defaultRetentionDays = var.data_retention_days
}
})
depends_on = [btp_subaccount_entitlement.data_privacy]
}
data "btp_subaccount_service_plan" "dpi_standard" {
subaccount_id = var.btp_subaccount_id
name = "standard"
offering_name = "data-privacy-integration-service"
}
# L1: Create role collection for data privacy officers
resource "btp_subaccount_role_collection" "data_privacy_officer" {
subaccount_id = var.btp_subaccount_id
name = "HTH SF Data Privacy Officer"
description = "HTH: Manages data protection, consent, and retention policies"
roles {
name = "Subaccount Viewer"
role_template_app_id = "cis-local!b2"
role_template_name = "Subaccount_Viewer"
}
}
# L2+: Enable Personal Data Manager for field-level security
resource "btp_subaccount_entitlement" "personal_data_manager" {
count = var.profile_level >= 2 ? 1 : 0
subaccount_id = var.btp_subaccount_id
service_name = "personal-data-manager-service"
plan_name = "standard"
}
resource "btp_subaccount_service_instance" "personal_data_manager" {
count = var.profile_level >= 2 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "hth-sf-pdm"
serviceplan_id = data.btp_subaccount_service_plan.pdm_standard[0].id
parameters = jsonencode({
xs-security = {
xsappname = "hth-sf-pdm"
tenant-mode = "dedicated"
}
sensitiveFields = var.sensitive_field_names
masking = {
enabled = var.mask_sensitive_fields
maskCharacter = "*"
visibleChars = 4
}
})
depends_on = [btp_subaccount_entitlement.personal_data_manager]
}
data "btp_subaccount_service_plan" "pdm_standard" {
count = var.profile_level >= 2 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "standard"
offering_name = "personal-data-manager-service"
}
# L3: Enable data residency enforcement (restrict data to specific regions)
resource "btp_subaccount_service_instance" "data_residency" {
count = var.profile_level >= 3 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "hth-sf-data-residency"
serviceplan_id = data.btp_subaccount_service_plan.dpi_standard.id
parameters = jsonencode({
xs-security = {
xsappname = "hth-sf-data-residency"
tenant-mode = "dedicated"
}
retention = {
defaultRetentionDays = var.data_retention_days
}
dataResidency = {
enforced = true
}
})
}
4. Monitoring & Detection
4.1 Audit Logging
Profile Level: L1 (Baseline) NIST 800-53: AU-2, AU-3
ClickOps Implementation
Step 1: Enable Audit Trail
- Navigate to: Admin Center → Audit Logging
- Enable comprehensive logging
- Configure retention
Detection Focus
Code Pack: Terraform
# Enable the SAP Audit Log service for SuccessFactors
resource "btp_subaccount_entitlement" "audit_log" {
subaccount_id = var.btp_subaccount_id
service_name = "auditlog-management"
plan_name = "default"
}
resource "btp_subaccount_service_instance" "audit_log" {
subaccount_id = var.btp_subaccount_id
name = "hth-sf-audit-log"
serviceplan_id = data.btp_subaccount_service_plan.audit_log_default.id
parameters = jsonencode({
retentionPeriod = var.audit_retention_days
})
depends_on = [btp_subaccount_entitlement.audit_log]
}
data "btp_subaccount_service_plan" "audit_log_default" {
subaccount_id = var.btp_subaccount_id
name = "default"
offering_name = "auditlog-management"
}
# Create a service binding for audit log API access
resource "btp_subaccount_service_binding" "audit_log_binding" {
subaccount_id = var.btp_subaccount_id
name = "hth-sf-audit-log-binding"
service_instance_id = btp_subaccount_service_instance.audit_log.id
}
# Role collection for audit log viewers
resource "btp_subaccount_role_collection" "audit_viewer" {
subaccount_id = var.btp_subaccount_id
name = "HTH SF Audit Viewer"
description = "HTH: Read-only access to SuccessFactors audit logs"
roles {
name = "Subaccount Viewer"
role_template_app_id = "cis-local!b2"
role_template_name = "Subaccount_Viewer"
}
}
# L2+: Enable SIEM integration via webhook for real-time audit event forwarding
resource "btp_subaccount_service_instance" "audit_siem_webhook" {
count = var.profile_level >= 2 && var.siem_webhook_url != "" ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "hth-sf-audit-siem-webhook"
serviceplan_id = data.btp_subaccount_service_plan.audit_log_default.id
parameters = jsonencode({
retentionPeriod = var.audit_retention_days
webhook = {
url = var.siem_webhook_url
enabled = true
events = ["security", "data-access", "configuration-change"]
}
})
depends_on = [btp_subaccount_entitlement.audit_log]
}
# L2+: Extended audit retention (730 days)
resource "btp_subaccount_service_instance" "audit_log_extended" {
count = var.profile_level >= 2 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "hth-sf-audit-log-extended"
serviceplan_id = data.btp_subaccount_service_plan.audit_log_default.id
parameters = jsonencode({
retentionPeriod = var.profile_level >= 3 ? 1095 : 730
})
depends_on = [btp_subaccount_entitlement.audit_log]
}
# L3: Enable the Alert Notification service for real-time security alerts
resource "btp_subaccount_entitlement" "alert_notification" {
count = var.profile_level >= 3 ? 1 : 0
subaccount_id = var.btp_subaccount_id
service_name = "alert-notification"
plan_name = "standard"
}
resource "btp_subaccount_service_instance" "alert_notification" {
count = var.profile_level >= 3 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "hth-sf-alert-notification"
serviceplan_id = data.btp_subaccount_service_plan.alert_standard[0].id
parameters = jsonencode({
configuration = {
actions = [
{
name = "bulk-data-access-alert"
type = "EMAIL"
properties = {
destination = "security-team@company.com"
}
}
]
conditions = [
{
name = "bulk-employee-data-access"
description = "HTH: Detect bulk employee data access via API"
propertyKey = "eventType"
predicate = "EQUALS"
propertyValue = "data-access"
}
]
}
})
depends_on = [btp_subaccount_entitlement.alert_notification]
}
data "btp_subaccount_service_plan" "alert_standard" {
count = var.profile_level >= 3 ? 1 : 0
subaccount_id = var.btp_subaccount_id
name = "standard"
offering_name = "alert-notification"
}
Appendix B: References
Official SAP SuccessFactors Documentation:
- SAP SuccessFactors Platform Documentation
- SAP SuccessFactors Security Recommendations
- SAP Trust Center
API & Developer Resources:
Compliance & Certifications:
- SOC 1 Type II, SOC 2 Type II, ISO 27001, ISO 22301, BS 10012 – via SAP Trust Center Compliance Finder
Security Incidents:
- No major public security breaches specific to SAP SuccessFactors have been identified. SAP was designated a Critical ICT Third-Party Service Provider (CTPP) by European Supervisory Authorities in November 2025, reflecting its systemic importance to financial sector digital infrastructure.
Changelog
| Date | Version | Maturity | Changes | Author |
|---|---|---|---|---|
| 2025-12-14 | 0.1.0 | draft | Initial SAP SuccessFactors hardening guide | Claude Code (Opus 4.5) |