This is a cross-system integration playbook covering the full employee onboarding lifecycle from hire event in the HRIS through IT provisioning, ERP access assignment, equipment ordering, and ITSM ticket creation. The identity provider (Okta or Microsoft Entra ID) serves as the orchestration hub -- it receives hire events from the HRIS and pushes provisioning actions downstream via SCIM, Microsoft Graph, or application-specific APIs.
| System | Role | API Surface | Direction |
|---|---|---|---|
| Workday HCM / SuccessFactors | HRIS -- source of truth for employee master data | REST (RaaS) / OData v2 | Outbound (hire event trigger) |
| Okta / Microsoft Entra ID | Identity Provider -- orchestration hub | SCIM 2.0, REST | Inbound (from HRIS), Outbound (to apps) |
| Active Directory / Entra ID | Directory service -- group/OU assignment | LDAP / Microsoft Graph | Inbound (from IdP) |
| SAP S/4HANA / D365 / Salesforce | ERP/CRM -- role and permission assignment | OData / REST / SOAP | Inbound (from IdP or iPaaS) |
| ServiceNow | ITSM -- ticket creation for manual tasks | REST Table API | Inbound (from IdP or iPaaS) |
| Okta Workflows / Workato / MuleSoft | iPaaS -- complex orchestration | REST | Orchestrator |
| API Surface | Protocol | Best For | Auth Method | Real-time? | SCIM Support? |
|---|---|---|---|---|---|
| Workday RaaS | HTTPS/JSON or XML | Extracting hire/worker data | OAuth 2.0 (JWT) | Near real-time (polling) | No (use Workday Studio) |
| SuccessFactors OData | HTTPS/JSON | Employee Central CRUD | OAuth 2.0 SAML Bearer | Near real-time (polling) | Via Entra connector |
| Okta SCIM 2.0 | HTTPS/JSON | User provisioning to downstream apps | Bearer token | Yes | Native |
| Microsoft Graph | HTTPS/JSON | Entra ID user/group management | OAuth 2.0 | Yes | Via provisioning service |
| ServiceNow Table API | HTTPS/JSON | Incident/request/catalog item creation | OAuth 2.0 or Basic | Yes | Limited |
| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Max SCIM users per page | 100-200 | Okta SCIM push | Configurable, default 100 |
| Max Graph API batch | 20 requests | Microsoft Graph | JSON batch endpoint |
| ServiceNow Table API | 250 records/request | Table API insert | Use batch API for larger payloads |
| Workday RaaS report | 100,000 rows | Report output | Paginate for larger datasets |
| Limit Type | Value | Window | Notes |
|---|---|---|---|
| Okta API rate limit | 600 requests/min | Per-minute | Org-wide; provisioning counts against this |
| Microsoft Graph | 10,000 requests/10min | Per-app | Provisioning service has its own allocation |
| SuccessFactors OData | 200 concurrent / fair use | Per-tenant | No hard daily cap, but throttling applies |
| ServiceNow REST | 10 concurrent | Per-user | Increase via sys_properties |
| Flow | Use When | Systems | Token Lifetime | Notes |
|---|---|---|---|---|
| OAuth 2.0 JWT Bearer | Workday-to-Okta server integration | Workday | 60 min | Register ISU in Workday; JWT signed with X.509 cert |
| OAuth 2.0 SAML Bearer | SuccessFactors-to-Entra ID | SuccessFactors | 60 min | Requires SAML assertion from SF |
| SCIM Bearer Token | IdP-to-downstream app provisioning | All SCIM apps | Long-lived | Rotate every 90 days; store in IdP vault |
| OAuth 2.0 Client Credentials | ServiceNow API integration | ServiceNow | 30 min | Register OAuth app in ServiceNow |
START -- Automate employee onboarding from HRIS to ERP
|
+-- Which HRIS is your source of truth?
| +-- Workday
| | +-- IdP is Okta? --> Use native Workday-Okta connector (HR-as-master)
| | +-- IdP is Entra ID? --> Use Entra provisioning service with Workday connector
| | +-- IdP is other? --> Use iPaaS (Workato/MuleSoft) with Workday RaaS
| +-- SAP SuccessFactors
| | +-- IdP is Entra ID? --> Use Entra SF Employee Central connector
| | +-- IdP is Okta? --> Use Okta SFEC provisioning integration
| | +-- IdP is other? --> Use iPaaS with SF OData API
| +-- BambooHR / UKG / Other
| +-- Check if native IdP connector exists
| +-- If not --> iPaaS or webhook-to-SCIM adapter
|
+-- What needs provisioning?
| +-- Identity (AD/directory) --> SCIM or Graph API from IdP
| +-- SaaS apps (Slack, Zoom, Google) --> SCIM from IdP
| +-- ERP roles (SAP, Oracle, D365) --> IdP group-to-role mapping + SoD approval
| +-- Equipment (laptop, phone) --> ServiceNow catalog item request via API
| +-- Physical access (badge) --> ServiceNow or custom facilities API
|
+-- Pre-start provisioning needed?
+-- YES --> Configure pre-hire interval (7-14 days before start)
+-- NO --> Standard day-of provisioning on start date
| Step | Source System | Action | Target System | Data Objects | Failure Handling |
|---|---|---|---|---|---|
| 1 | HRIS (Workday/SF) | Hire event created | IdP (Okta/Entra) | Worker profile, dept, job code, manager, start date | Retry 3x with backoff; alert HR ops |
| 2 | IdP | Create user identity | Active Directory / Entra ID | sAMAccountName, UPN, email, OU, groups | Retry 3x; fallback to manual ticket |
| 3 | IdP | Assign AD groups by dept + role | Active Directory | Group membership | Log and alert; non-blocking |
| 4 | IdP | SCIM push to SaaS apps | Slack, Zoom, Google, etc. | User profile, license tier | Per-app retry; deactivate on partial fail |
| 5 | IdP / iPaaS | Assign ERP roles by job code | SAP / D365 / Salesforce | Security role, permission set | SoD approval queue; no auto-assign privileged |
| 6 | iPaaS / IdP | Create equipment request | ServiceNow | Catalog item (laptop, peripherals) | Create incident if catalog fails |
| 7 | iPaaS / IdP | Create badge/workspace request | ServiceNow / Facilities | Location, floor, desk | Non-blocking; manual ticket fallback |
| 8 | iPaaS / IdP | Send welcome email | Email / Slack | Login URLs, IT contact, first-day info | Retry; queue for manual send |
Set up the HRIS-to-IdP integration connector. All downstream provisioning depends on this link. [src1, src7]
For Workday + Okta: Enable HR-as-master mode, configure ISU in Workday with Get_Workers API access, set Pre-Hire Interval, map worker attributes to Okta profile.
For SuccessFactors + Entra ID: Use Entra Enterprise Applications > SuccessFactors provisioning connector, configure OData credentials, set scoping filter.
Verify: Test hire in HRIS sandbox appears in IdP within sync interval (5-40 minutes).
The IdP creates AD accounts with proper OU placement and group membership based on department and job code. [src2]
Define OU mapping rules (department + location -> target OU), group assignment rules (jobCode -> AD security groups), and UPN/email generation with collision handling.
Verify: Get-ADUser -Identity "newuser" -Properties memberOf shows correct groups.
For each downstream app, configure SCIM push from the IdP. Set provisioning priority: identity-critical apps first (email, Slack), then productivity tools, then specialized apps. [src1, src3]
Verify: Test user in IdP appears in each downstream app within 5-15 minutes.
ERP roles require job-code-to-role mapping with segregation of duties review for privileged access. Maintain mapping table in IdP or iPaaS, not in code. [src5]
Verify: New hire can log into ERP with correct role within 24h of start date.
Trigger ServiceNow catalog item requests automatically on hire event. Trigger at pre-hire stage (7-14 days before start) to account for procurement SLA. [src4]
// ServiceNow REST API -- create catalog item request for new hire equipment
const response = await fetch(
`https://${instance}.service-now.com/api/sn_sc/servicecatalog/items/${catalogItemSysId}/order_now`,
{
method: 'POST',
headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' },
body: JSON.stringify({
sysparm_quantity: 1,
variables: {
employee_name: employee.displayName,
department: employee.department,
laptop_model: getLaptopModel(employee.jobCode)
}
})
}
);
Verify: Check ServiceNow for RITM creation with correct catalog item and requester.
Send welcome email after all provisioning completes. Include SSO enrollment link (never plain-text passwords), VPN instructions, Slack channels, and IT support contact.
Verify: Confirm delivery in email logs; verify all linked URLs resolve.
| Source Field (HRIS) | Target Field (IdP) | Target Field (AD) | Transform | Gotcha |
|---|---|---|---|---|
| workerID / personIdExternal | employeeNumber | employeeID | Direct | Workday uses WID internally; export uses Employee_ID |
| legalName.firstName | firstName | givenName | Direct | SF may return preferred name, not legal name |
| legalName.lastName | lastName | sn | Direct | Handle apostrophes/hyphens in sAMAccountName |
| email (work) | Direct or generate | HRIS may not have work email for pre-hires | ||
| supervisorID | managerId | manager (DN) | Lookup (ID to DN) | Manager must exist in AD before new hire |
| departmentName | department | department | Mapping table | HRIS names rarely match ERP department codes |
| jobTitle | title | title | Mapping table | Free-text in HRIS; must map to structured ERP codes |
| locationCode | office | physicalDeliveryOfficeName | Mapping table | Location codes differ across every system |
| startDate | startDate | accountExpires (inverse) | Date format conversion | Workday: ISO 8601; SAP: YYYYMMDD; AD: FILETIME |
| Code | Meaning | System | Resolution |
|---|---|---|---|
| 409 Conflict | User already exists | SCIM endpoint | Check for deactivated user; reactivate instead of create |
| 400 uniqueness | Username collision | AD / SCIM | Implement collision counter: jsmith -> jsmith2 |
| 403 Forbidden | Insufficient permissions | Workday API | Add ISU to required domain security policies |
| 404 Not Found | Referenced object missing | SCIM / ERP | Implement dependency ordering; retry with backoff |
| 429 Too Many Requests | Rate limit exceeded | Okta / Entra | Exponential backoff; batch provisioning during off-peak |
| SCIM 500 | Internal server error | Downstream app | Retry 3x; route to dead letter queue |
Two-pass sync -- first pass creates users, second pass sets manager references. [src7]Implement rehire detection: match on email/employee ID, reactivate existing account. [src1]24h reminder, 48h escalation, 72h auto-approve non-critical with audit flag. [src4]Trigger equipment request 7-14 days before start; maintain loaner laptop pool. [src4]Set PagerDuty reminder 30 days before each SCIM token expiration. [src3]Retry with 30-minute delay after initial 404. [src5]# BAD -- HR emails IT with a spreadsheet of new hires
# IT manually creates accounts in each system
# Average time: 5-8 hours per employee
# Error rate: 15-25%
# GOOD -- Hire event in HRIS triggers automated pipeline
# IdP receives event, provisions all downstream systems
# Average time: 5-15 minutes (automated) + approval wait
# Error rate: <2%
# BAD -- race condition: ERP role assignment before AD account exists
async def provision_all(employee):
await asyncio.gather(
create_ad_account(employee), # Takes 30s
create_erp_role(employee), # Fails: AD not ready
create_slack_account(employee), # Fails: email not active
)
# GOOD -- respect dependency ordering
async def provision_staged(employee):
# Stage 1: Identity foundation
ad_account = await create_ad_account(employee)
await wait_for_ad_replication(ad_account, timeout=120)
# Stage 2: Depends on AD (parallel)
await asyncio.gather(
create_email_account(employee),
assign_ad_groups(employee),
)
# Stage 3: Depends on groups + approval
await request_erp_role_with_approval(employee)
# Stage 4: Independent
await order_equipment(employee)
// BAD -- mapping changes require code deployment
function getERPRole(jobCode) {
if (jobCode === 'FIN-AP') return 'SAP_FI_AP_CLERK';
if (jobCode === 'SALES-REP') return 'SF_STANDARD_USER';
// 200 more if/else statements...
}
// GOOD -- mapping table in database, maintained by HR/IT ops
async function getERPRole(jobCode) {
const mapping = await db.query(
'SELECT erp_system, erp_role, approval_required ' +
'FROM job_role_mappings WHERE job_code = ? AND active = true',
[jobCode]
);
if (!mapping.length) {
await createManualReviewTicket(jobCode);
return null;
}
return mapping;
}
Build complete sandbox chain; run 10+ test hires including edge cases (rehires, transfers, same-name employees). [src1]Design onboarding and offboarding as a single lifecycle. Every provisioning action must have a corresponding deprovisioning action. [src6]Event-driven or 5-15 min polling for hire/termination events. Batch is fine for attribute updates. [src7]Dashboard showing per-app success/failure rates; alert on >5% failure rate; weekly reconciliation report. [src1]Least-privilege role mapping by job code. Access reviews at 30/60/90 days. [src6]Separate provisioning templates with account expiration tied to contract end date. [src2]# Check Okta provisioning status for a user
curl -s -H "Authorization: SSWS ${OKTA_API_TOKEN}" \
"https://${OKTA_DOMAIN}/api/v1/apps/${APP_ID}/users?filter=profile.email+eq+%[email protected]%22" | jq .
# Check Entra ID provisioning logs
az ad audit-log provisioning list \
--filter "targetIdentity/displayName eq 'New User'" --top 10
# Check ServiceNow RITM status for equipment order
curl -s -H "Authorization: Bearer ${SN_TOKEN}" \
"https://${SN_INSTANCE}.service-now.com/api/now/table/sc_req_item?sysparm_query=request.requested_for.email=newuser@example.com" | jq '.result[] | {number, state}'
# Reconciliation -- compare headcount across systems
echo "HRIS active: $(curl -s ${HRIS_API}/workers?active=true | jq '.total')"
| Component | Version | Status | Notable Changes |
|---|---|---|---|
| SCIM 2.0 (RFC 7643/7644) | 2.0 | Current standard | Stable since 2015; enterprise extension widely adopted |
| Okta Identity Engine | OIE 2024+ | Current | Replaced Classic Engine; lifecycle hooks API changed |
| Microsoft Entra provisioning | 2024+ | Current | Formerly Azure AD; API endpoints unchanged |
| Workday RaaS | 2024R2+ | Current | Added real-time SCIM connector (limited GA) |
| SuccessFactors EC | 2H 2024+ | Current | Improved OData v4 support |
| ServiceNow EOT | Vancouver+ | Current | Enhanced lifecycle event APIs |
| Use When | Don't Use When | Use Instead |
|---|---|---|
| 200+ employees, 10+ hires/month | <50 employees, <5 hires/month | Manual checklist with IT ticket |
| Cloud HRIS + cloud IdP | On-prem HRIS with no API | MIM/FIM for on-prem identity sync |
| Multiple SaaS + ERP systems | Single ERP with built-in onboarding | ERP native onboarding module |
| SOX/SOC 2/GDPR audit trail required | No compliance requirements | Simpler scripted approach |
| Multinational with regional differences | Single office, single region | Simplified single-policy provisioning |
| Capability | Okta + Workday | Entra ID + SuccessFactors | Google + BambooHR | Notes |
|---|---|---|---|---|
| HRIS-to-IdP connector | Native (HR-as-master) | Native (Entra provisioning) | Via iPaaS | Okta and Entra deepest |
| SCIM app catalog | 7,000+ apps | 5,000+ apps | Limited native | Okta largest catalog |
| Pre-hire provisioning | Yes (Pre-Hire Interval) | Yes (future-dated sync) | iPaaS-dependent | Critical for day-1 readiness |
| ERP role provisioning | Via Okta groups/Workflows | Via Entra groups/Access Packages | Manual or iPaaS | Entra best for complex governance |
| Equipment ordering | Okta Workflows + ServiceNow | Logic Apps + ServiceNow | iPaaS + ServiceNow | All need ITSM platform |
| Offboarding automation | Native (deactivate propagates) | Native (disable propagates) | iPaaS-dependent | Okta and Entra equally strong |
| Access reviews / governance | Okta Identity Governance (add-on) | Entra Access Reviews (P2) | Third-party needed | Entra P2 most cost-effective for M365 shops |
| Cost | $$$ (Okta WIC pricing) | $$ (M365 E5 or P1/P2 add-on) | $ (free tier) | Google cheapest but least capable |