A former developer finished a three-month engagement eight months ago. Their GitHub access - including private repos, internal tooling, and staging environments - is still live. Nobody noticed. The IT team disabled the Okta account, so it looked handled. But that developer was never in Okta to begin with. They used a personal Gmail, provisioned directly by the lead engineer on day one.

This is what an "orphaned contractor account" actually looks like in the wild. Not a theoretical risk. Not an edge case. A completely predictable outcome of a process designed for employees - one that quietly fails every time it meets a contractor.

Contingent workers now make up roughly 30-40% of the U.S. workforce, according to the U.S. Government Accountability Office, and that number keeps climbing1that number is forecast to keep climbing. Yet most identity governance programs still assume the workforce is made entirely of employees with HRIS records. It isn't. The gap between how your tools model your workforce and how it actually looks is where orphaned accounts, overprovisioned access, and audit findings live.

This guide is a practical walkthrough - not a "why this matters" post (we covered that in our piece on why standard JML automation breaks for contractors). Here's the step-by-step process for fixing it: alternative identity sources, automated provisioning, time-bound access, and clean offboarding - even when no HR event ever fires.

The Core Problem: Your JML Process Was Designed for Employees

Most organizations run joiner-mover-leaver (JML) automation built on a single assumption: the HRIS is the source of truth. Employee gets hired -> HR creates a record -> a workflow fires -> access gets provisioned. Employee leaves -> HR closes the record -> SSO is disabled -> SCIM-connected apps get deprovisioned.

This works - when the person is in the HRIS.

Contractors usually aren't. They're tracked in procurement portals, staffing agency systems, manager emails, or spreadsheets. When a contractor's engagement ends, no HR record closes. No JML event fires. No automation runs. The contractor's Slack workspace, GitHub membership, Notion access, and Jira instance stay exactly as they were on day one.

warning Warning

The HRIS trap: Standard JML automation fires when an HR record changes. Contractors usually have no HR record - so no event ever fires, and no account ever gets deprovisioned automatically. This isn't a process failure. It's an architectural gap in how most IGA tools were designed.

This isn't an IT team failure. It's an architectural gap. The tooling was never designed to handle identities that exist outside the HRIS. Until you change the architecture - not just the process - you'll keep producing orphaned accounts on a schedule.

Before You Start: Assess Your Current Exposure

Before fixing the process going forward, know how exposed you are right now.

The 7-Step Process for Clean Contractor Lifecycle Management

1
Step 1 - Define Your Contractor Identity Sources

Stop treating the HRIS as your only source of truth. Map every system where contractor identities actually live: procurement/vendor portals, project management tools (Jira, Linear), manager-initiated requests, contract management platforms (DocuSign, Ironclad), staffing agency rosters, and manual IT intake tickets. Each of these is a valid identity source - you just need to wire them in.

2
Step 2 - Capture the Access Lifecycle Metadata Upfront

At the moment a contractor is onboarded, collect: contract start date, contract end date (mandatory), project scope (which tools, which repos, which channels), access approver (the sponsoring manager), and access level (least-privilege, not 'give them what the dev team has'). This metadata is what drives automated provisioning and clean offboarding later. Without it, you're already setting up an orphan account.

3
Step 3 - Provision Access Through Policy-Driven Workflows

Route the access request through an automated workflow, not a ticket queue. The workflow should: check the contractor's role profile against a predefined entitlement catalog, provision only the specific apps and scopes needed (channel-level in Slack, repo-level in GitHub, page-level in Notion - not broad group assignments), and log every provisioning action with a timestamp and approver for audit trail purposes.

4
Step 4 - Enforce Time-Bound Access From Day One

Every contractor account gets an automatic expiry date tied to the contract end date captured in Step 2. This is not optional and not a reminder email - it's a hard expiry enforced at the access layer. When the date arrives, access is revoked automatically across every connected app, whether it supports SCIM, has an API, or neither. No manual action required. No Slack reminder to 'please remember to deprovision.'

