Back to User Provisioning & Access Management

Developer Handover Pack

Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.

4 pagesPDF · Technical
FS-DOC-04Technical

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

Step
Name
Description
1
Receive Hire or Departure Notification
HR emails or messages IT with the employee's start or end date, role, and department. This often arrives with incomplete details and no standard format. Time cost: 10 min
2
Clarify Role and Required Access
IT follows up with the hiring manager to confirm which systems, groups, and permission levels the employee needs. Back-and-forth often takes a full business day. Time cost: 30 min
3
Create Identity Provider Account
IT creates the user account in Okta, setting the correct display name, username, and department attributes. Time cost: 15 min
4
Provision Google Workspace Account
IT creates the Google Workspace account, assigns the user to the correct organisational unit, and adds them to relevant shared drives and group inboxes. Time cost: 20 min
5
Assign Microsoft 365 Licence and Groups
IT assigns a Microsoft 365 licence, configures Teams membership, and adds the user to the correct SharePoint sites. Time cost: 15 min
6
Add User to Slack Workspace and Channels
IT invites the employee to Slack and manually adds them to each relevant channel based on their role. Channel lists are rarely documented. Time cost: 10 min
7
Raise Jira Ticket for Additional App Access
For systems not covered by single sign-on, IT opens a Jira ticket and routes it to the relevant app owner for manual account creation. Time cost: 15 min
8
Send Welcome and Credentials Email
IT drafts and sends a welcome email with login instructions, temporary password, and links to setup guides. This is done per hire with no template. Time cost: 15 min
9
Update HRIS Record with Account Status
IT or HR manually updates the BambooHR employee record to confirm accounts have been provisioned and the start date is covered. Time cost: 10 min
10
Deactivate All Accounts on Departure
On an employee's last day IT must deactivate Okta, Google Workspace, Microsoft 365, and Slack accounts in sequence. Any missed system is a live security risk. Time cost: 25 min
11
Transfer Files and Reassign Ownership
IT transfers Google Drive and email ownership to the departing employee's manager and archives the mailbox according to the data retention policy. Time cost: 20 min
12
Log Access Changes for Audit
IT manually records what was provisioned or deprovisioned in a shared spreadsheet or Jira comment for compliance purposes. Time cost: 10 min
Time cost summary: Total manual time per provisioning event is 195 minutes (3 hours 15 min) for a full hire cycle, or approximately 55 minutes for an offboarding-only event (steps 9 to 12). At 6 to 10 events per month the process consumes roughly 5 hours per week of IT and HR staff time. The automation replaces steps 1 through 6 (Provisioning Policy Agent) and steps 9 through 12 (Offboarding Audit Agent), leaving only the elevated-permissions review gate (between steps 3 and 4 in the automated flow) as a required human touch.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Provisioning Policy Agent

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.

Trigger
BambooHR webhook fires on employee record status change to New Hire, Transfer, or Terminated.
Tools
BambooHR, Okta, Google Workspace, Microsoft 365, Slack
Replaces steps
Steps 1, 2, 3, 4, 5, and 6 of the current manual process
Estimated build
22 hours / 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.
Offboarding Audit Agent

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.

