Set up a delegated Microsoft Graph credential, then build workflow actions that change users, licences, groups and mailboxes

To make changes in Microsoft 365, such as resetting a password, offboarding a leaver or assigning a licence, you build a workflow action that calls Microsoft Graph with a Microsoft Graph credential. This page shows MSPs and IT teams how to set up that credential, choose its scopes, call Graph from a script, and decide who approves each action.

The Microsoft 365 connection is read-only and is separate from this credential. See What SuperIT can do in Microsoft 365 for what SuperIT can read without an action.

How Microsoft 365 actions work

  1. An engineer, an end user or a ticket investigation asks SuperIT to do something, for example "Reset Jane's password".
  2. SuperIT finds a published action that does it and runs it with the requester's inputs. The action's authorization policy decides whether the requester may run it and whether someone must approve it first.
  3. After any approval, the action's PowerShell script runs in SuperIT's cloud sandbox. The script gets a fresh Microsoft Graph access token from the linked credential and calls the Graph REST API.
  4. The result appears in chat and in the action's Executions tab. If the run is linked to a ticket, SuperIT adds a note to it in your PSA.

No Microsoft 365 actions ship with SuperIT today. You build each one, usually by asking SuperIT to draft it. The guides show how.

How the Microsoft Graph credential works

The Microsoft Graph credential is delegated. A Microsoft 365 administrator signs in once when you create it, and every action that uses it acts as that administrator, limited to the scopes you chose. What an action can actually do is the overlap of two things:

  • The scopes on the credential, for example User.ReadWrite.All.
  • The Entra ID roles the signed-in administrator holds, for example User Administrator.

If either is missing, Microsoft Graph refuses the call and the action fails with a permission error. Changes appear in Microsoft 365 audit logs under the signed-in administrator's name.

SuperIT stores the credential encrypted and refreshes the token for each run. It hands the token to the script only after any approval, as the environment variable CREDENTIAL_<NAME>_TOKEN. <NAME> is the credential name in capitals with every run of other characters replaced by _. A credential named M365 Graph gives CREDENTIAL_M365_GRAPH_TOKEN. The guides on this site assume that name.

There is no app-only (client credentials) option. The credential always acts as a signed-in administrator.

Choose the administrator account

Sign in with a dedicated admin account for automation, for example [email protected], not a person's own account:

  • Actions keep working when a staff member leaves.
  • Give the account only the Entra ID roles your actions need (see the table below). User Administrator covers most user, licence and group tasks.
  • Microsoft audit logs show clearly which changes came from SuperIT actions.

Most of the scopes below need admin consent for the organisation. When the account signs in, Microsoft asks for consent. If the account isn't allowed to grant admin consent, a Global Administrator (or Privileged Role Administrator) must grant it.

Step 1: Create the Microsoft Graph credential

You need the Engineer or Admin role. See Roles.

  1. Switch to the team whose tenant the actions will change. For an MSP, that is usually your service provider team, if you publish actions to managed teams (see Use the actions in managed teams).
  2. Go to Workflows → Credentials and select New. The Add credential form opens.
  3. In Name, enter M365 Graph.
  4. In Auth scheme, choose Microsoft Graph.
  5. In Scopes (space or comma separated), enter the scopes your actions need. See Scopes per task.
  6. Select Register with Microsoft Graph.
  7. Sign in to Microsoft with the automation admin account and accept the permissions.
  8. Back in SuperIT, check that the credential shows Authorized. The Script environment variables panel shows the variable name, CREDENTIAL_M365_GRAPH_TOKEN.

SuperIT always adds openid and offline_access, so you don't need to enter them.

To add scopes later, open the credential, change Scopes, select Save changes, then Re-authorize. "Scopes apply on the next authorization."

You can also ask SuperIT in chat to set up the credential. An admin can say "Set up a Microsoft Graph credential called M365 Graph with User.ReadWrite.All", and SuperIT opens a prefilled credential form for you to finish.

Create each of the other credentials in Scopes per task the same way, with its own name and scopes, when you build an action that needs it.

Scopes per task

