Skip to content

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.

  1. In your app registration in Microsoft Entra, under API permissions, add these application permissions and select Grant admin consent:
    • User.Read.All to read the leaver’s account.
    • User.EnableDisableAccount.All to disable it.
    • User.RevokeSessions.All to sign them out.
    • Directory.Read.All to list their groups, and GroupMember.ReadWrite.All to remove them.
  2. 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.
  3. Create the workflow below, with your connection’s name in place of m365. Change the filter so it matches only the groups this workflow may change, for example the groups whose names start with Access-.
  4. 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.
  5. Ask an admin to approve the workflow. See Approve a workflow.
name: Offboard a leaver in Microsoft 365
description: 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 }}
  • 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 reports not_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: false lets the other groups go ahead. Keep such groups out of the filter.
  • 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.