5
Step 5 - Run Continuous Access Reviews During the Engagement

A contractor's role changes mid-project more often than you think. Enforce quarterly (or event-triggered) access reviews for all active contractor identities. Reviews should surface: unused entitlements (apps the contractor hasn't logged into in 30+ days), scope creep (access that widened beyond the original approval), and accounts that no longer map to an active contract or manager. Right-size permissions continuously - don't wait for offboarding to discover the sprawl.

6
Step 6 - Trigger Offboarding Without an HR Event

You cannot wait for HR to fire a termination event that was never going to fire. Set up three parallel offboarding triggers: (1) Date-based: the contract end date from Step 2 fires an automatic full deprovision. (2) Manager-initiated: the sponsoring manager has a one-click offboarding action that removes all contractor access immediately. (3) Inactivity-based: if a contractor account shows zero activity for a configurable period (e.g., 30 days), it's automatically flagged for suspension and review. Any one of these three triggers should be sufficient to close all access - including apps outside SSO, apps without SCIM, and any direct credentials that were provisioned outside the main identity provider.

7
Step 7 - Verify, Document, and Close the Loop

After offboarding fires, automatically generate a deprovisioning report: which accounts were closed, at what timestamp, across which apps. This report becomes your audit evidence. It answers the auditor's question - 'Can you confirm this former contractor no longer has access?' - in seconds, not weeks of manual log hunting. Store it alongside the original access approval as a complete identity lifecycle record.

The Offboarding Trigger Problem: Why "We Have a Process" Isn't Enough

Most teams, when asked about contractor offboarding, say some version of: "The manager emails IT when the contract ends." That's a process. It's not governance.

The difference matters. A process depends on someone remembering, acting, and following through - across every contractor, every project, every team, every time zone. Governance is automated, policy-driven, and doesn't depend on anyone's memory.

Here's how the most common offboarding triggers compare - and where each one breaks down:

Offboarding TriggerHow It WorksWhat It MissesRisk Level
HR termination eventHR closes record -> SSO disabled -> SCIM apps deprovisionedContractors with no HR record, direct logins, non-SCIM apps🔴 High for contractors
Manual IT ticketManager emails IT -> IT manually removes access app by appApps IT doesn't know about, after-hours departures, forgotten tickets🔴 High
SSO disable onlyOkta/Entra account disabled -> SSO-gated apps blockedDirect logins, apps outside SSO perimeter, non-SCIM integrations🟠 Medium (partial)
Date-based auto-expiry (contract end date)Contract end date fires automatic deprovision across all connected appsOnly covers apps connected to the governance platform🟢 Low (with universal connectors)
Manager-initiated one-click offboardingManager triggers immediate full access removal from a single interfaceRequires manager action - must be part of process design🟢 Low (with right tooling)
Inactivity-based suspensionNo login for 30+ days -> account auto-suspended and flagged for reviewDoesn't catch access that's still in use by an unauthorized party🟢 Low (as a safety net)

The only approach that reliably closes access without a human action is date-based auto-expiry - with universal app coverage as the enforcement mechanism. Without universal connectors that reach every app in your stack (SCIM, API, or neither), time-bound access is just a policy on paper.

What "Alternative Identity Sources" Actually Means in Practice

If contractors don't live in your HRIS, you need to wire in the systems where they do live. Here's what that looks like across common contractor intake paths:

Procurement and Vendor Portals

Contractors hired through procurement flows (SAP Ariba, Coupa, ServiceNow vendor records) have a contract record with a start date and end date. Wire this system into your IGA platform as an identity source. A new vendor record triggers provisioning. A closed purchase order triggers offboarding.

Manager Attestation and IT Intake Forms

For contractors onboarded via manager request (a Jira ticket, a form, a Slack message), the intake form becomes the identity source - but only if you capture the right data upfront. A form that collects name, email, and "what they need access to" isn't enough. You need contract end date, sponsoring manager, and access scope. Anything less and you've onboarded someone you can't cleanly offboard.