Use the fewest scopes that do the job, and keep higher-risk tasks on their own credential, so a mistake or misuse in one action can't reach further than it needs to. The guides use one credential per task family:

Credential Used for Environment variable
M365 Graph User administration: onboarding, offboarding, passwords, sign-in blocking, licences and groups CREDENTIAL_M365_GRAPH_TOKEN
M365 Security Revoking sessions, Temporary Access Passes and MFA resets CREDENTIAL_M365_SECURITY_TOKEN
M365 Reports Read-only reports, such as inactive accounts CREDENTIAL_M365_REPORTS_TOKEN
M365 Mail Reports Sending report emails (Mail.Send) CREDENTIAL_M365_MAIL_REPORTS_TOKEN
M365 Exchange Exchange Online tasks: out-of-office, forwarding, shared mailboxes and inbox rules CREDENTIAL_M365_EXCHANGE_TOKEN

Link each credential only to the actions in its family.

Task Delegated Graph scopes Entra ID role for the admin account
Look up users User.Read.All Any role that can read users, for example Directory Readers
Create or update a user User.ReadWrite.All User Administrator
Reset a password User-PasswordProfile.ReadWrite.All, User.Read.All, GroupMember.Read.All Helpdesk Administrator, Password Administrator or User Administrator. Privileged Authentication Administrator to reset other admins
Block or unblock sign-in User.EnableDisableAccount.All, User.Read.All, GroupMember.Read.All User Administrator
Revoke sign-in sessions User.RevokeSessions.All, User.Read.All, GroupMember.Read.All Helpdesk Administrator or User Administrator
Assign or remove licences LicenseAssignment.ReadWrite.All, User.Read.All License Administrator or User Administrator
Add or remove group members GroupMember.ReadWrite.All, User.Read.All Groups Administrator or User Administrator
Issue a Temporary Access Pass, remove MFA methods UserAuthenticationMethod.ReadWrite.All, User.Read.All, GroupMember.Read.All Authentication Administrator. Privileged Authentication Administrator for admins
Licence reports LicenseAssignment.Read.All, User.Read.All Global Reader or License Administrator
Sign-in activity reports AuditLog.Read.All, User.Read.All Reports Reader or Global Reader. The tenant needs Microsoft Entra ID P1 or P2
Send a report email Mail.Send None. The email is sent from the signed-in administrator's mailbox

GroupMember.Read.All lets these actions check whether the target account holds an admin role through a role-assignable group, so they can refuse to act on admins.

A credential for general user administration (onboarding, offboarding, passwords, licences and groups) might use:

User.ReadWrite.All User-PasswordProfile.ReadWrite.All User.RevokeSessions.All LicenseAssignment.ReadWrite.All GroupMember.ReadWrite.All

These scopes follow Microsoft's Graph permissions reference. Test each action in your tenant before you rely on it, and add a scope if Microsoft Graph returns a permission error.

Mail-enabled security groups and distribution lists can't be changed through Microsoft Graph. Use Exchange Online for those.

Call Microsoft Graph from PowerShell

Actions run PowerShell 7 in SuperIT's cloud sandbox. The sandbox doesn't include the Microsoft Graph PowerShell SDK, so Connect-MgGraph fails. Call the Graph REST API with Invoke-RestMethod and the credential's token:

$token = $env:CREDENTIAL_M365_GRAPH_TOKEN
if (-not $token) { throw "The M365 Graph credential is not linked to this action." }

$headers = @{ Authorization = "Bearer $token" }
$graph   = "https://graph.microsoft.com/v1.0"

$upn  = $ctx.inputs.user_upn
$user = Invoke-RestMethod -Uri "$graph/users/$upn`?`$select=id,displayName,accountEnabled" -Headers $headers
Write-Output "Found $($user.displayName). Account enabled: $($user.accountEnabled)"

$result = @{ user = $user.displayName; enabled = $user.accountEnabled }

What SuperIT provides to every PowerShell action:

  • $ctx.inputs.<name> holds each input. Every value is a string, booleans arrive as "true" or "false", and an optional input left blank is missing ($null).
  • $ErrorActionPreference = "Stop" is already set, so a failed Graph call stops the script and marks the run as failed.
  • Anything you write with Write-Output appears in the run's Stdout. Set $result = @{ ... } to return structured output.
  • The script, inputs and credentials together must fit in about 28 KiB, and runs time out after 5 minutes unless you raise Script timeout (minutes), up to 60.

