Friday terminate, Monday the vendor is still reading mail
Most offboarding runbooks end at Okta disable or Google Admin suspend. That kills the human session. It does not kill the refresh tokens the employee handed to HubSpot, an AI extension, and a personal GitHub six months ago. Monday morning those vendors still call Gmail. The auditor who samples terminated users will find the grants. You will write a management response.
The ScopeMantle model is a cascade: HRIS event, IdP suspend, grant revoke for that principal, then SCIM cleanup, then a closed ticket with an export. Order matters. SCIM first looks tidy and leaves the tokens. Revoke first, then deprovision the app tiles you actually own.
HRIS-triggered deprovisioning is on the product Roadmap. SCIM cascade revoke is Beta. You can still run the cascade by hand or with your own webhooks today. This page is the model, the edge cases, and the evidence pack. See the companion OAuth offboarding SCIM cascade post for IdP-specific notes.
The failure mode in one paragraph
Employee is terminated Friday at 16:00. Okta is disabled at 16:12. Google session dies. Drift still holds a Salesforce refresh token the AE authorized in 2023. An AI tool still holds gmail.readonly. Neither grant is an "app assignment" in the Okta tile sense. Both are user-consent OAuth. Your CASB sees nothing. Your SCIM job deprovisions Salesforce the user account and congratulates itself. The Drift token is a different credential. That is the finding.
Cascade design
| Step | Owner | Evidence |
|---|---|---|
| 1. HRIS termination (or garden-leave effective date) | HR / people ops | Webhook or ticket timestamp |
| 2. IdP suspend | Identity | Okta / Google event |
| 3. Revoke all OAuth grants for the principal | Security / ScopeMantle | Per-grant revoke log |
| 4. SCIM deprovision sanctioned apps | IAM / IT | SCIM 204s / app admin export |
| 5. Close ticket with export attached | IT ops | Hash of "zero grants remain" query |
Run revoke before you announce internally if you are in a leaky-org situation. Run it at the effective date, not the announcement date, if counsel or a union contract says so. Those are legal inputs. The cascade just needs a timestamp it can trust.
Edge cases people skip
Garden leave / legal hold. Counsel may delay revoke on a mailbox. Document the exception with an effective revoke date. Do not leave it as a Slack "hold off." Personal OAuth grants to random AI tools are rarely on the hold. Split the mailbox hold from the toy-grant revoke.
Shared mailboxes. Exchange / Google shared-mailbox delegation is a separate workflow. Still revoke the person's own grants the same day. Do not wait for the mailbox project.
Union notification periods. Automate on effective termination, not the day HR told the manager.
M&A. Duplicate grants across two IdPs for ninety days post-close are normal. Map the legacy IdP before you merge. KPI is still zero grants on the terminated side.
Service accounts. If a "user" grant looks like automation, pull it out of the workforce cascade and treat it as a production-identity review. Do not bulk-revoke a CI bot because someone reused a human mailbox.
Procedure you can run without ScopeMantle
- Pick ten users terminated in the last 90 days.
- In Google Admin, open each user (or export tokens) and list third-party apps still authorized.
- In Okta, list OAuth grants / admin-approved apps still assigned or still consented.
- Count remaining grants. If the number is not zero, you have the finding. Write it down before someone "cleans the sample."
- Revoke remnants. Screenshot or export after.
- Add a checklist line to the offboarding ticket: "OAuth grants = 0." Not "account disabled."
- For the next termination, run the grant revoke in the same change window as IdP suspend.
- Once a quarter, run a synthetic termination in a test OU. Target: zero grants within sixty minutes. Record the drill.
At a few hundred employees this is painful and still doable. At a few thousand it is how senior engineers quit. Productized revoke with a retained log is the point of governance once HRIS trigger is live. Until then, the connector still gives you per-user grant inventory from Google Workspace and Okta so the ticket is not a treasure hunt.
Migration from IdP-only (three weeks, no heroics)
- Week one. Baseline grants for all active employees. Note terminated-user leftovers and clean them as a one-time project.
- Week two. Wire HRIS webhook to a test tenant. Fire a fake termination. Confirm revoke then SCIM. Keep a rollback: re-consent is ugly, so use a test user.
- Week three. Production cutover. Measure the KPI: terminated users with nonzero grants = 0.
Log retention for revoke events should match your audit hold. Teams often pick seven years because that is what they already use for access logs. Pick a number counsel already blessed. Do not invent a new retention class for OAuth.
What to tell an auditor
"CC6.7 shows the account was disabled. CC9.2 shows the delegate tokens were revoked. Here is a terminated-user sample with a zero-grant export hashed on the ticket." If SCIM is in the packet, label it as app-account deprovision, not as OAuth revoke. If Entra is involved, label Beta. If someone asks about HIPAA, we are not attested and we offer no BAA.
Failure modes
- SCIM-only runbooks.
- Revoking by display name after a rebrand, missing the client ID.
- Disabling the user and assuming Google kills third-party tokens. It does not, not in the way you want.
- Skipping contractors because they were never in the HRIS. Put contractors in the HRIS or accept they will never offboard cleanly.
- Measuring success as "ticket closed in ITSM" instead of "grants remaining = 0."
How ScopeMantle fits
Identity engineers should verify terminated users show zero grants after the webhook (or the manual ticket) processes. Sixty minutes is a reasonable internal SLA once automation exists. Until HRIS trigger is Roadmap-complete, measure ticket age instead and be honest about it.
M&A week is when people skip the cascade because two IdPs are in flux. That is when leftover grants multiply. Freeze terminations to a single runbook owner for the first fortnight after close, or you will explain the sample at the next audit with a shrug.
Today: inventory and manual / API revoke with an audit trail. SCIM cascade revoke: Beta. HRIS-triggered deprovisioning: Roadmap. Entra: Beta. Pricing $5 / $6, no seat min, custom 500+, 30-day trial. Pair with shadow OAuth so you understand why the token survived the disable.
Worked example: the AE who left for a competitor
Friday: HR marks the AE terminated effective end of day. Okta disable at 17:10. Salesforce SCIM removes the user at 17:18. Marketing's conversation-intelligence app still holds a refresh token the AE authorized in 2023. Monday the competitor rumor mill is loud and you cannot prove the token is dead. That is not a hypothetical personality. It is the Drift-shaped leftover on a single principal.
Fix: step 3 and 4 of the paste-in runbook, same Friday window. Export the AE's grants at 17:12. Revoke. Confirm zero. Then SCIM. If legal hold applies to the mailbox, still revoke the intelligence app unless counsel names it in the hold. Most holds do not name a random OAuth client. Ask the question once, in writing.
Identity should not wait for the laptop return ticket. Tokens do not live on the laptop. MDM wipe is irrelevant to Drift-shaped leftovers. Say that in the ITSM workflow so service desk stops sequencing OAuth behind shipping labels.
For shared mailboxes the Exchange or Google group work continues on its own ticket. The personal grant revoke still closes Friday. Splitting those tickets is how you keep CC9.2 samples clean: the auditor asks about the human, you show zero grants, and the mailbox project is a different workpaper. Identity engineers implementing this should treat sixty minutes to zero grants as the internal SLA once automation exists, and should say so when it does not.
IdP-specific notes (GA vs Beta)
Google Workspace (GA connector). User-level third-party apps live under the user and under the org-wide Apps with access list. Revoke at the user for offboarding. Revoke at the client ID if the whole vendor is dead. Super-admin is not required for daily review if you grant a delegated app-access admin. Keep super-admin sampling in CC6.1, not mixed into this packet.
Okta (GA connector). Distinguish app assignments you pushed via SCIM from grants the user consented. Both can survive a deactivate depending on how the app is configured. Test with a real disposable user. Read the cascade post before you argue with IAM in Slack.
Entra (Beta). Do not write an offboarding SLA that assumes Entra grant revoke is complete. Label the gap. Multi-IdP companies that only clean Google will claim success and fail the Microsoft-side sample.
Contractor and agency paths
Agencies that run ads or support on your Salesforce often authorize connected apps from their own users. Your HRIS will never terminate them. Put agency users in a register with an end date, or accept that offboarding is a contract clause plus a quarterly Connected Apps export, not an HRIS webhook. ScopeMantle will not invent those humans.
Contractors in a separate IdP (vendor tenant) need the same zero-grant check in that tenant. If you cannot get API access, make it a SOC 2 vendor-review question and sample screenshots. Honest limitation.
Runbook text you can paste
Offboarding addition (paste into ITSM) 1. HRIS effective date recorded. 2. IdP suspend (Okta / Google). 3. Export OAuth grants for principal (client ID, scopes). 4. Revoke all user-consent grants. Confirm count = 0. 5. SCIM deprovision sanctioned apps. 6. Shared mailbox / legal hold: counsel exception ID or N/A. 7. Attach before/after export. Hash. Close.
If step 4 is missing, the ticket is an account disable, not an offboarding. Name it honestly in the sample or the auditor will name it for you.
What to do this week
- Sample ten recent terminations. Publish the leftover-grant count internally. That number funds the project.
- Add "OAuth grants = 0" to the offboarding template.
- Name the garden-leave exception owner (counsel).
- Schedule one synthetic termination drill.
- Read the cascade post and start a trial if you want the inventory on day one.
Until automation exists, publish the manual median from the last ten terminations. A median of three days is a program you can defend. A hope of sixty minutes is only a slide. Laptop return stays a separate ticket. Tokens do not live on the laptop.
Field guide: showing the leftover number without a witch hunt
Sample ten terminations. Publish the count. Do not name the humans in a company-wide channel. Name the process gap. Add the ITSM line. Schedule the disposable-user test. If HR will not give emails, the sample is blocked and that is also a finding. $5 / $6, no seat min, HRIS Roadmap, SCIM Beta, Entra Beta. Cascade post.
After the first ten tickets, publish leftover grants as a rate, not a vibe. If the rate is not zero, the cascade is still a draft. Keep laptop return off the predecessor list. Keep Entra labelled Beta in any SLA you write. Trial via /demo if you want per-user grant lists without a scavenger hunt in Admin.