Project Start/End Dates as Lifecycle Signals

For project-based contractors (common in tech, logistics, and consulting), the project itself is the lifecycle signal. When the project in Jira, Linear, or your PSA tool closes - or when a sprint milestone is reached - that event can trigger a contractor access review or expiry. This works especially well for contractors tied to a specific deliverable rather than an ongoing role.

Staffing Agency and Workforce Management Systems

If you use a vendor management system (VMS) or staffing platform, the contractor lifecycle often lives there first. An API connection between your VMS and your IGA platform means contractor onboarding and offboarding synchronize automatically - no manual handoff required.

The unifying principle: every intake path needs to produce the same three data points - start date, end date, and access scope - and feed them into a single governance layer that applies consistent policy regardless of how the contractor was sourced.

Fine-Grained Provisioning: The Difference Between "Access" and "The Right Access"

One of the most common mistakes in contractor onboarding is provisioning access by analogy: "Give them the same setup as the dev team." Fast? Sure. Correct? Never.

Contractors should get only the access their specific role and project require - at the most granular level your tools support. That means:

  • Slack: specific channels, not workspace-wide access
  • GitHub: specific repositories, not org-wide membership
  • Notion: specific pages or databases, not full workspace access
  • Jira: specific projects, not every project in the instance
  • AWS/GCP: specific environments, not dev-or-prod-level broad roles

This isn't pedantry. It's the difference between a contractor whose access, if compromised, exposes one project - and one whose access exposes your entire engineering stack.

Most IGA tools stop at SCIM group assignments, which means fine-grained access at the channel, repo, or project level goes unenforced. Look for a platform with connectors that go deeper than SCIM - what some call "SCIM++" - so the policy you write matches the access actually granted.

The Three-Trigger Offboarding Model

Clean contractor offboarding doesn't rely on a single trigger. It uses three in parallel - any one of which should be sufficient to revoke all access:

Trigger 1 - Date-Based Expiry The contract end date, captured at onboarding, fires an automated full deprovision on the scheduled day. No human action required. This is the primary trigger.

Trigger 2 - Manager-Initiated Offboarding The sponsoring manager has a single-action offboarding button - in the governance platform, or surfaced via Slack/Teams - that immediately removes all contractor access. This handles early terminations, scope changes, and situations where the contract end date shifts unexpectedly.

Trigger 3 - Inactivity-Based Suspension If a contractor account shows zero login activity for a configurable period (30 days is a reasonable default), it's automatically flagged for suspension and sent to the sponsoring manager for review. This catches contractors who've informally stopped working but whose formal end date hasn't arrived - and accounts that were simply forgotten.

All three triggers need to deprovision access across every connected application - including apps outside the SSO perimeter, apps without SCIM support, and any direct credentials provisioned outside your main identity provider. An offboarding that removes Okta access but leaves GitHub, Notion, and the customer portal untouched is a partial offboarding - which is just an orphaned account in slow motion.

Audit Readiness: Closing the Loop on Every Contractor Lifecycle

When a compliance framework asks you to prove a contractor no longer has access, you need that proof in seconds - not reassembled from screenshots, access logs, and Slack histories over three weeks.

Every contractor offboarding event should automatically generate a deprovisioning record: a timestamped report listing every account closed, across every app, with the trigger that fired and the approver of record. This document, alongside the original access approval from onboarding, forms a complete identity lifecycle audit trail.

That audit trail answers questions like:

  • "Who had access to this repository between January and March?"
  • "Was contractor X still active on the day of the incident?"
  • "Can you prove the former vendor's access was removed when the contract ended?"

These are real audit questions. The organizations that answer them confidently are the ones that automated the lifecycle - not the ones with the most comprehensive spreadsheet.

