What IdentityOps is
Link to section “What IdentityOps is”In 30 seconds
Link to section “In 30 seconds”IdentityOps (identity operations) keeps an organisation’s digital identities accurate and their authentication strong. It creates, changes and removes accounts as people join, move and leave, driven by the HR record; connects applications through single sign-on (SSO) and automated provisioning; enrols and recovers multi-factor authentication (MFA); and tracks machine identities (service accounts, API keys, OAuth applications) that have no HR record at all.
In one line: every identity that can sign in belongs to someone or something that still needs it, and proves itself with a method that is hard to phish and hard to talk a help desk into resetting.
For IAM engineers, IT administrators, identity architects and security leaders. Facts checked 2026-10-17.
At a glance
Link to section “At a glance”| Item | Summary |
|---|---|
| Term status | Emerging. A label in vendor glossaries and team names, with differing scopes. The field beneath it, identity and access management (IAM), is established, with a professional body of knowledge[5] and stable standards. |
| Goals | No account outlives its need; joiners productive on day one; leavers out everywhere within the SLA; phishing-resistant sign-in and recovery; every machine identity owned. |
| In scope | Joiner–mover–leaver (JML) from HR, directories and identity providers (IdPs), SSO (SAML, OIDC), SCIM provisioning, MFA enrolment and recovery, the IGA platform and birthright access, non-human identities (NHIs), identity threat signals. |
| Out of scope | Permission design, access requests and reviews, the HR process, detection: see what it is not and its neighbours. |
| Prerequisites | None; basic web authentication (passwords, cookies, tokens) helps. |
| Key outputs | Lifecycle policy and SLAs, an application register, reconciliation reports, MFA and recovery standards, an NHI register, audit evidence. |
The problem it solves
Link to section “The problem it solves”MITRE ATT&CK lists valid accounts as a route to initial access and persistence, noting that adversaries “may abuse inactive accounts: for example, those belonging to individuals who are no longer part of an organization”.[6] Every incident in the use cases is an identity that should not have existed, or should not have been usable.
| Operating reality | Without IdentityOps | With IdentityOps |
|---|---|---|
| A leaver | IT learns days later; some SaaS accounts stay active | The HR termination triggers disablement, deprovisioning and session revocation within an SLA |
| A new SaaS app | Local accounts with their own passwords | SSO plus SCIM, or a documented exception |
| A lost phone | A help desk resets MFA after a friendly call | Recovery by a defined method, with notification |
| A service account | Shared password, no owner, no expiry | Registered owner, short-lived or rotated credential, end date |
What IdentityOps is not
Link to section “What IdentityOps is not”- Not authorisation design. Roles, policies and least privilege are IAMOps. IdentityOps assigns birthright access (the access a role gets automatically) but does not design the permissions behind it.
- Not privileged access. Requests, just-in-time elevation, vaults and review campaigns are AccessOps, run on the IGA platform this page operates.
- Not HR. PeopleOps decides that someone joins, moves or leaves and owns the data; IdentityOps changes accounts.
- Not a product. An IdP or IGA suite is a tool; a stale HR feed defeats either.
- Not customer identity first. Customer identity (CIAM) shares the protocols but not the lifecycle; this page is workforce-first.
Where IdentityOps comes from and where it sits
Link to section “Where IdentityOps comes from and where it sits”Origins and evolution
Link to section “Origins and evolution”No founding document exists. The label is recent; the standards it operates are not: SAML 2.0 (OASIS, March 2005)[7] and SCIM 2.0 (2015)[8][9] for sign-in and provisioning; CISA’s call for phishing-resistant MFA as “the gold standard” (2022);[10] NIST SP 800-63-4 (July 2025);[11] the OpenID shared-signals specifications (approved as Final Specifications in September 2025);[12] and NIST IR 8587 on token protection (September 2026).[13]
Glossary and mental model
Link to section “Glossary and mental model”| Term | Meaning on this page |
|---|---|
| Authoritative source | The system that decides an identity should exist: HR for employees, a sponsor record for contractors and guests, an owner register for machines. |
| Directory / IdP | The directory stores accounts and groups (Active Directory, LDAP); the identity provider authenticates users for applications. Microsoft Entra ID plays both roles. |
| SSO (SAML, OIDC) | The IdP vouches for the user with a SAML assertion or an OpenID Connect ID token, whose sub is “never reassigned” within an issuer.[14] |
| Provisioning (SCIM, JIT) | Creating, updating and deactivating accounts in applications. SCIM uses an API; just-in-time (JIT) creates an account at first SSO login and has no channel for removal. |
| Orphan / dormant account | Orphan: no authoritative source or owner. Dormant: unused for longer than policy allows. |
| Phishing-resistant authenticator | One that cannot be relayed through a fake site: FIDO2/WebAuthn and PKI smart cards. Codes typed by hand (OTP, SMS) are not.[15] |
| AAL1–AAL3 | NIST’s authentication assurance levels: at least one factor; two factors; two factors with a phishing-resistant, non-exportable key.[15] |
| Account recovery | Regaining access after losing authenticators; NIST sets the allowed methods per AAL.[15] |
| NHI | A non-human identity: service account, API key, OAuth client, certificate, workload identity. |
| IGA | Identity governance and administration: the platform that holds lifecycle and birthright rules and produces evidence. |
| Tier-0 | A system whose compromise gives control of everything that trusts it: the IdP, its signing keys, the directory-sync server. A term from Microsoft’s administrative tier model.[16] |
| Shared signals | OpenID event standards: SSF is the framework, CAEP carries session and credential changes, RISC account events such as credential-compromise.[17][18] |
The mental model: three ledgers that must agree. The HR ledger says who should exist. The directory says who can authenticate. The application ledger (local accounts plus live sessions and tokens) says who is actually in. Incidents live in the gaps: a terminated worker still enabled, a disabled user with a live session, a SaaS account the IdP never knew about.
How IdentityOps relates to other Ops
Link to section “How IdentityOps relates to other Ops”| Page | IdentityOps focus | Their focus |
|---|---|---|
| IAMOps | Identities, groups as lifecycle containers, NHI inventory | Permission design and evaluation, policy as code |
| AccessOps | Running the IGA platform, birthright rules | Requests, elevation, PAM, break-glass, reviews |
| PeopleOps | Account changes, reconciliation | The HR event, its data and dates |
| CloudSecOps | Federation into clouds, IAM users and keys | Cloud posture and guardrails |
| EndpointOps | Device signals in sign-in | Managing devices |
| DetectionOps, SOC Ops | Identity signals and containment actions | Detections, triage |
| ComplianceOps | Producing lifecycle evidence | Mapping it to frameworks |
Diagram source (Mermaid)
flowchart TB PEO["PeopleOps: HR events"] -->|"join, move, leave"| IDO IDO["IdentityOps: who exists, how they prove it"] IDO -->|"identities, groups"| IAM["IAMOps:<br/>what they may do"] IDO -->|"runs the IGA platform"| ACC["AccessOps:<br/>request, elevate, review"] IDO -->|"sign-in signals"| SIG["DetectionOps, SOC Ops:<br/>identity alerts"] IDO -.->|"lifecycle evidence"| CMP["ComplianceOps:<br/>evidence"] classDef core fill:#e8f3f2,stroke:#16756f,color:#122029 classDef neutral fill:#f1f4f6,stroke:#5b7a87,color:#122029 class IDO core class PEO,IAM,ACC,SIG,CMP neutral
Text equivalent: PeopleOps sends join, move and leave events into IdentityOps, which owns who exists and how they prove it. IdentityOps hands identities and groups to IAMOps (what identities may do), runs the IGA platform that AccessOps uses for requests, elevation and reviews, and sends sign-in signals to DetectionOps and SOC Ops (identity alerts). ComplianceOps draws lifecycle evidence from IdentityOps (dotted edge).
The split can be mapped onto NIST CSF 2.0’s PR.AA subcategories, an editorial mapping (the CSF assigns no teams): PR.AA-01 to -04 (identities, credentials, proofing, authentication, assertions) to IdentityOps; PR.AA-05 (permissions, least privilege and their review) to IAMOps for design and AccessOps for reviews.[19]
Principles and operating model
Link to section “Principles and operating model”Charter and principles
Link to section “Charter and principles”This charter is this Atlas’s proposal; no official IdentityOps manifesto exists.
Mission: every identity that can authenticate is known, owned, needed and strongly verified, and the evidence shows it.
- Every identity has an authoritative source. NIST SP 800-53 asks organisations to “Align account management processes with personnel termination and transfer processes”.[20]
- Events, not tickets, change accounts. A termination entered once in HR drives every downstream change.
- Deprovisioning ends when sessions end.
- Phishing-resistant by default; recovery no weaker than sign-in. A security key reset by phone is as strong as the phone call.
- Machines get a lifecycle too: owner, purpose, expiry, rotation, decommissioning.
- The IdP is tier-0 production: configuration, federation trusts and signing keys under change control.
- Measure the gaps between the three ledgers, not tickets closed.
Non-goals: designing permissions (IAMOps) and approving elevated access (AccessOps).
Fundamentals: the building blocks
Link to section “Fundamentals: the building blocks”| Block | Job | Failure if missing |
|---|---|---|
| Authoritative sources | Decide who should exist | Orphans; missed leavers |
| Directory | Store accounts, groups, attributes | Duplicates; no stable identifier |
| Identity provider | Authenticate; issue assertions and tokens | Passwords per app |
| Lifecycle engine / IGA | Turn HR events into account changes | Manual tickets; drift |
| Provisioning connectors | Create, update, deactivate in apps (SCIM 2.0, vendor APIs) | Accounts survive leavers |
| Authenticators and recovery | Prove control; restore it safely | Phishing; help-desk takeover |
| Signals | Detect misuse; share session changes | Late detection |
Examples of each are in the tooling landscape.
Roles, ownership and RACI
Link to section “Roles, ownership and RACI”R = responsible, A = accountable, C = consulted, I = informed.
| Activity | HR / PeopleOps | Identity team | Application owner | Service desk | SOC |
|---|---|---|---|---|---|
| Record join, move, leave with effective date | A/R | I | — | — | — |
| Lifecycle rules and birthright policy | C | A/R | C | I | — |
| Connect an app (SSO, SCIM) | — | R | A | I | — |
| Leaver deprovisioning within SLA | C | A/R | R (non-SCIM apps) | I | I |
| MFA enrolment and recovery standard | — | A/R | — | R (executes) | C |
| NHI registration and rotation | — | A | R (each owner) | — | I |
| Identity alert containment | — | R | I | — | A |
| Lifecycle evidence for audit | C | A/R | C | — | — |
Managers and sponsors confirm contractor and guest need.
Lifecycle: joiner, mover, leaver
Link to section “Lifecycle: joiner, mover, leaver”Diagram source (Mermaid)
stateDiagram-v2 direction TB [*] --> Prehire: HR record created Prehire --> Active: start date, after proofing Prehire --> Deleted: offer withdrawn or no-show Active --> Active: mover recalculates birthright Active --> Suspended: leave of absence Suspended --> Active: return Active --> Disabled: leaver effective date Suspended --> Disabled: leaver effective date Disabled --> Active: rehire under policy Disabled --> Deleted: retention period ends Deleted --> [*]
Text equivalent: an identity starts in Prehire when HR creates the record and becomes Active on the start date, once the person is proofed; if the offer is withdrawn or the person never starts, it is deleted, not left as an orphan. A move keeps it Active but recalculates birthright access. Leave moves it to Suspended and back. On the leaver effective date it becomes Disabled. A rehire can reactivate it under policy; otherwise it is Deleted when the retention period ends.
- Prehire. Create the identity disabled so day-one access is ready. Microsoft’s HR provisioning matches records by employee ID by default and asks how rehires and termination dates are handled.[21]
- Proof before bootstrap. A bootstrap credential is only as good as the check on who receives it. HR or the hiring manager matches the person to identity documents before day one. For remote hires, Microsoft, writing on North Korean IT workers using stolen or “rented” identities, advises several on-camera sessions, asking people to “physically hold driver’s licenses, passports, or identity documents up to camera”, and notarised proof of identity.[22] Hand the pass only to the proofed person, in person or on live video. NIST SP 800-63A defines identity assurance levels (IAL1–IAL3) if you need a formal standard.[23]
- Joiner. Enable on the start date, assign birthright groups, and enrol phishing-resistant MFA with a bootstrap credential such as Entra’s Temporary Access Pass, “a time-limited passcode”.[24]
- Mover. Recalculate birthright and remove what the old role granted; movers are where access accumulates (Lab 1 checks it).
- Leaver. Disable, deprovision downstream, revoke sessions and tokens, delete after retention (the leaver workflow gives the product behaviour).
- Rehire. Reactivate with no previous access, or create a new identity, by written policy.
Operating model and governance
Link to section “Operating model and governance”Cadence: HR events, provisioning and alert routing run continuously; reconciliation and provisioning errors daily, with an owner per exception; a sample of assisted recoveries and new-app intake weekly; metrics and the NHI expiry report monthly; the leaver drill and an IdP configuration and federation-trust review quarterly.
SLAs are yours to set: NIST AC-2 leaves notification and disabling periods to the organisation.[20] Review IdP changes (new trust, admin or authentication policy) like production changes; attackers have added rogue federation trusts (Case 4).
Architecture and workflow
Link to section “Architecture and workflow”Reference architecture
Link to section “Reference architecture”Diagram source (Mermaid)
flowchart TB HR["HR system: authoritative for people"] --> LC REG["NHI owner register"] --> LC LC["Lifecycle engine / IGA: rules, birthright"] --> DIR DIR["Directory and IdP"] -->|"SSO, SCIM,<br/>CAEP events"| APPS APPS["SaaS and internal apps"] DIR -->|"sign-in logs,<br/>risk"| SOC["SOC and detection"] APPS --> REC["Reconciliation<br/>HR and NHI register vs<br/>directory export vs app exports"] DIR --> REC HR --> REC REG --> REC classDef core fill:#e8f3f2,stroke:#16756f,color:#122029 classDef neutral fill:#f1f4f6,stroke:#5b7a87,color:#122029 class LC,DIR,REC core class HR,REG,APPS,SOC neutral
Text equivalent: the HR system and the NHI owner register feed a lifecycle engine or IGA platform, which writes to the directory and IdP. The IdP signs users in to applications with SAML or OIDC, provisions them with SCIM, sends session events with CAEP, and sends sign-in logs and risk to the SOC. Reconciliation compares all three ledgers: HR and the NHI register (who should exist), the directory’s account export (who can authenticate) and application account exports (who is actually in).
| Component | Trust boundary notes |
|---|---|
| HR system | A write to HR can create an account: protect HR admin roles |
| Lifecycle engine / IGA | Connector credentials are high-value NHIs |
| Directory and IdP | Tier-0: admin roles, trusts and signing keys; see NIST IR 8587 on key management and token verification[13] |
| Provisioning connectors | One scoped, rotated token per app |
| Reconciliation | Reads each ledger directly, not the provisioning log |
Alternatives. Cloud-first: lifecycle in the IdP’s own features (licence-dependent[25]). Hybrid: HR provisions into Active Directory, which synchronises to the cloud;[21] the sync server “must be treated as a Tier 0 component”,[16] and Windows services should prefer group managed service accounts, whose passwords Windows manages.[26] IGA suite: for many sources and complex rules, at the cost of another tier-0 system.
End-to-end workflow: a leaver
Link to section “End-to-end workflow: a leaver”Diagram source (Mermaid)
sequenceDiagram autonumber participant HR as HR participant LC as Lifecycle participant IDP as IdP participant APP as SCIM app participant EV as Evidence HR->>LC: termination 17:00 LC->>IDP: disable account LC->>IDP: revoke sessions IDP->>APP: active=false Note over IDP,APP: Entra: next cycle APP-->>IDP: 200 or 204 Note over LC,EV: 6. timestamps recorded as evidence
Text equivalent: HR sends a termination with an effective time to the lifecycle engine, which disables the IdP account and revokes sessions and refresh tokens. The IdP sends each SCIM app a PATCH setting active to false (Okta on deactivation, Entra in its next provisioning cycle); the app replies 200 or 204. Finally the engine records each system’s timestamp as evidence (shown as a note across the lifelines).
Happy path, and what it depends on. Both IdPs deprovision SCIM apps by setting active to false, but only if configured
to: Okta needs “Deactivate Users” enabled for the app;[27] Entra needs the update action and the active
mapping.[28] Okta sends the request when the user is deactivated; Entra’s cycles run “approximately every 40 minutes” (as
of October 2026).[29]
Urgent leavers in Entra. On-demand provisioning can disable a user unassigned from an app, not one already disabled in Entra; a push “typically takes less than 30 seconds”.[30] In this page’s reading, that means: unassign the person from each critical app, push it, then disable the account. This reverses the disable-first order above and in Microsoft’s emergency steps[31] and leaves the account enabled until the last push, so use it only when removal inside the apps matters more than those minutes. It needs the app scoped to “Sync only assigned users and groups”,[28] and apps that authorise with OAuth (Microsoft names G Suite, Box and Slack) need their provisioning job stopped first.[30] An unassigned user leaves the job’s management, so a later soft-deletion sends no delete.[28] Otherwise disable first and deactivate critical apps directly (the Tier B path).
When deactivation means deletion. Okta never sends a delete,[27] but Entra sends a DELETE to apps without
soft-delete support and, unless the Delete target action is cleared, when the source user is permanently deleted
(automatically 30 days after soft deletion, or earlier by hand).[28] RFC 7643 leaves the meaning of active to each
application.[8]
Exception paths (each needs an owner and an SLA):
- Sessions outlive the account. Entra access tokens last about 60–90 minutes by default (Microsoft’s pages say “1 hour”
and “60-90 minutes”), and up to 28 hours where CAE applies (as of October 2026);[31][32] “the user
loses access when the access token expires”.[31]
revokeSignInSessionsinvalidates refresh tokens and session cookies after “a small delay of a few minutes”.[33] Okta’s session revocation “doesn’t clear the sessions created for web or native apps”.[34] Apps with their own sessions need their own revocation or short lifetimes. - Provisioning is broken. An Entra job whose calls keep failing enters quarantine, where its cycles slow to once a day, and is disabled after more than four weeks in quarantine;[28] leavers silently stay active in that app.
- Legal hold. Disable sign-in now; delay deletion; check each app’s deprovisioning behaviour first. In Entra, clear the Delete target action; for apps without soft delete, where even a disable becomes a DELETE, preserve the data before disabling or handle that app by hand (Tier B or C).[28] In Okta, deactivating the user is “a destructive operation” that deprovisions all assigned apps; suspension keeps assignments.[34]
Practices, frameworks and tools
Link to section “Practices, frameworks and tools”Core practices and playbooks
Link to section “Core practices and playbooks”| Practice | Goal | Trigger | Owner | Verification |
|---|---|---|---|---|
| HR-driven provisioning | Accounts follow HR | HR event | Identity team | Daily reconciliation |
| App connection standard | SSO and SCIM everywhere | New app | App owner | Register coverage |
| Mover recalculation | No access accumulation | Attribute change | Lifecycle engine | Group difference report |
| Leaver drill | Prove deprovisioning | Quarterly | Identity team | Per-app timestamps within SLA |
| Dormant sweep | Disable unused accounts, guests included; excluded: HR-suspended identities, emergency accounts,[35] NHIs with a registered longer cadence (owner confirms first) | Daily | Identity team | Window of 90–180 days, as Microsoft suggests;[36] exclusion list reviewed quarterly |
| Phishing-resistant rollout | Remove phishable sign-in | Programme | Identity team | Coverage and usage metrics |
| Verified recovery | No reset on a caller’s word | Every reset | Service desk | Weekly sample review |
| NHI registration and rotation | Machine identities owned and current | New credential; monthly | Each owner | Register vs inventory |
| IdP change control | Catch rogue admins and trusts | IdP change | Identity team | Unapproved-change alert |
Authentication and recovery practice
Link to section “Authentication and recovery practice”Phishing resistance. NIST SP 800-63B-4 requires verifiers to “offer at least one phishing-resistant authentication option at AAL2” and requires phishing resistance for US federal staff.[15] CISA calls FIDO/WebAuthn “The only widely available phishing-resistant authentication”; PKI smart cards also qualify.[10] Roll out in risk order: IdP and cloud administrators, then email, remote access and finance, then everyone. Synced passkeys suit most staff, but their keys are exportable, so NIST excludes them from AAL3:[15] give administrators device-bound security keys. Where push MFA remains, limit prompts[15] and use number matching as an interim step.[10]
Passwords, while they last: at least 15 characters (8 when used only with a second factor), no composition rules, no periodic changes, a forced change on evidence of compromise, and a blocklist of common and breached passwords.[15]
Recovery. NIST recognises saved recovery codes, issued recovery codes, recovery contacts and repeated identity proofing; any other method, such as a help-desk agent, must be “based on a risk analysis and documented”. At AAL2, recovery needs two codes obtained by different methods, a code plus a still-bound authenticator, or repeated proofing, and every recovery or new authenticator triggers a notification.[15] CISA’s advisory shows the attack: Scattered Spider posed as employees “to convince IT and/or helpdesk staff to provide sensitive information, reset the employee’s password, and transfer the employee’s MFA to a device they control”.[37] A defensible design:
- Self-service first, through a second registered authenticator (NIST encourages “at least two separate means of authentication”[15]).
- Assisted recovery issues a one-time bootstrap credential[24] only after the manager (or sponsor) confirms the person on a live video call or in person, and delivers it through that manager or to an already-registered device, never read out to the caller. A call-back to the HR phone number is weak evidence on its own: Scattered Spider conducted “SIM swaps” before calling help desks,[37] and NIST asks verifiers to consider “SIM change, number porting” before using the phone network to deliver an out-of-band secret[15] (a rule written for authentication; this page applies it by analogy to call-back verification).
- Privileged and high-risk accounts recover only through repeated proofing (in person or supervised video against an identity document) and a second administrator’s approval.
- Watch the seam: alert when a new MFA method follows a reset within hours, and when a federation trust or IdP admin is added.
Non-human identity lifecycle practice
Link to section “Non-human identity lifecycle practice”Machine identities have no HR record, so nothing signals their end. OWASP’s Non-Human Identities Top 10 (2025) starts with “Improper Offboarding”, “the inadequate deactivation or removal of non-human identities (NHIs) such as service accounts and access keys when they are no longer needed”, and includes long-lived secrets, NHI reuse and human use of NHIs.[38]
- Inventory per system: IdP app registrations and service principals, cloud IAM users and keys, CI/CD secrets, SaaS API tokens. AWS’s credential report covers IAM users’ passwords, keys and MFA, but only the first two access keys and no service-specific credentials.[39] It lists users only: IAM roles need their own inventory and last-used data,[40] designed with IAMOps.
- Register owner, purpose, environment, expiry and expected cadence: a quarter-end job is not dormant at 90 days, so the dormant sweep and Lab 3’s idle rule must read the registered cadence. No owner, no credential.
- Prefer short-lived credentials: AWS advises requiring “workloads to use temporary credentials with IAM roles”;[41] designing that federation belongs to IAMOps.
- Rotate what must stay long-lived, and record it.
- Decommission with evidence: check last use, disable, wait a business cycle, delete (Case 2 shows the cost of guessing).
Methods, standards and frameworks
Link to section “Methods, standards and frameworks”| Source | Kind | Use in IdentityOps |
|---|---|---|
| NIST SP 800-63-4[11] | US federal guideline | Assurance levels; authentication and recovery design |
| NIST SP 800-53 AC-2[20] | Control catalogue | Account management SLAs and evidence |
| NIST CSF 2.0 PR.AA[19] | Voluntary framework | Mapping controls across the identity trio |
| CISA ZTMM v2.0[42] | Maturity model (US federal) | Calibrating the maturity model |
| SAML 2.0, OIDC Core, RFC 9700[7][14][43] | Protocol standards | Federation and OAuth configuration baselines |
| SCIM 2.0[9] | Protocol standard | Provisioning requirement for apps |
| SSF, CAEP, RISC[12] | Protocol standards (final 2025) | Session and risk events across vendors |
| OWASP NHI Top 10[38] | Community risk list | NHI review checklist |
| MITRE ATT&CK[6] | Adversary knowledge base | Detection coverage with the SOC |
RFC 9700 doubles as an IdP configuration test: the implicit grant “SHOULD NOT” be used and the resource owner password credentials grant “MUST NOT be used”.[43] Most of these documents are US-originated; check your jurisdiction before treating any as a legal requirement.
Tooling landscape
Link to section “Tooling landscape”Categories first; named products are examples verified in documentation (as of October 2026), not endorsements.
| Category | Verified examples | Selection criteria |
|---|---|---|
| HR source | Workday, SAP SuccessFactors[21] | Effective dates, worker types, API |
| Directory and IdP | Microsoft Entra ID, Okta, Active Directory | SCIM, phishing-resistant methods, revocation API, logs |
| Lifecycle and IGA | Entra lifecycle workflows;[25] dedicated IGA suites | Connectors, testable rules, audit reports |
| Authenticators | FIDO2 security keys, passkeys, PIV cards | Exportability, recovery, device support |
| Identity threat signals | Entra ID Protection;[44] tools sold as identity threat detection and response (ITDR)[45] | Coverage beyond one IdP; judge ITDR by what it adds to the IdP’s own detections |
| NHI inventory | AWS IAM credential report;[39] IdP app registrations | Last-used data; credential types covered |
Lock-in. Every application trusts the IdP’s signing keys, which makes it the hardest system to replace; standard connections (SAML or OIDC plus SCIM) keep an exit possible.
Automation and AI
Link to section “Automation and AI”Automate the routine lifecycle; keep human approval for contractors without HR records, rehires, privileged identities and bulk changes (a mass termination can be an HR error). Machine learning already sits inside IdP risk detections. A language model may summarise a sign-in investigation; it must never be the verifier in a recovery flow. AI agents are NHIs (going further).
IdentityOps in practice
Link to section “IdentityOps in practice”Reference implementation
Link to section “Reference implementation”An illustrative design for a 2,000-person company with a cloud HR system, one cloud IdP and about 150 SaaS applications. The policy below is the single place where lifecycle rules live; the schema is this Atlas’s illustration, not a product format.
Example status: YAML syntax-checked by the Atlas validator; not loaded into any product.
# identity-lifecycle-policy.yaml
version: 3
sources:
employees: {system: hr, match_on: employee_id}
contractors: {system: sponsor-register, max_days: 180, sponsor_required: true}
machines: {system: nhi-register, owner_required: true, max_credential_days: 90}
birthright:
all: [all-staff, email]
department:
finance: [finance, erp]
sales: [sales, crm]
engineering: [engineering, git]
slas:
joiner_ready_hours_before_start: 24
leaver_disable_idp_hours: 4
leaver_deprovision_all_apps_hours: 24
dormant_disable_days: 90
dormant_exclusions: [hr_suspended, emergency_access, nhi_with_registered_cadence]
leaver_actions:
- disable_idp_account
- revoke_sessions_and_refresh_tokens
- scim_deactivate_connected_apps
- open_tickets_for_non_scim_apps
- remove_authenticators
retention:
delete_after_days: 30
unless: legal_hold
rehire:
restore_previous_access: false
recovery:
self_service: {any_of: [second_authenticator]}
standard:
require_all: [manager_confirms_on_live_video_or_in_person, one_time_pass]
pass_delivery: [via_manager, to_registered_device] # never read out on the call
privileged:
require_all: [in_person_or_supervised_video_proofing, second_admin_approval]
notify_user_on: [recovery, new_authenticator]
Every application gets a connection tier in a register, chosen with the decision framework:
| Tier | Connection | Leaver handling | Review |
|---|---|---|---|
| A | SSO (SAML or OIDC) plus SCIM | Automatic active=false |
Monthly provisioning error report |
| B | SSO plus a vendor API script | Scripted, logged | Monthly script run evidence |
| C | SSO with JIT only | Daily account export reconciled; manual removal within SLA | Weekly |
| D | No SSO (local passwords) | Ticket to the app owner | Exception expires; quarterly attestation |
Hands-on labs
Link to section “Hands-on labs”Labs 1 and 3 run anywhere with Python 3 and were executed for this page. Lab 2 needs a test tenant and was not executed.
Lab 1 (beginner): reconcile the three ledgers
Link to section “Lab 1 (beginner): reconcile the three ledgers”Objective: find leavers, orphans, duplicate accounts, movers with leftover access, missing joiners, dormant accounts and weak MFA from an HR roster and an IdP export. Prerequisites: Python 3.8 or later; no account, cost or risk; 30 minutes.
- Save the data as
jml.jsonand the script asjml_reconcile.py. - Run
python3 jml_reconcile.py jml.json, thenecho $?. - Fix the findings in
jml.json: setenabledtofalsefor cara, dev (on long leave, confirmed by the manager) and test-admin; removefinanceanderpfrom ben’s groups and set hismfatophishing-resistant; add an account for E104 (eli@example.com, groupsall-staff,email,finance,erp,phishing-resistant, last sign-in today). Run again. - What-if: in the original file, change
nowto2026-10-16T09:00:00Zand run again. Then restore it and add a second enabled account for E100 (copy ana’s record with"upn": "ana2@example.com") and run again.
Example status: verified by execution (Python 3.8.10, 2026-10-16; re-run 2026-10-17 after the duplicate check was added); output below is verbatim.
{
"policy": {
"now": "2026-10-16T12:00:00Z",
"leaver_sla_hours": 4,
"dormant_days": 90,
"birthright": {
"all": ["all-staff", "email"],
"finance": ["finance", "erp"],
"sales": ["sales", "crm"],
"engineering": ["engineering", "git"]
}
},
"hr": [
{"id": "E100", "status": "active", "dept": "finance"},
{"id": "E101", "status": "active", "dept": "sales"},
{"id": "E102", "status": "terminated", "dept": "sales",
"end": "2026-10-16T06:00:00Z"},
{"id": "E103", "status": "active", "dept": "engineering"},
{"id": "E104", "status": "active", "dept": "finance"}
],
"idp": [
{"upn": "ana@example.com", "emp": "E100", "enabled": true,
"groups": ["all-staff", "email", "finance", "erp"],
"mfa": "phishing-resistant", "last": "2026-10-15T09:00:00Z"},
{"upn": "ben@example.com", "emp": "E101", "enabled": true,
"groups": ["all-staff", "email", "sales", "crm", "finance", "erp"],
"mfa": "otp", "last": "2026-10-16T08:00:00Z"},
{"upn": "cara@example.com", "emp": "E102", "enabled": true,
"groups": ["all-staff", "email", "sales", "crm"],
"mfa": "phishing-resistant", "last": "2026-10-16T07:30:00Z"},
{"upn": "dev@example.com", "emp": "E103", "enabled": true,
"groups": ["all-staff", "email", "engineering", "git"],
"mfa": "none", "last": "2026-06-01T10:00:00Z"},
{"upn": "test-admin@example.com", "emp": null, "enabled": true,
"groups": ["all-staff", "email"], "mfa": "none",
"last": "2026-09-30T23:10:00Z"}
]
}
"""Reconcile an HR roster with identity-provider accounts (IdentityOps Lab 1)."""
import json
import sys
from datetime import datetime
def ts(value):
return datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ")
def main(path):
with open(path) as f:
data = json.load(f)
pol = data["policy"]
now = ts(pol["now"])
hr = {w["id"]: w for w in data["hr"]}
accounts = {} # employee id -> every account that claims it
for a in data["idp"]:
if a["emp"]:
accounts.setdefault(a["emp"], []).append(a)
findings = []
for a in data["idp"]:
if a["emp"] not in hr and a["enabled"]:
findings.append("ORPHAN %s has no HR record" % a["upn"])
for emp, w in sorted(hr.items()):
owned = accounts.get(emp, [])
if w["status"] == "active" and not owned:
findings.append("JOINER %s active in HR, no account" % emp)
continue
enabled = [a for a in owned if a["enabled"]]
if len(enabled) > 1:
findings.append("DUPLICATE %s has %d enabled accounts (%s)"
% (emp, len(enabled), ", ".join(a["upn"] for a in enabled)))
for a in owned:
if w["status"] == "terminated" and a["enabled"]:
hours = (now - ts(w["end"])).total_seconds() / 3600
late = "BREACH" if hours > pol["leaver_sla_hours"] else "within SLA"
findings.append("LEAVER %s enabled %.1f h after end date (%s)"
% (a["upn"], hours, late))
if w["status"] == "active":
allowed = set(pol["birthright"]["all"] + pol["birthright"][w["dept"]])
extra = sorted(set(a["groups"]) - allowed)
if extra:
findings.append("MOVER %s (%s) keeps %s"
% (a["upn"], w["dept"], ", ".join(extra)))
humans = [a for a in data["idp"] if a["emp"] in hr and a["enabled"]
and hr[a["emp"]]["status"] == "active"]
strong = [a for a in humans if a["mfa"] == "phishing-resistant"]
for a in data["idp"]:
idle = (now - ts(a["last"])).days
if a["enabled"] and idle > pol["dormant_days"]:
findings.append("DORMANT %s last sign-in %d days ago" % (a["upn"], idle))
if a["enabled"] and a["mfa"] != "phishing-resistant":
findings.append("MFA %s uses %s" % (a["upn"], a["mfa"]))
for f in findings:
print(f)
print("Phishing-resistant coverage (active staff): %d/%d (%.1f%%)"
% (len(strong), len(humans), 100.0 * len(strong) / len(humans)))
print("Findings: %d" % len(findings))
return 1 if findings else 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1]))
Expected output (step 2), exit code 1:
ORPHAN test-admin@example.com has no HR record
MOVER ben@example.com (sales) keeps erp, finance
LEAVER cara@example.com enabled 6.0 h after end date (BREACH)
JOINER E104 active in HR, no account
MFA ben@example.com uses otp
DORMANT dev@example.com last sign-in 137 days ago
MFA dev@example.com uses none
MFA test-admin@example.com uses none
Phishing-resistant coverage (active staff): 1/3 (33.3%)
Findings: 8
Validation. Step 3 prints Phishing-resistant coverage (active staff): 3/3 (100.0%) and Findings: 0, exit code 0.
Step 4 first prints LEAVER cara@example.com enabled 3.0 h after end date (within SLA): the same gap passes or fails on time
alone, so leaver SLAs need timestamps, not daily flags. The duplicate run adds DUPLICATE E100 has 2 enabled accounts (ana@example.com, ana2@example.com) (Findings: 9): two live accounts for one person, the rehire failure in the
troubleshooting table. Troubleshooting: KeyError: 'dept' means an HR record lacks a department;
a strptime ValueError means a timestamp without the trailing Z. Teardown: delete the files. Next: run it on real
exports, handled under your data rules.
Lab 2 (intermediate): deactivate a SCIM account and revoke sessions
Link to section “Lab 2 (intermediate): deactivate a SCIM account and revoke sessions”Objective: run a leaver by hand against a test application and IdP tenant, as automation would. Prerequisites: a
SCIM 2.0 test endpoint and token; for Okta an OAuth token with the okta.users.manage scope (Okta recommends scoped OAuth tokens
over API tokens[34]); for Entra a token with User.RevokeSessions.All;[33] curl 7.76 or later for
--fail-with-body.[46] Risk: never run it against production users.
Example status: JSON and bash syntax-checked; not executed (needs a SCIM test app and an IdP test tenant). Request shapes from RFC 7644, Okta and Microsoft Graph documentation.[9][27][34][33]
deactivate.json, the body Okta sends to deactivate a user:[27]
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{"op": "replace", "value": {"active": false}}]
}
#!/usr/bin/env bash
# Leaver drill against TEST systems only.
set -euo pipefail
SCIM="https://scim.example.com/scim/v2" # placeholder SCIM base URL
: "${SCIM_TOKEN:?set a test SCIM bearer token}"
: "${OKTA_USER_ID:?set the Okta user id}" "${OKTA_ACCESS_TOKEN:?set an Okta OAuth token}"
: "${ENTRA_USER_ID:?set the Entra object id or UPN}" "${GRAPH_TOKEN:?set a Graph token}"
LEAVER="test.leaver@example.com" # SCIM userName in the test app
CURL=(curl -sS --fail-with-body) # stop on HTTP 4xx/5xx
# 1. Find the user (RFC 7644 filter; Okta sends the same query)
"${CURL[@]}" -G "$SCIM/Users" -H "Authorization: Bearer $SCIM_TOKEN" \
-H "Accept: application/scim+json" \
--data-urlencode "filter=userName eq \"$LEAVER\"" > lookup.json
PICK='import json; print(json.load(open("lookup.json"))["Resources"][0]["id"])'
ID=$(python3 -c "$PICK")
# 2. Deactivate (soft delete): PATCH active=false
"${CURL[@]}" -X PATCH "$SCIM/Users/$ID" -H "Authorization: Bearer $SCIM_TOKEN" \
-H "Content-Type: application/scim+json" --data @deactivate.json
# 3a. Okta: end IdP sessions and revoke OAuth tokens (oauthTokens defaults to false).
# Also clears remembered-device MFA state: forgetDevices defaults to true on
# Identity Engine and false on Classic Engine; pass it explicitly to be sure.
OKTA="https://example.okta.com" # placeholder org URL
"${CURL[@]}" -X DELETE \
"$OKTA/api/v1/users/$OKTA_USER_ID/sessions?oauthTokens=true&forgetDevices=true" \
-H "Authorization: Bearer $OKTA_ACCESS_TOKEN"
# 3b. Entra: invalidate refresh tokens and session cookies
GRAPH="https://graph.microsoft.com/v1.0"
"${CURL[@]}" -X POST "$GRAPH/users/$ENTRA_USER_ID/revokeSignInSessions" \
-H "Authorization: Bearer $GRAPH_TOKEN" -H "Content-Type: application/json" -d ''
Expected output: step 1 returns a ListResponse with one resource; step 2 HTTP 200 with the user showing "active": false,
or 204 with no body;[9] step 3a HTTP 204 with no body, and the user’s remembered devices are forgotten as a side
effect;[34] step 3b a 2xx response.[33] Any 4xx or 5xx
stops the script and prints the error body. Validation: the user cannot sign in to the test app and an old refresh
token fails; issued access tokens stay valid until they expire.[31] Troubleshooting: an empty Resources
array means the app matches on another attribute; HTTP 403 means a missing scope or role. Teardown: reactivate with
"active": true or delete the test user.
Lab 3 (advanced): audit machine identities from a credential report
Link to section “Lab 3 (advanced): audit machine identities from a credential report”Objective: find unowned, unused, idle and unrotated access keys and human IAM users, using the real credential-report columns.[39] Prerequisites: Python 3.8 or later; 45 minutes; step 5 needs IAM read access to a non-production account.
- Save
make_report.py,nhi_audit.pyand the owner registerowners.json. - Run
python3 make_report.py > credential_report.csvto create the synthetic report. - Run
python3 nhi_audit.py credential_report.csv owners.json. - Remediate in the data: delete the
report-export,jane.adminandold-etlrows fromUSERS(after their owners confirm), and changelegacy-backupto a new key created and used on2026-10-16. Run steps 2 and 3 again. - Optional, real account (not executed here):
aws iam generate-credential-report, thenaws iam get-credential-report --query Content --output text | base64 --decode > credential_report.csv. TheContentfield is Base64-encoded;[47] reports can be generated at most once every four hours.[39] A real report also has a row for the account root user, which the script flags NO-OWNER: check it separately for MFA and no access keys.[48]
Example status: steps 1–4 verified by execution (Python 3.8.10, 2026-10-16, re-run 2026-10-17), output verbatim; step 5 not executed.
"""Write a synthetic AWS IAM credential report (real column names, fake users)."""
import csv
import sys
COLUMNS = [
"user", "arn", "user_creation_time", "password_enabled", "password_last_used",
"password_last_changed", "password_next_rotation", "mfa_active",
"access_key_1_active", "access_key_1_last_rotated", "access_key_1_last_used_date",
"access_key_1_last_used_region", "access_key_1_last_used_service",
"access_key_2_active", "access_key_2_last_rotated", "access_key_2_last_used_date",
"access_key_2_last_used_region", "access_key_2_last_used_service",
"cert_1_active", "cert_1_last_rotated", "cert_2_active", "cert_2_last_rotated",
]
T = "T00:00:00+00:00"
USERS = [ # user, password, mfa, key 1 created, key 1 last used
("ci-deploy", "false", "false", "2026-09-01", "2026-10-15"),
("legacy-backup", "false", "false", "2024-03-10", "2026-10-14"),
("report-export", "false", "false", "2025-11-20", None),
("jane.admin", "true", "false", "2026-08-01", "2026-10-12"),
("old-etl", "false", "false", "2025-01-05", "2025-06-30"),
]
out = csv.DictWriter(sys.stdout, fieldnames=COLUMNS, lineterminator="\n")
out.writeheader()
for user, pwd, mfa, created, used in USERS:
row = {c: "N/A" for c in COLUMNS}
row.update({
"user": user, "arn": "arn:aws:iam::111122223333:user/" + user,
"user_creation_time": created + T, "password_enabled": pwd,
"mfa_active": mfa, "access_key_1_active": "true",
"access_key_1_last_rotated": created + T,
"access_key_1_last_used_date": used + T if used else "N/A",
"access_key_2_active": "false", "cert_1_active": "false",
"cert_2_active": "false",
})
out.writerow(row)
{
"as_of": "2026-10-16",
"max_key_age_days": 90,
"max_idle_days": 90,
"owners": {
"ci-deploy": "platform-team",
"legacy-backup": "storage-team",
"old-etl": "data-team"
}
}
"""Audit IAM users and access keys from an AWS credential report (IdentityOps Lab 3)."""
import csv
import json
import sys
from datetime import datetime, timezone
EMPTY = ("N/A", "no_information", "not_supported", "")
def days_since(value, now):
if value in EMPTY:
return None
return (now - datetime.fromisoformat(value)).days
def main(report_path, register_path):
with open(register_path) as f:
reg = json.load(f)
now = datetime.strptime(reg["as_of"], "%Y-%m-%d").replace(tzinfo=timezone.utc)
with open(report_path, newline="") as f:
rows = list(csv.DictReader(f))
findings, owned, ok, keys = [], 0, 0, 0
for r in rows:
user = r["user"]
if user in reg["owners"]:
owned += 1
else:
findings.append("NO-OWNER %s: no owner registered" % user)
if r["password_enabled"].lower() == "true":
mfa = "on" if r["mfa_active"].lower() == "true" else "OFF"
findings.append("HUMAN %s: console password, MFA %s; federate"
% (user, mfa))
for k in ("1", "2"):
if r["access_key_%s_active" % k].lower() != "true":
continue
keys += 1
age = days_since(r["access_key_%s_last_rotated" % k], now)
idle = days_since(r["access_key_%s_last_used_date" % k], now)
key = "%s key %s" % (user, k)
if idle is None:
findings.append("UNUSED %s: never used, %d days old" % (key, age))
elif idle > reg["max_idle_days"]:
findings.append("IDLE %s: last used %d days ago" % (key, idle))
elif age > reg["max_key_age_days"]:
findings.append("ROTATE %s: %d days old, in use" % (key, age))
else:
ok += 1
for line in findings:
print(line)
print("Owner coverage: %d/%d users" % (owned, len(rows)))
print("Active keys within policy: %d/%d" % (ok, keys))
print("Findings: %d" % len(findings))
return 1 if findings else 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1], sys.argv[2]))
Expected output (step 3), exit code 1:
ROTATE legacy-backup key 1: 950 days old, in use
NO-OWNER report-export: no owner registered
UNUSED report-export key 1: never used, 330 days old
NO-OWNER jane.admin: no owner registered
HUMAN jane.admin: console password, MFA OFF; federate
IDLE old-etl key 1: last used 473 days ago
Owner coverage: 3/5 users
Active keys within policy: 2/5
Findings: 6
Validation. Step 4 prints Owner coverage: 2/2 users, Active keys within policy: 2/2 and Findings: 0. Lesson:
jane.admin is a person on an IAM user; AWS wants humans to “use federation with an identity provider”,[41] so the fix is
federation, not rotation. Troubleshooting: a fromisoformat ValueError means a Z suffix (Python 3.8 needs +00:00).
Teardown: delete the files; treat a real report as sensitive data.
Use cases and scenarios
Link to section “Use cases and scenarios”Four sourced incidents, each a different gap. Facts are the organisations’ or responders’ own accounts; lessons are this page’s.
Case 1: a legacy test tenant and an OAuth app (sourced)
Link to section “Case 1: a legacy test tenant and an OAuth app (sourced)”From late November 2023, Midnight Blizzard “used a password spray attack to compromise a legacy non-production test tenant account”,[49] which “did not have multifactor authentication (MFA) enabled”. The actor then used “a legacy test OAuth application that had elevated access to the Microsoft corporate environment” and created more OAuth applications to reach mailboxes.[50] Gap: a test account outside MFA policy and a legacy test app that still had elevated access. Practice: inventory every tenant and app registration; MFA for every interactive account. Success measure: zero interactive accounts without MFA; zero privileged app registrations without an owner.
Case 2: a service account, session tokens and credentials nobody rotated (sourced)
Link to section “Case 2: a service account, session tokens and credentials nobody rotated (sourced)”Okta found that from 28 September to 17 October 2023 an attacker used “a service account stored in the system itself”, whose credentials “had been saved into the employee’s personal Google account”; session tokens in support files let the attacker hijack five customers’ sessions.[51] Cloudflare, one of them, reported that “we failed to rotate one service token and three service accounts (out of thousands)” because “mistakenly it was believed they were unused”.[52] Gap: machine-identity use assumed, not measured. Practice: prove rotation item by item against the inventory, with last-used evidence; treat session tokens as credentials. Success measure: rotated ÷ exposed = 100%, checked by a second person.
Case 3: SaaS accounts signing in with passwords only (sourced)
Link to section “Case 3: SaaS accounts signing in with passwords only (sourced)”Mandiant’s 2024 investigation of UNC5537, which targeted Snowflake customer instances, found accounts “not configured with multi-factor authentication”, infostealer-harvested credentials that “had not been rotated for as long as four years”, and no network allow lists; about 165 potentially exposed organisations were notified.[53] Gap (this page’s reading): app accounts protected by a password alone, outside any IdP’s MFA policy. Practice: tier every SaaS app (reference implementation); enforce SSO and MFA; reconcile local accounts. Success measure: critical apps at Tier A or B; local accounts without MFA = 0.
Case 4: the help desk as the bypass (sourced)
Link to section “Case 4: the help desk as the bypass (sourced)”CISA’s Scattered Spider advisory (revised 29 July 2025) describes help-desk password and MFA resets, push bombing, SIM swapping, self-registered MFA tokens and, historically, a federated IdP added to the victim’s SSO tenant.[37] In May 2025 the UK NCSC asked organisations to “review helpdesk password reset processes”.[54] Gap: recovery weaker than authentication. Practice: tiered recovery and alerts on post-reset MFA and federation changes. Success measure: every sampled reset followed the script.
Measure, govern, pay
Link to section “Measure, govern, pay”Metrics and KPIs
Link to section “Metrics and KPIs”MojoAuth suggests “time to provision and deprovision, orphaned accounts found per review, and the rate of account-recovery requests”;[1] the set below makes them precise.
| KPI | Definition / formula | Pitfall | Review |
|---|---|---|---|
| Leaver compliance (end to end) | Leavers disabled in the IdP and deactivated in every connected app within SLA ÷ leavers | Measuring only the IdP | Monthly |
| Time to disable and deprovision (p50, p95) | IdP disable time, and last app deactivation time, − HR effective time | Late HR entry looks like an identity delay (track HR lag apart); provisioning cycles add lag per app | Monthly |
| Orphan rate | Enabled accounts with no authoritative source or owner ÷ enabled accounts | Disabled orphans counted as solved | Weekly |
| Phishing-resistant coverage | Active people with a phishing-resistant authenticator ÷ active people | Counting “MFA enabled”, SMS included | Monthly |
| Phishing-resistant usage | Holders’ interactive sign-ins using such a method ÷ holders’ interactive sign-ins | Mixing in non-holders hides weak fallbacks | Monthly |
| Automated deprovisioning coverage | User–app assignments on Tier A or B apps ÷ all user–app assignments (sum over apps of their user counts) | A per-app count hides one large local-account app | Quarterly |
| Joiner day-one readiness | Joiners working with birthright access at start ÷ joiners | Counting account creation only | Monthly |
| Verified recovery rate | Sampled assisted resets that followed the script ÷ sampled resets | Sampling easy cases | Weekly |
| NHI credential compliance | Machine credentials owned and within age and idle limits ÷ machine credentials | Inventory gaps flatter the ratio | Monthly |
Worked calculation (illustrative scenario). HR records 40 leavers in a month. The IdP disabled 36 within the 4-hour SLA; HR entered the other four two days late. Three of the 36 still had a Tier C account after 24 hours.
- IdP-only compliance = 36 ÷ 40 = 90.0%; end to end = (36 − 3) ÷ 40 = 82.5%. The gap has two owners: HR entry lag (PeopleOps) and Tier C reconciliation (IdentityOps).
- Of 1,400 staff, 1,190 have a FIDO2 key or passkey: coverage = 85.0%. Of those 1,190 holders’ 62,000 interactive sign-ins, 41,000 used one: usage = 66.1%. A third of holders’ sign-ins still use weaker methods, so policy still accepts them from people who own a strong one: require a phishing-resistant method by policy.
Targets: set from the baseline, then tighten. Coverage and Tier A share lead; leaver compliance and identity incidents lag.
Security, privacy and compliance
Link to section “Security, privacy and compliance”| Risk | Signal | Mitigation | Owner |
|---|---|---|---|
| Password spray, credential stuffing | Detections such as “Password spray” and “Leaked credentials”[44] | Phishing-resistant MFA; blocklist; no local passwords | Identity, SOC |
| MFA prompt bombing (T1621)[55] | Many push prompts for one user | Number matching, prompt limits, phishing-resistant methods | Identity |
| Help-desk social engineering | New MFA method soon after an assisted reset | Tiered recovery; notification; alert | Service desk, SOC |
| Token theft and replay | Detections such as “Anomalous token”[44] | Short sessions; revocation; signing-key protection[13] | Identity |
| Rogue federation trust (T1484.002)[56] or authentication-policy change (T1556)[57] | IdP change outside change control | Few admins; change alerts; trust review | Identity |
| Orphaned machine identity | Credential with no owner or recent use | Register, expiry, decommissioning | Owners |
Privacy. Identity records are personal data. Send applications only the attributes they need, restrict HR-sourced attributes, and set retention for disabled accounts and sign-in logs with PrivacyOps. Rules vary by jurisdiction; this page gives no legal advice.
Compliance. Auditors usually ask for leavers with a timestamp per system, reconciliation results and MFA coverage, against controls such as NIST AC-2.[20] Mapping evidence to ISO/IEC 27001, SOC 2 and other frameworks belongs to ComplianceOps.
Cost, capacity and sustainability
Link to section “Cost, capacity and sustainability”- Licence tiers drive design. Entra HR-driven provisioning needs P1 or P2 plus the HR application’s licence;[21] lifecycle workflows need Entra ID Governance or Entra Suite;[25] even the last-sign-in property for dormant checks needs P1 or P2,[36] and the inactive-guest report needs ID Governance or Entra Suite.[58] SaaS vendors often put SCIM in higher plans (Docker’s guide is marked Business).[59] Price the Tier A target, not just the IdP.
- Labour. Tier C and D apps and assisted recoveries are recurring manual work. Measure both.
- Hardware. Two security keys per administrator (one spare), plus replacement.
- Resilience. Every sign-in depends on the IdP: see the FAQ on outages.
- Sustainability is not material here beyond hardware lifecycle.
Assurance of the operating model
Link to section “Assurance of the operating model”- Independent reconciliation reads application data, not the provisioning log.
- Control tests: the quarterly leaver drill (a test identity in Tier A–D apps); sign in with a disabled test account; replay an old refresh token; an authorised social-engineering test of the help-desk script.
- Decay signals: provisioning errors or quarantined jobs, growth of Tier C and D, a spike in recovery requests, expired exceptions still open, and NHIs without owners.
When things go wrong
Link to section “When things go wrong”Common failures and troubleshooting
Link to section “Common failures and troubleshooting”| Symptom | Likely cause | Diagnosis | Remediation | Prevention |
|---|---|---|---|---|
| Leaver still active in an app | Tier C or D app; provisioning job failing or quarantined[28] | Job status; app export | Deactivate by hand; fix connector | Alert on quarantine; daily reconciliation |
| Disabled user still reads mail or files | Sessions and tokens issued before disablement | Logs after the disable time | Revoke sessions and refresh tokens | Revocation as a leaver step; continuous access evaluation where supported[60] |
| Duplicate identity after rehire | New employee ID; matching rule misses | Compare HR and directory IDs (Lab 1 prints DUPLICATE) |
Merge or disable the duplicate | Written rehire policy[21] |
| Mover keeps old access | Rules only add groups | Group difference against birthright | Remove extra groups | Recalculate on every change (Lab 1) |
| Hundreds of accounts disabled at once | HR feed error or changed scoping filter | Spike in disable events | Pause the job; restore from the audit log | Bulk-change threshold needing approval |
| An app’s SSO fails one morning | Expired SAML signing certificate | App error; certificate dates | Update certificate and metadata | Certificate expiry calendar |
Worked runbook: a fraudulent MFA reset
Link to section “Worked runbook: a fraudulent MFA reset”Illustrative scenario. At 10:05 the SOC sees a new authenticator registered for a finance manager, 20 minutes after a phoned-in MFA reset, then a sign-in from an unfamiliar device: the pattern CISA describes for Scattered Spider.[37]
Diagram source (Mermaid)
flowchart TB
A["Alert: new MFA method after a reset"] --> B{"User confirms via known channel?"}
B -->|"yes, it was them"| Z["Close; record and review the script"]
B -->|"no or unreachable"| C["Contain: block sign-in, revoke sessions, remove new methods"]
C --> D["Scope: sign-ins, consents, inbox rules, roles, federation"]
D --> E["Eradicate: remove rogue apps, rules, trusts; rotate exposed secrets"]
E --> F["Recover: re-proof the user, issue new authenticators"]
F --> G["Learn: fix recovery script and detections"]
classDef risk fill:#fbeceb,stroke:#b4332b,color:#122029
classDef decision fill:#fdf3e3,stroke:#c9800f,color:#122029
classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
class A,C risk
class B decision
class D,E,F,G,Z core
Text equivalent: an alert of a new MFA method after a reset leads to one question: does the user confirm it through a known channel? If yes, close and review the script. If not, contain, scope, eradicate, recover and learn, in that order.
- Verify (0–10 min). Reach the user through the manager or a device registered before the reset, not the number on the ticket; a call to the HR number alone may ring a SIM-swapped phone.
- Contain (10–20 min). Block sign-in; revoke sessions and refresh tokens (Graph
revokeSignInSessions[33] or OktaDELETE /api/v1/users/{userId}/sessions?oauthTokens=true&forgetDevices=true, which also clears remembered devices, a default on Identity Engine but not on Classic Engine[34]); remove the attacker’s authenticator; end app sessions that outlive the IdP’s (exception paths). - Scope (20–90 min). Sign-ins since the reset; new OAuth consents and app registrations (Midnight Blizzard kept access through OAuth apps[50]); inbox rules[44]; role assignments; federation and authentication-policy changes.
- Eradicate. Remove rogue consents, apps, rules and trusts; ask owners to rotate secrets she could reach.
- Recover. Re-proof her through the privileged path, issue new authenticators and confirm the recovery notifications NIST requires.[15]
- Learn (within 5 days). Compare the ticket with the script, fix the failed step, and send the alert to DetectionOps. Incident coordination follows IncidentOps; adversary-facing work (evidence, forensics, notification) belongs to ResponseOps.
Done when no session issued after the reset survives, no rogue method or consent remains, and the script fix is live.
Anti-patterns and myths
Link to section “Anti-patterns and myths”- “Disabled in the directory means offboarded.” Sessions, local app accounts and machine credentials survive. Measure end to end.
- “MFA is 100%.” If SMS and push count, phishable sign-ins hide in the number. Report phishing-resistant coverage and usage.
- Forced password expiry. NIST says verifiers “SHALL NOT require subscribers to change passwords periodically”;[15] CISA’s advisory agrees.[37] Change on evidence of compromise.
- JIT as the provisioning strategy. It never removes accounts; Docker, for example, recommends “SCIM with JIT turned off”.[59]
- The help desk as the default recovery path. It makes social engineering a supported feature.
- People sharing service accounts. OWASP lists “Human Use of NHI” as a top risk;[38] it also destroys attribution.
- Myth: SSO concentrates risk, so avoid it. It concentrates control too: one place to enforce MFA, revoke and log. Treat the IdP as tier-0 instead of scattering passwords.
Deciding and adopting
Link to section “Deciding and adopting”When to use IdentityOps and when not to
Link to section “When to use IdentityOps and when not to”Name and staff it when you have dozens of SaaS apps, contractors or guests without HR records, a hybrid directory, auditors asking for leaver evidence, machine identities growing faster than people, or a recent identity incident.
Do not build a separate practice in a small organisation (a few dozen people, a handful of apps): one administrator with the IdP’s built-in features, SSO wherever possible, security keys for administrators and a monthly reconciliation are enough. Do not buy an IGA suite before HR data is clean and the application register exists: rules on bad attributes automate bad decisions.
Hidden responsibilities: an IdP on-call with change control; a service desk with a script and authority to refuse callers; app owners who accept SLAs for what cannot be automated.
Decision framework: connecting an application
Link to section “Decision framework: connecting an application”Diagram source (Mermaid)
flowchart TB
A{"SAML or OIDC?"} -->|"no"| D["Replace, block or Tier D exception"]
A -->|"yes"| C{"SCIM on our plan?"}
C -->|"yes"| TA["Tier A: SSO + SCIM"]
C -->|"no"| E{"Deactivation API?"}
E -->|"yes"| TB["Tier B: SSO + script"]
E -->|"no"| TC["Tier C: daily reconciliation"]
classDef decision fill:#fdf3e3,stroke:#c9800f,color:#122029
classDef core fill:#e8f3f2,stroke:#16756f,color:#122029
classDef risk fill:#fbeceb,stroke:#b4332b,color:#122029
class A,C,E decision
class TA,TB,TC core
class D risk
Text equivalent: without SAML or OIDC, replace or block the app, or record a Tier D exception with an expiry. With SSO and SCIM on your plan, use Tier A. Without SCIM but with a user-deactivation API, use Tier B. Otherwise use Tier C with daily reconciliation; if the app holds sensitive data or many users, negotiate SCIM with the vendor meanwhile.
IdP-native lifecycle or an IGA suite? Ask four questions: several authoritative sources? complex birthright rules? many non-SCIM or on-premises targets? heavy audit reporting? Two or more “yes” answers usually justify a dedicated platform and its running cost.
Maturity model
Link to section “Maturity model”This model is this Atlas’s proposal, calibrated against CISA’s Zero Trust Maturity Model, whose identity pillar runs from Traditional (the agency “manually orchestrates (onboards, offboards, and disables)” identities) to Optimal (“continuously validates identity with phishing-resistant MFA”).[42] Thresholds are suggestions.
| Level | Observable behaviour | Exit criteria to the next level |
|---|---|---|
| 0 Ad hoc | Accounts by email and ticket; local passwords; no reconciliation | Sources named; application register exists |
| 1 Centralised | One IdP; SSO for major apps; any MFA; JML by ticket | HR feed live; leaver SLA measured |
| 2 Automated | HR-driven JML; SCIM for top apps; daily reconciliation; NHI inventory | Leaver compliance ≥ 90%; orphan rate tracked |
| 3 Governed | Phishing-resistant admins and most staff; tiered recovery; owned NHIs; IdP change control; drills | Phishing-resistant usage ≥ 80%; all NHIs owned |
| 4 Continuous | Session events shared (CAEP) where supported; risk-driven re-authentication; short-lived machine credentials | Sustained ≥ 95% leaver compliance |
Levels 0–1 resemble CISA’s Traditional stage, 2 Initial, 3 Advanced and 4 Optimal; the mapping is approximate.
Adoption roadmap: 30/60/90 days
Link to section “Adoption roadmap: 30/60/90 days”| Window | Actions | Milestone and metric |
|---|---|---|
| Days 1–30 | Name owners; build the tiered application register; run Lab 1 on real exports; security keys for administrators; recovery script | Baseline KPIs |
| Days 31–60 | HR-driven provisioning for one population; SCIM for the ten largest apps; daily reconciliation; NHI inventory (Lab 3) | First automated leavers; owned exception list |
| Days 61–90 | Session revocation for leavers; first drill; alerts on post-reset MFA and federation changes; Tier D expiry dates | Drill evidence; leaver compliance rising |
Dependencies: clean HR dates (PeopleOps), app owners’ time, licences, SOC capacity. Quick wins: delete orphans; security keys for IdP administrators; remove SMS where a stronger method exists.
Toolkit
Link to section “Toolkit”Checklists
Link to section “Checklists”Quick start
- Authoritative source named for employees, contractors, guests and machines
- Application register with a tier and owner per app
- Leaver SLA measured from the HR effective time
- Security keys for every IdP and cloud administrator
- Recovery script approved by security and the service desk
- New hires proofed against identity documents (live video for remote hires) before a bootstrap pass is issued
Application onboarding preflight
- SSO tested; local password sign-in disabled where possible
- Deactivation enabled (Okta “Deactivate Users”; Entra update action and
activemapping) and tested with a test user: whatactive=falsemeans in this app, whether it deletes, and how long the push takes - Only needed attributes mapped; session lifetime and revocation documented
- Provisioning token registered as an NHI with owner and expiry
Quarterly review
- Leaver drill across Tier A–D apps, timestamps recorded
- No provisioning job in error or quarantine
- Admin roles, federation trusts and signing-certificate expiry dates reviewed
- Alerts firing for new admins, new trusts and authentication-policy changes
- Legal-hold path tested (disable without delete)
Templates
Link to section “Templates”1. Application connection record
APPLICATION CONNECTION RECORD v1 (owner signs)
Application / vendor: ______________ Business owner: ________
Data classification: public | internal | confidential | restricted
Users (now / in 12 months): ____ / ____
SSO protocol: SAML | OIDC | none (=> Tier D exception)
Provisioning: SCIM | API script | JIT only | manual
Tier: A | B | C | D Exception expiry: ______
Meaning of deactivate here: blocks sign-in | frees licence | deletes data
App session lifetime / revoke: ______ / how: ____________________________
Attributes sent: ____________________ (minimum needed only)
Provisioning credential: NHI id ______ owner ______ expiry ______
Leaver SLA accepted by owner: yes / no Next review: ______________
2. Assisted recovery script (service desk)
ASSISTED MFA / PASSWORD RECOVERY v2
1. Never act on the number, email or chat the caller gives you.
2. Look up the person in HR. A call-back to the HR number is NOT proof
on its own: numbers can be SIM-swapped or ported.
3. The manager (or sponsor) confirms the person on a live video call or
in person, reached through a known channel.
4. Privileged or finance role? STOP. Route to in-person or supervised
video proofing AND approval by a second administrator.
5. Issue a ONE-TIME bootstrap pass valid <= 1 hour. Deliver it via the
manager or to a device registered before the request; never read
it out on the call. Never set a password or register an
authenticator on the user's behalf.
6. Record: ticket, verification steps, approver, delivery channel, time.
7. Tell the caller the user will be notified of the reset.
8. Pressure, urgency or "the CEO needs this now" = escalate to security.
3. Non-human identity registration
Example status: YAML syntax-checked by the Atlas validator; field names are this Atlas’s suggestion.
nhi_id: nhi-0427
kind: oauth-client # service-account | api-key | oauth-client | certificate
system: idp-prod
purpose: "Nightly export of invoices to the data warehouse"
owner: team-finance-data # a team, plus a named individual below
owner_person: a.rossi@example.com
environment: production # never shared with test
cadence: nightly # expected use; the dormant sweep compares against it
credential:
type: client-secret
max_age_days: 90
last_rotated: 2026-09-30
permissions_ref: iamops-review-2026-q3 # design and review live in IAMOps
expires: 2027-03-31 # re-register or decommission by this date
decommission:
disable_first: true
observe_days: 14
Deep comparisons
Link to section “Deep comparisons”Provisioning methods
| Method | Creates | Updates | Removes | Main risk |
|---|---|---|---|---|
| HR-driven into the directory | Yes | Yes | Yes | Dirty HR data spreads everywhere |
| SCIM 2.0 to apps | Yes | Yes | Deactivates (active=false) |
Connector token theft; quarantined jobs |
| Vendor API script | Yes | Partly | If written | Script rot when the API changes |
| JIT at first SSO login | Yes | At sign-in, if supported | No | Accounts outlive leavers; reconciliation needed |
| Manual ticket | Yes | Slowly | Slowly | Delay and forgotten steps |
Is IdentityOps just IAM with a new name? Largely, for the operational half of IAM; the label stresses running the lifecycle as a measured production service.
Do we need an IGA product? Not to start; ask the four questions in the decision framework.
Disable or delete a leaver? Disable at once, delete later, and first learn what each app does on “disable”: some connectors delete (legal hold). Keep the account disabled for the retention period, longer under legal hold.
Contractors have no HR record. What is their source? A sponsor register: a named employee sponsors each contractor, with an end date that disables the account unless renewed. Guest (B2B) accounts need the same rule; Microsoft’s inactive-guest report (an Entra ID Governance or Entra Suite feature) defaults to 90 days without sign-in.[58]
What if the IdP is down? Existing sessions last until they expire; new sign-ins fail. Microsoft advises “two or more emergency access accounts”, cloud-only and not federated;[35] practise with them. The procedure belongs to AccessOps.
Going further
Link to section “Going further”Advanced topics and emerging direction
Link to section “Advanced topics and emerging direction”- Shared signals (final 2025, early adoption). CAEP events such as
session-revokedandcredential-changelet an IdP tell applications to cut a session it has revoked:[17] the standard answer to sessions outliving accounts. Check each app’s support first. - Token and signing-key protection (new guidance). NIST IR 8587 (September 2026) covers protecting tokens and assertions “from forgery, theft, and misuse”, including key management, token verification and life-cycle controls.[13]
- Passkeys at workforce scale (maturing). Recovery and device turnover are the open operational questions.
- AI agents as identities (unsettled). No standard defines their lifecycle yet; treat each as an NHI with an owner, purpose, expiry and short-lived credential.
Learning path
Link to section “Learning path”| Stage | Do this |
|---|---|
| Prerequisites | HTTP, cookies and TLS basics; what a token is |
| 1 day | Read the authenticator, phishing-resistance and recovery sections of SP 800-63B-4;[15] run Lab 1 |
| 1 week | In a test tenant, connect one SSO app and one SCIM app; run Lab 2 |
| 30 days | Run Lab 3 on a non-production cloud account; build the application register; run one leaver drill |
| Specialisation | Federation and key security, IGA design, shared signals, identity proofing |
| Portfolio | A reconciliation tool; an NHI register; a recovery script with a tabletop record |
The IDPro Body of Knowledge is a vendor-neutral reading list for the wider IAM field.[5]
Wrap-up
Link to section “Wrap-up”Executive recap and cheat sheet
Link to section “Executive recap and cheat sheet”| Topic | Remember |
|---|---|
| Definition | Running who exists and how they prove it |
| Decisions | Authoritative source per identity type; app tiers; recovery tiers; IdP-native or IGA suite |
| Practices | HR-driven JML; SCIM plus session revocation; daily reconciliation; NHI register; IdP change control |
| Metrics | End-to-end leaver compliance; time to disable; orphan rate; phishing-resistant coverage and usage; verified recovery rate |
| Watch-outs | Sessions outlive accounts; JIT never removes; help-desk resets; machine credentials believed unused |
| Next action | Run Lab 1 on real exports this week; enrol IdP administrators on security keys |
A judgement call: who may reset MFA?
Link to section “A judgement call: who may reset MFA?”Learning objectives and mastery check
Link to section “Learning objectives and mastery check”After this page you can explain the three-ledger model and the identity trio; design a leaver flow that ends sessions; choose connection and recovery tiers; evaluate an estate with the KPIs and the maturity model.
- HR marks a leaver at 09:00; the IdP account is disabled at 09:20; at 11:00 the leaver is still editing a document in a SaaS app connected by SCIM. Give two likely reasons.
Show answer for question 1
Not the access token: one issued before 09:20 had expired by 10:50 at the latest (Entra’s default is 60–90 minutes;[32]
services that support CAE cut their longer tokens on disable[60]). Likely: the app’s own session survives, and active=false, whose meaning each
app defines,[8] may only block new sign-ins; or the deactivation never arrived (a failing or quarantined job,[28] or
Okta’s “Deactivate Users” left off[27]). Entra’s 40-minute cycle explains a short delay, not 100 minutes.[29]
Revoke app sessions as a leaver step and measure end to end.
- Your dashboard shows “MFA enabled: 100%”. Why is that not evidence of strong authentication?
Show answer for question 2
It counts phishable methods; NIST does not treat typed codes (OTP, SMS) as phishing-resistant.[15] Report phishing-resistant coverage, and usage among holders: below 100% means weak fallbacks are still accepted from people who own a strong method.
- After a supplier breach your team rotated “all” exposed credentials, yet one was used weeks later. What was missing?
Show answer for question 3
An inventory with last-used evidence to prove completeness against; Cloudflare’s missed credentials were “believed they were unused”.[52] Measure rotated ÷ exposed, item by item.
- A SaaS app holding customer contracts offers SAML with JIT, no SCIM on your plan and no user API. Which tier, and what interim control?
Show answer for question 4
Tier C: JIT never removes accounts, so reconcile the app’s user export daily and remove leavers within the SLA. Because the data is sensitive, negotiate SCIM with a deadline (decision framework).
- Design challenge: name three alerts that catch help-desk recovery abuse.
Show answer for question 5
Conclusion
Link to section “Conclusion”IdentityOps is a new name for old, unglamorous work, and the work matters more than the name. Its core is simple to state and hard to sustain: three ledgers that agree every day; a sign-in method a fake website cannot steal; a recovery path a confident caller cannot talk through; machine identities that end when their purpose ends. None of the incidents on this page defeated cryptography: a test account had no MFA, a service account was believed unused, a password was four years old, a help desk was persuaded. If you can show, with timestamps, that leavers are out everywhere, that sign-in resists phishing and that every machine identity has an owner, you are doing IdentityOps, whatever your teams are called.
Sources and further reading
Link to section “Sources and further reading”Claim-by-claim evidence: research/identityops-ledger.md. Product documentation changes often: the identity team should re-check
the product facts on this page (cycle intervals, token defaults, licence tiers, API versions) at its quarterly IdP configuration
review, and before relying on any of them.
Further reading: Passkeys (FIDO Alliance); Microsoft Entra ID Governance overview.
Changelog: 2026-10-16 — first version: research, ledger, draft, six diagrams; Labs 1 and 3 executed on synthetic data, Lab 2
syntax-checked only; no independent fact-check review yet. 2026-10-17 — revised after independent review r1: recovery no longer
trusts phone call-backs (SIM swap); Entra deletion behaviour corrected; proofing before bootstrap; provisioning preconditions and
latency; ATT&CK, CSF and case wording; Lab 2 hardened; figures 2–4 corrected; repetition cut; 11 sources added, 1 removed. 2026-10-17 — revised after independent review r2 (12 minor
findings): access-token lifetime stated as 60–90 minutes with Microsoft’s token-lifetime page added; IR 8587 authorship; shared-signals
dating; quarantine mechanism; Okta forgetDevices side effect in Lab 2 and the runbook; Lab 1 detects duplicate accounts (re-executed);
policy YAML schema; deprovisioning-coverage formula; dormant-sweep exclusions and NHI cadence; guest-report licence; figure 4 note;
ephemeral term-status sources archived. 2026-10-17, post-score polish: AAL1 glossary wording (“at least one factor”); the
PSTN risk-indicator rule labelled as applied by analogy; Entra’s unassign-then-push path for urgent leavers with its caveats;
re-check cadence for product facts; figure 1 edges carry handoff labels; figure 3 reconciliation inputs named in the node instead of on curved
edges; NIST and Entra sources re-opened. 2026-10-17, after the polish check: the urgent-leaver path labelled as this page’s
reading, with its trade-off and two preconditions.
Identity Operations: What It Means — MojoAuth glossary, updated 2026-09-28. Checked 2026-10-16. ↩︎ ↩︎
What Is Identity Operations? — NHI Mgmt Group glossary, updated 2026-06-07. Checked 2026-10-16. ↩︎
What is IdentityOps? — Opsio, 2025-08-25 (updated 2025-10-13), as seen 2026-10-16; archived copy of 2026-10-17. Checked 2026-10-16. ↩︎
Security Operations Engineer (Identity Operations team) — Microsoft job posting via AnitaB.org, undated (“Posted 6+ months ago”), as seen 2026-10-16; archived copy of 2026-10-17. Checked 2026-10-16. ↩︎
IDPro Body of Knowledge — IDPro. Checked 2026-10-16. ↩︎ ↩︎
Valid Accounts, T1078 — MITRE ATT&CK, modified 2026-05-12. Checked 2026-10-16. ↩︎ ↩︎
SAML V2.0 Technical Overview — OASIS, 2008-03-25 (cites the March 2005 core specification). Checked 2026-10-16. ↩︎ ↩︎
RFC 7643, SCIM: Core Schema — IETF, September 2015. Checked 2026-10-16. ↩︎ ↩︎ ↩︎
RFC 7644, SCIM: Protocol — IETF, September 2015. Checked 2026-10-16. ↩︎ ↩︎ ↩︎ ↩︎
Implementing Phishing-Resistant MFA — CISA fact sheet, October 2022. Checked 2026-10-16. ↩︎ ↩︎ ↩︎
SP 800-63-4, Digital Identity Guidelines — NIST, 2025-07-31. Checked 2026-10-16. ↩︎ ↩︎
Three Shared Signals Final Specifications Approved — OpenID Foundation, 2025-09-02. Checked 2026-10-16. ↩︎ ↩︎
NIST IR 8587, Protecting Tokens and Assertions from Forgery, Theft, and Misuse — NIST Internal Report (authors from NIST, Accenture Federal Services and CISA), 2026-09-15. Checked 2026-10-16, authorship re-checked 2026-10-17. ↩︎ ↩︎ ↩︎ ↩︎
OpenID Connect Core 1.0 incorporating errata set 2 — OpenID Foundation, 2023-12-15. Checked 2026-10-16. ↩︎ ↩︎
SP 800-63B-4, Authentication and Authenticator Management — NIST, 2025. Checked 2026-10-16, re-checked 2026-10-17. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
Microsoft Entra Connect: Prerequisites and hardware — Microsoft Learn, 2026-01-16. Checked 2026-10-17. ↩︎ ↩︎
OpenID Continuous Access Evaluation Profile 1.0 — OpenID Foundation, 2025-08-29. Checked 2026-10-16. ↩︎ ↩︎
OpenID RISC Profile Specification 1.0 — OpenID Foundation, 2025-08-29. Checked 2026-10-17. ↩︎
The NIST Cybersecurity Framework (CSF) 2.0 — NIST CSWP 29, 2024-02-26. Checked 2026-10-16. ↩︎ ↩︎
SP 800-53 Rev. 5 (Release 5.2.0), control AC-2 — NIST, release 5.2.0 of 2025-08-27; control text read in the OSCAL catalog. Checked 2026-10-16. ↩︎ ↩︎ ↩︎ ↩︎
Plan cloud HR application to Microsoft Entra user provisioning — Microsoft Learn, 2025-07-24. Checked 2026-10-16. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
Jasper Sleet: North Korean remote IT workers’ evolving tactics to infiltrate organizations — Microsoft Threat Intelligence, 2025-06-30 (updated 2026-04-21). Checked 2026-10-17. ↩︎
SP 800-63A-4, Identity Proofing and Enrollment — NIST, 2025. Checked 2026-10-17. ↩︎
Configure Temporary Access Pass — Microsoft Learn, 2026-03-04. Checked 2026-10-16. ↩︎ ↩︎ ↩︎
What are lifecycle workflows? — Microsoft Learn, 2026-03-12. Checked 2026-10-16. ↩︎ ↩︎ ↩︎
Group Managed Service Accounts overview — Microsoft Learn, 2025-07-01. Checked 2026-10-17. ↩︎
Understanding SCIM and SCIM 2.0 protocol guide — Okta Developer. Checked 2026-10-16. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
How Application Provisioning works in Microsoft Entra ID — Microsoft Learn, 2025-03-04 (updated 2026-02-05). Checked 2026-10-16, re-checked 2026-10-17. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
Tutorial: Develop and plan provisioning for a SCIM endpoint — Microsoft Learn, 2026-09-15. Checked 2026-10-16. ↩︎ ↩︎
Provision a user or group on demand — Microsoft Learn, 2025-03-04 (updated 2026-10-14). Checked 2026-10-17. ↩︎ ↩︎
Revoke user access in an emergency in Microsoft Entra ID — Microsoft Learn, 2026-06-19. Checked 2026-10-16, re-checked 2026-10-17. ↩︎ ↩︎ ↩︎ ↩︎
Configurable token lifetimes in the Microsoft identity platform — Microsoft Learn, 2026-04-08 (updated 2026-06-15). Checked 2026-10-17. ↩︎ ↩︎
user: revokeSignInSessions — Microsoft Graph v1.0, 2024-04-17. Checked 2026-10-16. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
Okta Management API OpenAPI file, version 2026.41.0 — Okta (operations “Revoke all user sessions”, “Deactivate a user”, “Suspend a user”); rendered as User Sessions and User Lifecycle. Checked 2026-10-17. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
Manage emergency access admin accounts — Microsoft Learn, 2026-06-04. Checked 2026-10-16. ↩︎ ↩︎
How to manage inactive user accounts — Microsoft Learn, 2025-02-21. Checked 2026-10-16. ↩︎ ↩︎
AA23-320A, Scattered Spider — CISA and partners, 2023-11-16, last revised 2025-07-29. Checked 2026-10-16. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
OWASP Top 10 Non-Human Identities Risks – 2025 — OWASP, 2025. Checked 2026-10-16. ↩︎ ↩︎ ↩︎
Get credential reports for your AWS account — AWS IAM User Guide. Checked 2026-10-16. ↩︎ ↩︎ ↩︎ ↩︎
RoleLastUsed — AWS IAM API Reference. Checked 2026-10-17. ↩︎
Security best practices in IAM — AWS IAM User Guide. Checked 2026-10-16. ↩︎ ↩︎
Zero Trust Maturity Model, Version 2.0 — CISA, April 2023. Checked 2026-10-16. ↩︎ ↩︎
RFC 9700, Best Current Practice for OAuth 2.0 Security — IETF, January 2025. Checked 2026-10-16. ↩︎ ↩︎
What are risk detections? — Microsoft Learn, 2026-04-22. Checked 2026-10-16. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
Microsoft Defender for Identity dashboard — Microsoft Learn, 2026-07-02. Checked 2026-10-16. ↩︎
curl man page,
--fail-with-body— curl project (“Added in 7.76.0”). Checked 2026-10-17. ↩︎get-credential-report — AWS CLI Command Reference. Checked 2026-10-16. ↩︎
Root user best practices for your AWS account — AWS IAM User Guide. Checked 2026-10-17. ↩︎
Microsoft Actions Following Attack by Nation State Actor Midnight Blizzard — MSRC, 2024-01-19. Checked 2026-10-16. ↩︎
Midnight Blizzard: Guidance for responders on nation-state attack — Microsoft Security Blog, 2024-01-25. Checked 2026-10-16. ↩︎ ↩︎
Unauthorized Access to Okta’s Support Case Management System: Root Cause and Remediation — Okta Security, 2023-11-03. Checked 2026-10-16. ↩︎
Thanksgiving 2023 security incident — Cloudflare, 2024-02-01. Checked 2026-10-16. ↩︎ ↩︎
UNC5537 Targets Snowflake Customer Instances for Data Theft and Extortion — Mandiant (Google Cloud), 2024-06-10. Checked 2026-10-16. ↩︎
Incidents impacting retailers – recommendations from the NCSC — NCSC (UK), 2025-05-04. Checked 2026-10-16. ↩︎
Multi-Factor Authentication Request Generation, T1621 — MITRE ATT&CK, modified 2025-10-24. Checked 2026-10-16. ↩︎
Domain or Tenant Policy Modification: Trust Modification, T1484.002 — MITRE ATT&CK, modified 2026-05-12. Checked 2026-10-17. ↩︎
Modify Authentication Process, T1556 — MITRE ATT&CK, modified 2026-05-12. Checked 2026-10-16. ↩︎
Monitor and clean up stale guest accounts — Microsoft Learn, 2024-12-30. Checked 2026-10-17. ↩︎ ↩︎
Migrate JIT to SCIM — Docker Docs. Checked 2026-10-16. ↩︎ ↩︎
Continuous access evaluation — Microsoft Learn, 2026-04-08. Checked 2026-10-16. ↩︎ ↩︎