@synergyconsulting/n8n-nodes-microsoft-365-admin
v1.0.2
Published
Microsoft 365 Admin node for n8n: users, groups, authentication methods and licenses via Microsoft Graph, using app-only authentication.
Keywords
Readme
Microsoft 365 Admin
An n8n node for managing users, groups, authentication methods and licenses in Microsoft Entra ID through the Microsoft Graph API.
It authenticates as an application rather than a user, so it runs unattended: no browser sign-in, no redirect URI, and no refresh token to expire.
Operations
User — Create · Get · Get Many · Update · Delete · Add to Group · Remove From Group · Get Groups · Get Manager · Set Manager · Revoke Sessions
Group — Create · Get · Get Many · Update · Delete · Get Members · Get Owners · Add Owner · Remove Owner
Authentication — Get Many Methods · Get Password Method · Delete Method · Create Temporary Access Pass · Reset Password
License — Query Tenant Licenses · Query User Licenses · Query License Holders · Assign · Assign to Group · Unassign
Install
In n8n, go to Settings → Community nodes → Install and enter
@synergyconsulting/n8n-nodes-microsoft-365-admin.
To install it manually instead, run this in your n8n user folder and restart n8n:
cd ~/.n8n/nodes
npm install @synergyconsulting/n8n-nodes-microsoft-365-adminn8n 1.81 or newer is required: the license write operations run as custom operations, which older versions do not execute.
Setup
1. Register an application
In the Entra admin center go to Applications → App registrations → New registration. Choose Single tenant and leave the redirect URI blank — this node never uses one.
From the Overview page copy the Application (client) ID and the Directory (tenant) ID. Under Certificates & secrets create a client secret and copy its Value straight away; it is only shown once.
2. Grant permissions
Under API permissions → Add a permission → Microsoft Graph, choose Application permissions. Not Delegated — delegated permissions do nothing for an app-only connection and every call comes back 403.
| Permission | Covers |
|---|---|
| Organization.Read.All | the connection test and tenant license queries |
| User.ReadWrite.All | all user operations and user licensing |
| Group.ReadWrite.All | all group operations, including members and owners |
| UserAuthenticationMethod.ReadWrite.All | Authentication → Get Many Methods, Get Password Method, Delete Method and Create Temporary Access Pass |
| User-PasswordProfile.ReadWrite.All | Authentication → Reset Password through passwordProfile |
Then click Grant admin consent. This needs Global Administrator or Privileged Role Administrator — Application Administrator is not enough.
Reset Password additionally requires the application's service principal to hold at least the User Administrator Microsoft Entra role. Resetting privileged administrators is subject to the Entra role hierarchy and can require Privileged Authentication Administrator. These directory roles are separate from Microsoft Graph application permissions.
3. Add the credential
In n8n create a Microsoft 365 Admin (Service Principal) API credential and fill in the tenant ID, client ID and secret. Leave the Graph base URL on Global unless your tenant is in a sovereign cloud.
Save to run the connection test.
Things worth knowing
Recreate the credential after changing permissions. The access token is cached on the credential. Graph replies 403 to a valid token that lacks a permission, and n8n only fetches a new token on a 401 — so a token minted before you granted consent keeps failing forever. Deleting and re-adding the credential is the fix; editing and saving is not.
Entra ID applies one license change per tenant at a time. A second assignLicense
write arriving while the first is still being processed is rejected outright — "Error due
to concurrent requests being made to the tenant" — and the tenant can stay busy for the
better part of a minute. Assign, Assign to Group and Unassign therefore behave differently
from every other operation in this node: they send one request at a time rather than one
per input item in parallel, and a rejected write is retried with a growing delay instead of
failing the run. Three things make a bulk change finish quickly:
- Pick every SKU in one item. The License SKU field is a multi-select, and one request carries any number of licenses for the same tenant-processing time. Ten licenses on one user is one request, not ten.
- Swap in place. Options → License SKU Names or IDs to Remove on Assign removes licenses in the same request that adds the new ones, so an E3 → E5 move costs one round of processing instead of two.
- Let items collapse. Options → Combine Items for the Same Target (on by default) merges every input item aimed at the same user into a single request, so a workflow that emits one item per license change still sends one request per user.
For hundreds of users, license through a group instead: Assign to Group is a single write that Entra fans out to the members itself, in the background.
Options also carries Max Retries (default 5) and Wait Between Requests, for tenants where something outside the workflow — an admin in the portal, another automation — is competing for the same lock.
Password reset goes through passwordProfile, not the authentication methods API.
Graph's POST /users/{id}/authentication/methods/{id}/resetPassword supports delegated
access only — there is no application permission for it, so an app-only credential like
this one can never call it, whatever roles the app holds. Authentication → Reset Password
therefore PATCHes passwordProfile instead, which is the app-only equivalent: it writes
to Entra ID and, where password writeback is configured, on to on-premises AD. Leave the
Password option empty and the node generates one and returns it as password on the output
item — the only place a generated password exists, so capture it in the same run.
Deleting a method needs its type as well as its ID. Each method type lives in its own
Graph collection, and Get Many Methods reports an @odata.type rather than the URL
segment a delete needs. The node fills that gap: every method it returns carries
methodType (phoneMethods, fido2Methods, …), methodName and deletable, so an MFA
reset is Get Many Methods → Filter on deletable → Delete Method with
{{ $json.methodType }} and {{ $json.id }}. Picking by hand works too: choose the type,
and the Method list shows what that user has registered.
Some methods refuse to be deleted. Graph rejects deleting a phone number that is the
user's default MFA method — the user has to change their default first — and there is no
delete for a password at all. A mobile number cannot be removed while an
alternateMobile one exists.
A Temporary Access Pass is returned once. The temporaryAccessPass field of the
response is the passcode; it is never readable again. A user can hold only one usable pass,
so issuing a second replaces the first. A multi-use pass is only accepted if the Temporary
Access Pass authentication method policy allows it, and the method has to be enabled in
that policy for the target user at all — otherwise Graph refuses to issue one.
Revoking sessions is under User, not Authentication — User → Revoke Sessions invalidates refresh tokens and browser sessions, which pairs well with a password reset.
Set usageLocation before licensing a user. Assigning a license to a user without one
fails with an error that looks like a permissions problem. Set it first with User → Update
using a two-letter country code, e.g. LT.
Licenses inherited from a group cannot be unassigned directly. Query License Holders
returns licenseAssignmentStates; if assignedByGroup is set, the license comes from
group-based licensing and Unassign silently does nothing. Remove the user from that group
instead.
Assign to Group needs Entra ID P1 and licenses members in the background, so a successful response does not mean they are licensed yet.
Users holding admin roles need more than Graph permissions. To modify them the app also has to be assigned a directory role such as User Administrator — and Authentication Administrator for the Authentication resource, or Privileged Authentication Administrator to act on privileged accounts.
Using expressions
Any field can be driven from workflow data. Resource pickers (User, Group, Manager, Owner) take an expression once you switch them to By ID; dropdowns such as License SKU take one via the Fixed/Expression toggle.
Resource and Operation are the exceptions — n8n needs to know the operation to decide which fields to show. Use a Switch node if you need to vary it at runtime.
Development
npm install
npm run dev # n8n with this node linked, on http://localhost:5678
npm run build
npm run lint
npm testnpm run test:coverage enforces an 80% floor on lines, statements, branches and functions.
Layout
The node follows n8n's actions/transport structure, so each operation is one file that owns its parameters and its own request:
nodes/Microsoft365Admin/
├── Microsoft365Admin.node.ts # node description; delegates execution to the router
├── actions/
│ ├── router.ts # picks the operation for each input item
│ ├── node.type.ts # the resource → operation map, as types
│ └── <resource>/
│ ├── index.ts # the Operation dropdown, plus every operation's parameters
│ └── <operation>.operation.ts # `properties`, `description`, `execute`
├── methods/ # loadOptions and listSearch for the pickers
├── transport/ # Graph requests, paging and error translation
└── helpers/ # shared parameter shapes and per-resource logicTo add an operation: write <operation>.operation.ts exporting properties, description
and execute, register it in the resource's index.ts (both the export and the dropdown),
and add it to actions/node.type.ts.
Two things depart from the plain per-item pattern, both for reasons Graph forces:
- The three License write operations export
executeAllinstead ofexecute. Entra ID applies one license change per tenant at a time, so they run once for the whole input, serialise their requests and fold every item aimed at the same target into one call. - Reset Password returns the password it generated, which is why it is programmatic rather than a declarative PATCH — Graph answers 204 with nothing in it.
License
MIT. Includes code derived from the Microsoft Entra ID node in n8n; copyright in the original work belongs to n8n GmbH. Releases up to 1.0.0 were distributed under n8n's Sustainable Use License. See LICENSE.md.
