Offboard a leaver in Microsoft 365
Who this is for: IT and security admins who want leavers’ Microsoft 365 access removed the same way every time.
Before you start: a Microsoft 365 connection (see Connect Microsoft 365), and a Microsoft Entra admin who can grant application permissions.
This page shows a workflow that takes a leaver’s user principal name, disables their account, ends their open sessions and removes them from your access groups. It uses the ready-made Microsoft 365 actions. Each step changes one user and is safe to run again.
- In your app registration in Microsoft Entra, under API permissions, add these application permissions and select Grant admin consent:
User.Read.Allto read the leaver’s account.User.EnableDisableAccount.Allto disable it.User.RevokeSessions.Allto sign them out.Directory.Read.Allto list their groups, andGroupMember.ReadWrite.Allto remove them.
- Disabling an account is a sensitive action. Microsoft may also require an admin role for the app, such as User Administrator. Only a Privileged Authentication Administrator or a Global Administrator can disable an administrator who has a privileged role, so offboard admins by hand or give that role only after careful thought.
- Create the workflow below, with your connection’s name in place of
m365. Change thefilterso it matches only the groups this workflow may change, for example the groups whose names start withAccess-. - Start a dry run with a real leaver’s user principal name. It reads the account and the groups for real, but holds back every change and logs it as “would have sent”. Check in the run log that it would change the right account and the right groups.
- Ask an admin to approve the workflow. See Approve a workflow.
name: Offboard a leaver in Microsoft 365description: Disable the leaver's Microsoft Entra ID account, sign them out everywhere and remove them from the access groups.
on: manual: true
steps: - id: leaver name: Read the leaver's account uses: library/ms365.get-user@v1 connections: graph: m365 with: user: ${{ trigger.body.upn }}
- id: disable name: Disable the account needs: [leaver] if: ${{ steps.leaver.outputs.found }} uses: library/ms365.disable-user@v1 connections: graph: m365 with: user: ${{ steps.leaver.outputs.user.id }}
- id: sign_out name: Sign the leaver out everywhere needs: [disable] uses: library/ms365.revoke-sign-in-sessions@v1 connections: graph: m365 with: user: ${{ steps.leaver.outputs.user.id }}
- id: groups name: List the leaver's access groups needs: [disable] uses: library/ms365.list-user-groups@v1 connections: graph: m365 with: user: ${{ steps.leaver.outputs.user.id }} filter: "startswith(displayName,'Access-')"
- id: remove name: Remove the leaver from each access group needs: [groups] uses: library/ms365.remove-group-member@v1 connections: graph: m365 strategy: for_each: ${{ steps.groups.outputs.groups }} fail_fast: false with: group: ${{ each.item.id }} member: ${{ steps.leaver.outputs.user.id }}What to expect
Section titled “What to expect”- The account is disabled first. The sign-out and the group changes run only after it, so the leaver can’t sign in again in between.
- Running it again is safe. An account that is already disabled reports
already_disabled, and a group the leaver already left reportsnot_a_member. Nothing fails. - Some groups can’t be changed here. Groups with dynamic membership follow their membership rule, and only security groups and Microsoft 365 groups can be changed through Microsoft Graph. Those steps fail and say why, and
fail_fast: falselets the other groups go ahead. Keep such groups out of thefilter. - Sign-out takes a few minutes. Microsoft can take a few minutes before every app notices, and it doesn’t sign out guest users from other organisations.