Trigger
Provisioning Policy Agent outputs a deprovision manifest with event_type: 'deprovision' and manifest_status: 'complete'.
Tools
Okta, Google Workspace, Microsoft 365, Slack, Jira
Replaces steps
Steps 9, 10, 11, and 12 of the current manual process
Estimated build
14 hours / 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.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full trigger-to-output data flow with field names at each agent handoff
// ─────────────────────────────────────────────────────────────
// 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
// ─────────────────────────────────────────────────────────────
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation platform with native HTTP request nodes and credential management. One workflow per agent: 'Provisioning Policy Agent Workflow' and 'Offboarding Audit Agent Workflow'. A shared credential store holds all API keys, OAuth tokens, and service account credentials referenced by both workflows. No credentials are hard-coded in workflow nodes.
Webhook configuration
BambooHR webhook points to the automation platform's inbound webhook URL for the Provisioning Policy Agent Workflow. The endpoint must accept POST requests with a shared secret header (X-BambooHR-Signature) for payload verification. A second internal webhook (platform-to-platform) passes the completed provisioning manifest from the Provisioning Policy Agent Workflow to the Offboarding Audit Agent Workflow when event_type is 'deprovision'. All webhook URLs are environment-specific (sandbox and production endpoints are separate).
Templating approach
The role-to-access policy is stored as a structured JSON config file (or a Supabase table with a 'role_policy' schema) and loaded at runtime by the Provisioning Policy Agent. The Jira audit ticket description uses a Markdown template rendered at runtime with values from the audit_record object. The Slack alert and manager notification messages use a plain-text template with interpolated fields (employee full name, Jira issue key, last day). All templates are versioned in the project repository and must not be modified directly inside the orchestration layer.
Error logging
All step-level errors and timeout events write a row to a Supabase table ('automation_error_log') with columns: error_id (uuid), workflow_name (string), step_name (string), employee_id (string), error_message (string), occurred_at (timestamp). A Supabase database webhook on INSERT to this table triggers a Slack alert to the IT Administrator channel (channel ID confirmed before deployment). Critical errors (any Okta or Google deactivation failure on a termination event) also send an email alert to support@gofullspec.com for FullSpec monitoring.
Testing approach
All integration testing is completed in sandbox environments before any production credentials are connected. BambooHR sandbox employee records are used to fire test webhooks. Okta Developer org is used for identity API testing. Google Workspace test domain and Microsoft 365 developer tenant are used for provisioning action tests. Slack test workspace is used for channel and membership tests. Jira sandbox project ('ITDEV') receives all audit tickets during QA. Promotion to production credentials happens only after the FullSpec QA sign-off on all test cases in the Test and QA Plan.
Estimated total build time
Provisioning Policy Agent: 22 hours. Offboarding Audit Agent: 14 hours. End-to-end integration testing and QA: included in the 36-hour total build scope. Total: 36 hours across a 3 to 4 week delivery window, consistent with the Standard build timeline.
Build blockers to resolve before FullSpec starts the agent builds: (1) The role-to-access policy table must be finalised and handed over by the IT Administrator. (2) Okta SCIM provisioning to Google Workspace and Microsoft 365 must be active and verified. (3) All API credentials and OAuth apps must be provisioned (BambooHR API key, Okta service app client ID and secret, Google service account with domain-wide delegation, Microsoft 365 app registration with required Graph API permissions, Slack bot token with correct scopes, Jira API token). (4) The Jira project key and issue type for audit records must be confirmed. (5) Legal or compliance sign-off on email and Drive archiving rules must be received before the Offboarding Audit Agent is deployed to production.
Credential
Type
Scope / Permission required
Status
BambooHR API key
API key header
Read employee records; configure webhooks
To confirm
Okta service app
OAuth 2.0 client credentials
okta.users.manage, okta.groups.manage
To confirm
Google service account
JWT / domain-wide delegation
admin.directory.user, admin.directory.group, drive.transfer
To confirm
Microsoft Graph app registration
OAuth 2.0 (client credentials)
User.ReadWrite.All, Group.ReadWrite.All, Directory.ReadWrite.All
To confirm
Slack bot token
OAuth 2.0 bot token
channels:write, users:read, admin.users:write (SCIM)
To confirm
Jira API token
Basic auth (email + token)
Project write access on IT audit project
To confirm
Supabase service role key
API key
Insert/read on automation_error_log table
To provision
For any build questions, credential setup issues, or pre-build queries, contact the FullSpec team at support@gofullspec.com. All credential values are stored exclusively in the shared credential store of the orchestration platform and are never written into workflow node configuration or source code.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for User Provisioning & Access Management.

Launch Plan
Operations · Owner
View
ROI and Business Case
Finance · Owner
View
Process Runbook / SOP
Operations · Owner
View
Integration and API Spec
Technical · Developer
View
Test and QA Plan
Quality · Developer
View