Use backticks before ? and $ in OData query strings, as above. Graph returns up to 100 items per page; follow @odata.nextLink to get the rest. See Workflows reference for all sandbox limits.

Exchange Online tasks

Out-of-office replies for other users, mail forwarding, removing inbox rules from other users' mailboxes, shared mailbox permissions and distribution lists need Exchange Online. The sandbox includes the ExchangeOnlineManagement module.

Connect-ExchangeOnline needs a token for Exchange Online, not for Microsoft Graph, and one credential can't hold both. Create a second Microsoft Graph credential named M365 Exchange with this scope:

https://outlook.office365.com/Exchange.Manage

Sign in with an account that holds the Exchange Administrator role. Then connect in the script:

$token = $env:CREDENTIAL_M365_EXCHANGE_TOKEN
if (-not $token) { throw "The M365 Exchange credential is not linked to this action." }

# A delegated token must be paired with the signed-in admin's UPN, read from the token itself.
$part = $token.Split('.')[1].Replace('-', '+').Replace('_', '/')
$part += '=' * ((4 - $part.Length % 4) % 4)
$claims = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($part)) | ConvertFrom-Json

Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -AccessToken $token -UserPrincipalName $claims.upn -ShowBanner:$false
try {
    Get-Mailbox -Identity $ctx.inputs.mailbox | Select-Object DisplayName, RecipientTypeDetails
}
finally {
    Disconnect-ExchangeOnline -Confirm:$false
}

Test the Exchange Online connection with a read-only command, such as the Get-Mailbox example above, before you build actions that change mailboxes.

Choose approvals

Every action links an authorization policy. Rules are checked from the top, and the first rule that matches the requester decides. Groups are superit:* tags you assign in Users → Manage groups; synced m365:* groups can't be used. With no policy, only engineers and admins can run the action, without approval.

Suggested starting points. These are deliberately conservative; loosen them only once an action has run reliably in your tenant:

Kind of action Suggested policy
Read-only reports Engineers and admins (superit:engineers, superit:admins) → No approval needed
Anything that changes Microsoft 365: onboarding, offboarding, passwords, sign-in, sessions, licences, groups, MFA, mailboxes, forwarding and inbox rules Engineers and admins (superit:engineers, superit:admins) → Require approval from superit:admins

Don't add an Anyone rule to an action that changes Microsoft 365. The script can't tell who asked, so an Anyone rule would let any end user request a change to any account.

Anyone in the approver group can approve, because groups are tags an admin assigns, not roles. Keep end users out of superit:admins and any other approver group. Approvers get an email and can approve in the app or in chat. Unanswered approvals expire after 7 days.

Mail forwarding to outside addresses is a common route for data theft. Keep approval on any forwarding action.

Test before you publish

The Test button in the action editor runs the script for real, not as a dry run. It skips authorization and approval, uses the real credential, and can change real accounts. Test with a test user, never with a real person's account. Test runs aren't billed.

Use the actions in managed teams

An MSP can build an action once on the service provider team and publish it to managed teams with the Publish dialog. This needs a primary PSA connection. Each managed team gets a read-only copy, and each linked credential arrives blank, unless that team already has a credential with the same name and type, which the copy uses as it is. An engineer or admin on each managed team opens Workflows → Credentials, opens each credential (marked Needs configuration) and selects Re-authorize, signing in with an admin account in that customer's tenant. Until then, runs are refused. See Publish to managed teams.

Guides

If something goes wrong

  • The run fails with Authorization_RequestDenied, Forbidden or 403. The credential is missing a scope, or the signed-in admin lacks the Entra ID role. Add the scope and select Re-authorize, or give the admin account the role.
  • "Credential '…' is an unconfigured placeholder — set its values before running": the credential on a managed team hasn't been authorized yet. See Use the actions in managed teams.
  • The token stops working after the admin account's password changes or the account is disabled. Open the credential and select Re-authorize.