Developer Handover Pack
Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.
Developer Handover Pack
User Provisioning and Access Management
[YourCompany.com] · IT Department · Prepared by FullSpec · [Today's Date]
This document is the primary technical reference for the FullSpec build team working on the User Provisioning and Access Management automation. It covers the full current-state process map, both agent specifications with IO contracts, the end-to-end data flow, and the recommended build stack. The FullSpec team uses this pack to build, test, and deliver the automation. Your team (IT Administrator and HR Manager) provides access credentials, confirms the role-to-access policy before build begins, and handles the elevated-permissions approval step during live operation.
01Process snapshot
02Agent specifications
Reads the employee record from BambooHR the moment a status change fires (New Hire, Transfer, or Terminated). Resolves the correct access profile by matching the employee's role and department against the stored access policy rules. Produces a structured provisioning manifest covering every connected system. If any role attribute maps to a non-standard or elevated permission tier, the manifest is paused and routed to the IT Administrator for approval before any account creation action is executed. On approval (or if no elevated permissions are flagged), the agent executes account creation or deactivation across Okta, Google Workspace, Microsoft 365, and Slack in sequence. Estimated build time: 22 hours. Complexity: Complex.
// Input
bamboohr.employee.id // string, unique employee identifier
bamboohr.employee.status // enum: 'New Hire' | 'Transfer' | 'Terminated'
bamboohr.employee.first_name // string
bamboohr.employee.last_name // string
bamboohr.employee.email // string, work email to be created or deactivated
bamboohr.employee.department // string, mapped against access policy table
bamboohr.employee.job_title // string, used for role-level permission lookup
bamboohr.employee.start_date // date, ISO 8601
bamboohr.employee.manager_id // string, used for elevated-permission approval routing
// Processing: access policy lookup
policy.role_mapping[department][job_title] -> access_profile {
okta_group_ids: string[]
google_ou: string
google_group_emails: string[]
m365_licence_sku: string
m365_teams_ids: string[]
slack_channel_ids: string[]
elevated_permission_flag: boolean
}
// On approval (elevated_permission_flag = true)
it_admin.approval_status // enum: 'approved' | 'rejected'
it_admin.approved_at // timestamp, ISO 8601
it_admin.approver_id // string, IT Administrator user ID
// Output
provisioning_manifest {
employee_id: string
event_type: 'provision' | 'deprovision'
okta_account_id: string
google_account_id: string
m365_account_id: string
slack_member_id: string
elevated_flag: boolean
approval_required: boolean
manifest_status: 'complete' | 'pending_approval' | 'rejected'
actioned_at: timestamp
}- BambooHR must have a webhook configured on the employee status field. The webhook payload must include employee ID, status, department, job title, start date, and manager ID. Confirm the BambooHR tier supports custom webhooks (BambooHR Core or above required).
- Okta must be the federated identity provider for both Google Workspace and Microsoft 365 before this agent can push group memberships reliably. Verify Okta-to-Google SAML/SCIM provisioning and Okta-to-M365 SCIM are active in the target environment before build begins.
- The role-to-access policy table must be finalised by the IT Administrator and stored in a structured format (database table or JSON config) accessible to the orchestration layer. The agent cannot infer permissions without a complete reference. This is a build blocker.
- Elevated-permission flag logic must be defined explicitly: the IT team must supply a list of job titles or department codes that trigger the review gate. Default behaviour is to halt the manifest and send an approval request to the IT Administrator via Slack before any Okta account is created.
- Deduplicate on employee_id before executing any provisioning action. If a webhook fires twice for the same employee_id and event_type within a five-minute window, discard the second event and log a deduplication notice.
- For Transfer events, the agent must compare the incoming access profile against the employee's current Okta group memberships and apply only the delta (add new, remove old) rather than reprovisioning from scratch.
- Microsoft 365 licence assignment requires the correct SKU identifier per licence tier. Confirm available SKU IDs from the M365 tenant admin before build. Do not hard-code SKUs; store them in the policy config.
- Slack channel membership is driven by the slack_channel_ids array in the access policy. Channel lists must be documented by the IT team before build. The agent adds channels via the Slack API conversations.invite endpoint using the bot token with channels:write and users:read scopes.
Triggered by the Provisioning Policy Agent when the provisioning manifest carries an event_type of 'deprovision' for a Terminated employee. Executes the full account deactivation sequence across Okta, Google Workspace, Microsoft 365, and Slack in a defined order. Transfers Google Drive and email ownership to the line manager before suspending the account. Removes the employee from all Slack channels and deactivates the workspace membership. Writes a timestamped audit record to Jira as a new issue, attaching the completed manifest as an artifact. Raises a Slack alert to the IT Administrator if any deactivation step does not return a success confirmation within two minutes of execution. Estimated build time: 14 hours. Complexity: Moderate.
// Input (from Provisioning Policy Agent manifest)
provisioning_manifest.employee_id // string
provisioning_manifest.okta_account_id // string
provisioning_manifest.google_account_id // string
provisioning_manifest.m365_account_id // string
provisioning_manifest.slack_member_id // string
provisioning_manifest.actioned_at // timestamp
bamboohr.employee.manager_id // string, Drive and email transfer target
bamboohr.employee.last_day // date, ISO 8601
// Processing: deactivation sequence (ordered)
step_1: okta.deactivate(okta_account_id) // suspends SSO and downstream sessions
step_2: google.transfer_drive(google_account_id, manager_google_id)
step_3: google.transfer_email(google_account_id, manager_google_id)
step_4: google.suspend(google_account_id)
step_5: m365.remove_licences(m365_account_id)
step_6: m365.remove_groups(m365_account_id)
step_7: slack.deactivate(slack_member_id)
// Timeout alert (per step)
if step.confirmation_received_at > step.executed_at + 120s:
slack.alert(it_admin_channel, { step: step_name, employee_id, timestamp })
// Output
audit_record {
jira_issue_key: string // e.g. 'IT-4821'
employee_id: string
last_day: date
okta_deactivated_at: timestamp
google_suspended_at: timestamp
drive_transferred_at: timestamp
m365_removed_at: timestamp
slack_deactivated_at: timestamp
any_step_failed: boolean
failed_steps: string[] // empty array if all succeeded
audit_completed_at: timestamp
}- Deactivation order is non-negotiable: Okta must be suspended first to kill all active SSO sessions before any downstream system is touched. Google Drive and email ownership transfer must complete before the Google account is suspended, otherwise transfer calls will fail.
- Google Drive ownership transfer uses the Admin SDK Drive API with the domain-wide delegation service account. Confirm the service account has the https://www.googleapis.com/auth/drive scope delegated in the Google Workspace admin console before build.
- Microsoft 365 licence removal and group removal are separate API calls (PATCH to remove assignedLicenses, then DELETE on each group membership). Both must succeed before the step is marked complete. Log partial failures separately.
- Slack deactivation uses the admin.users.setInactive SCIM endpoint, which requires a Slack Enterprise Grid plan or a SCIM-enabled Slack app token. Confirm the Slack tier supports SCIM before build; if not, fall back to the users.admin.setInactive method under an admin user token.
- The Jira audit issue must be created in a dedicated Jira project (confirm project key with IT Administrator before build). The issue type should be 'Access Audit' or equivalent. Attach the full provisioning manifest JSON as an issue attachment, not just inline text.
- Legal and compliance must confirm the email and Drive archiving retention period before the offboarding flow goes live. The current build assumes ownership transfer with no deletion; any auto-delete rule requires a separate configuration flag.
- The two-minute timeout alert is per individual step. If multiple steps fail, each fires its own Slack alert. The IT Administrator Slack channel ID must be confirmed and stored in the credential store before deployment.
03End-to-end data flow
// ─────────────────────────────────────────────────────────────
// TRIGGER: BambooHR employee status change webhook
// ─────────────────────────────────────────────────────────────
INBOUND webhook POST /automation/bamboohr/status-change
payload.employee_id = '00412'
payload.status = 'Terminated' // New Hire | Transfer | Terminated
payload.first_name = 'Alex'
payload.last_name = 'Drummond'
payload.email = 'alex.drummond@yourcompany.com'
payload.department = 'Engineering'
payload.job_title = 'Senior Engineer'
payload.start_date = '2025-05-09'
payload.last_day = '2025-05-16'
payload.manager_id = '00199'
// ─────────────────────────────────────────────────────────────
// DEDUP CHECK: discard if same employee_id + status within 5 min
// ─────────────────────────────────────────────────────────────
dedup_key = hash(employee_id + status + floor(timestamp / 300))
IF dedup_key EXISTS IN dedup_store: DISCARD, LOG dedup_notice, EXIT
ELSE: WRITE dedup_key to dedup_store, TTL 600s
// ─────────────────────────────────────────────────────────────
// AGENT HANDOFF 1: Provisioning Policy Agent begins
// ─────────────────────────────────────────────────────────────
provisioning_policy_agent.input {
employee_id -> '00412'
status -> 'Terminated'
department -> 'Engineering'
job_title -> 'Senior Engineer'
manager_id -> '00199'
}
// Policy lookup
access_profile = policy_table.lookup(department='Engineering', job_title='Senior Engineer')
-> okta_group_ids: ['grp_eng_core', 'grp_infra_readonly']
-> google_ou: '/Engineering'
-> google_group_emails: ['eng-team@yourcompany.com']
-> m365_licence_sku: 'ENTERPRISEPACK'
-> m365_teams_ids: ['team_engineering', 'team_allstaff']
-> slack_channel_ids: ['C01ENG', 'C01GENERAL', 'C01INFRA']
-> elevated_permission_flag: false
// Elevated permission gate
IF elevated_permission_flag = true:
slack.send(it_admin_channel, approval_request { employee_id, access_profile })
WAIT for it_admin.approval_status
IF approval_status = 'rejected': HALT, log rejection, EXIT
IF approval_status = 'approved': CONTINUE with confirmed access_profile
ELSE:
CONTINUE immediately
// event_type derived from status
event_type = 'deprovision' // status='Terminated' -> deprovision; else -> provision
// Okta: deactivate (deprovision path)
okta.POST /api/v1/users/00412/lifecycle/deactivate
-> response.status = 200
-> okta_account_id = 'okta_00412'
// Google Workspace: suspend (deprovision path)
google_admin.PATCH /admin/directory/v1/users/alex.drummond@yourcompany.com
body.suspended = true
-> google_account_id = 'ga_00412'
// Microsoft 365: remove licence and groups (deprovision path)
m365.POST /v1.0/users/00412/assignLicense body.removeLicenses=['ENTERPRISEPACK']
m365.DELETE /v1.0/groups/team_engineering/members/00412
m365.DELETE /v1.0/groups/team_allstaff/members/00412
-> m365_account_id = 'm365_00412'
// Slack: deactivate (deprovision path)
slack.SCIM PATCH /Users/slack_00412 body.active = false
-> slack_member_id = 'slack_00412'
// Provisioning Policy Agent output: manifest
provisioning_manifest {
employee_id: '00412'
event_type: 'deprovision'
okta_account_id: 'okta_00412'
google_account_id: 'ga_00412'
m365_account_id: 'm365_00412'
slack_member_id: 'slack_00412'
elevated_flag: false
approval_required: false
manifest_status: 'complete'
actioned_at: '2025-05-16T09:04:11Z'
}
// ─────────────────────────────────────────────────────────────
// AGENT HANDOFF 2: Offboarding Audit Agent begins
// ─────────────────────────────────────────────────────────────
offboarding_audit_agent.input {
provisioning_manifest -> (full object above)
bamboohr.employee.manager_id -> '00199'
bamboohr.employee.last_day -> '2025-05-16'
}
// Drive and email transfer (before suspension confirmation)
google_admin.POST /admin/directory/v1/users/ga_00412/driveTransfers
body.destinationOrgUnitPath = '/Engineering'
body.transferToUserId = 'ga_00199' // manager's Google account
-> drive_transferred_at = '2025-05-16T09:04:18Z'
google_admin.PATCH /admin/directory/v1/users/ga_00412
body.emailForwardingAddress = 'jordan.reeves@yourcompany.com' // manager
-> email_transfer_confirmed = true
// Per-step timeout check
FOR each step IN [okta, google_drive, google_email, m365, slack]:
IF step.confirmation_received_at > step.executed_at + 120s:
slack.POST it_admin_channel { alert: 'step_timeout', step: step.name, employee_id: '00412' }
// Jira audit ticket creation
jira.POST /rest/api/3/issue
body.project.key = 'IT'
body.issuetype.name = 'Access Audit'
body.summary = 'Offboarding audit: Alex Drummond (00412) 2025-05-16'
body.description = audit_record (structured JSON embedded)
body.attachment = provisioning_manifest.json
-> jira_issue_key = 'IT-4821'
// Manager notification
slack.POST manager_dm { message: 'Alex Drummond offboarding complete. Audit: IT-4821.' }
// Offboarding Audit Agent output
audit_record {
jira_issue_key: 'IT-4821'
employee_id: '00412'
last_day: '2025-05-16'
okta_deactivated_at: '2025-05-16T09:04:12Z'
google_suspended_at: '2025-05-16T09:04:14Z'
drive_transferred_at: '2025-05-16T09:04:18Z'
m365_removed_at: '2025-05-16T09:04:22Z'
slack_deactivated_at: '2025-05-16T09:04:26Z'
any_step_failed: false
failed_steps: []
audit_completed_at: '2025-05-16T09:04:31Z'
}
// ─────────────────────────────────────────────────────────────
// END: full deprovision cycle complete in < 10 minutes
// ─────────────────────────────────────────────────────────────04Recommended build stack
More documents for this process
Every document generated for User Provisioning & Access Management.