For a broader look at how identity governance supports compliance readiness across frameworks like SOC 2, ISO 27001, and DORA, see our guide to regulatory-ready identity governance.

Where Universal Connectors Change the Equation

Everything in this guide depends on one underlying capability: the ability to provision and deprovision access across every app in your stack - not just the SCIM-friendly ones.

According to research cited by C1, 89% of organizations have integrated fewer than half of their applications with their IGA solution - leaving most of the environment ungoverned. Contractors often access the exact tools that sit outside the SSO perimeter (the project management tool, the analytics dashboard, the design platform on a free tier), making this gap even wider.

Iden's universal connectors reach 175+ applications, including apps without SCIM or APIs - no enterprise plan upgrades required to unlock automation. That means contractor access, including the "silly SaaS apps" that somehow became critical to your stack, is governed from day one with the same lifecycle automation that applies to your SCIM-connected core tools.

When a contractor's end date arrives, offboarding fires across every connected application automatically. Not just Okta. Not just the apps with SCIM. All of them. That's what zero missed offboarding actually requires.

Key Takeaways

  • Contractors don't have HRIS records - JML automation that depends on HR events will never fire for them. You need alternative identity sources.
  • Capture three data points at onboarding: contract end date, sponsoring manager, and granular access scope. Without these, clean offboarding is impossible.
  • Use three parallel offboarding triggers: date-based expiry, manager-initiated removal, and inactivity-based suspension. Any one should be sufficient.
  • Fine-grained access matters: provision at the channel, repo, and project level - not broad group assignments that outlast the engagement.
  • Universal connector coverage is the enforcement layer: time-bound access policies are only as strong as your ability to enforce them across 100% of your stack.
  • Auto-generate deprovisioning records: your audit trail should be automatic, not reconstructed manually when an auditor asks.

Frequently Asked Questions

help_outlineWhat if contractors are onboarded by different teams and there's no central intake process?expand_more

This is the most common situation. The fix isn't to mandate a single intake channel overnight - it's to wire multiple intake channels into a single governance layer. Whether the request comes from a Jira ticket, a manager-submitted form, a procurement portal, or a staffing agency API, your IGA platform should be able to ingest that request, extract the lifecycle metadata (start date, end date, scope), and apply the same policy-driven provisioning logic regardless of source.

help_outlineCan we enforce time-bound access for apps that don't support SCIM or have no API?expand_more

Yes - but only if your governance platform has universal connector coverage. Most IGA tools stop at SCIM-enabled apps. Iden's universal connectors reach apps with SCIM, apps with APIs, and apps with neither, using agent-based or UI-driven automation to provision and deprovision access regardless of what the application natively supports. Time-bound access is only as good as your ability to enforce it across 100% of the stack.

help_outlineWhat's the minimum metadata we need to collect at contractor onboarding to enable clean offboarding?expand_more

At minimum: contract end date, sponsoring manager (the offboarding approver), and the specific access scope (which apps, which repos, which channels - not just a role group). With these three data points, you can build a fully automated lifecycle that provisions on day one and deprovisions on day last without any manual intervention.

help_outlineHow do we handle contractors who extend their contract or come back for a second engagement?expand_more

Extensions should trigger a re-attestation workflow - the sponsoring manager approves a new end date, and the expiry is updated automatically. For returning contractors, treat them as a net-new provisioning cycle: re-verify their access needs, apply least-privilege from scratch, and set a new expiry. Avoid the temptation to simply 'reactivate' an old account, which often carries stale permissions from the previous engagement.

help_outlineHow do we prove to an auditor that a contractor's access was fully removed?expand_more

Your IGA platform should auto-generate a deprovisioning record at the moment offboarding completes: a timestamped report listing every account closed, in every app, at what time, triggered by which event (date-based, manager-initiated, or inactivity). This record - alongside the original access approval - forms a complete identity lifecycle audit trail. No screenshots. No manual log correlation. No weeks of prep.