Stitchflow
Microsoft Azure / Entra ID logo

Microsoft Azure / Entra ID User Management API Guide

API workflow

How to automate user lifecycle operations through APIs with caveats that matter in production.

UpdatedFeb 27, 2026

Summary and recommendation

Microsoft Entra ID exposes user lifecycle operations through the Microsoft Graph API (base URL: `https://graph.microsoft.com/v1.0`). Authentication uses OAuth 2.0 client credentials flow - register an app in Entra, create a client secret, add the required Graph application permissions (`User.ReadWrite.All` or `Directory.ReadWrite.All`), grant admin consent, and exchange credentials for a Bearer token at `https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token`.

For teams managing Entra ID programmatically at scale, Stitchflow's MCP server with ~100 deep IT/identity integrations connects Entra ID alongside the rest of the SaaS stack, enabling cross-system lifecycle automation without building and maintaining individual Graph API integrations per app. The MCP server handles auth, pagination, delta sync, and offboarding orchestration across connected systems.

Key Graph endpoints for user management: `GET /users` (list, max `$top=999`), `POST /users` (create), `PATCH /users/{id}` (update or disable), `DELETE /users/{id}` (soft delete, 30-day recycle bin), and `GET /users/delta` (incremental sync).

Throttling is enforced at 10,000 requests per 10 minutes per app per tenant, with a global ceiling of 130,000 requests per 10 minutes per tenant across all apps.

API quick reference

Has user APIYes
Auth methodOAuth 2.0 (Microsoft identity platform / Azure AD)
Base URLOfficial docs
SCIM availableYes
SCIM plan requiredMicrosoft Entra ID Premium P1 or P2 (also included in Microsoft 365 E3/E5). Entra ID acts as the SCIM provisioning SOURCE (IdP) that pushes users to SCIM-enabled target applications.

Authentication

Auth method: OAuth 2.0 (Microsoft identity platform / Azure AD)

Setup steps

  1. Register an application in the Microsoft Entra admin center (portal.azure.com or entra.microsoft.com) under App registrations.
  2. Note the Application (client) ID and Directory (tenant) ID.
  3. Under Certificates & secrets, create a client secret (or upload a certificate for production).
  4. Under API permissions, add Microsoft Graph application permissions (e.g., User.Read.All, User.ReadWrite.All, Directory.ReadWrite.All) and grant admin consent.
  5. Obtain an access token via the client credentials flow: POST https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token with client_id, client_secret, scope=https://graph.microsoft.com/.default, grant_type=client_credentials.
  6. Use the returned access_token as a Bearer token in the Authorization header for all Microsoft Graph requests.

Required scopes

Scope Description Required for
User.Read.All Read all users' full profiles List users, get user by ID
User.ReadWrite.All Read and write all users' full profiles Create, update, delete users
Directory.ReadWrite.All Read and write directory data including users and groups Full directory management including group membership
Directory.Read.All Read directory data Read-only directory operations
User.ManageIdentities.All Manage all users' identities Managing external identities on user accounts

User object / data model

Field Type Description On create On update Notes
id string (GUID) Unique identifier for the user object in Entra ID auto-generated immutable Use this as the stable identifier; UPN can change
userPrincipalName string UPN (login name), typically user@domain.com required optional Must be a verified domain in the tenant
displayName string Display name shown in directory required optional
mailNickname string Mail alias (portion before @) used for email required optional Required when creating a user
accountEnabled boolean Whether the user account is enabled for sign-in required optional Set to false to disable without deleting
passwordProfile object Password and force-change-on-next-sign-in settings required optional Contains password (string) and forceChangePasswordNextSignIn (boolean)
givenName string First name optional optional
surname string Last name optional optional
mail string Primary SMTP email address optional optional Read-only for synced users from on-premises AD
jobTitle string User's job title optional optional
department string Department name optional optional
mobilePhone string Primary mobile phone number optional optional
officeLocation string Office location in the user's place of business optional optional
usageLocation string (ISO 3166-1 alpha-2) Two-letter country code for license assignment optional optional Required before assigning Microsoft 365 licenses
assignedLicenses array of assignedLicense Licenses assigned to the user not set here via assignLicense action Use POST /users/{id}/assignLicense to modify
userType string Member or Guest optional optional Defaults to Member for new users
externalUserState string State of guest invitation (PendingAcceptance, Accepted) auto-set for guests read-only
onPremisesSyncEnabled boolean True if synced from on-premises AD via Entra Connect auto-set read-only Many fields are read-only for synced users
manager directoryObject (relationship) User's manager not in body via PUT /users/{id}/manager/$ref Separate endpoint required to set/update manager
proxyAddresses array of string Email addresses associated with the user optional optional Read-only for on-premises synced users

Core endpoints

List users

  • Method: GET
  • URL: https://graph.microsoft.com/v1.0/users
  • Watch out for: Without $select, Graph returns a default subset of fields. Use $select to control returned fields and reduce payload size. Max $top is 999.

Request example

GET /v1.0/users?$top=100&$select=id,displayName,userPrincipalName,accountEnabled
Authorization: Bearer {token}

Response example

{
  "value": [
    {"id":"abc-123","displayName":"Jane Doe","userPrincipalName":"jane@contoso.com","accountEnabled":true}
  ],
  "@odata.nextLink":"https://graph.microsoft.com/v1.0/users?$skiptoken=..."
}

Get user by ID or UPN

  • Method: GET
  • URL: https://graph.microsoft.com/v1.0/users/{id|userPrincipalName}
  • Watch out for: Using UPN as the identifier can fail if the UPN contains special characters (e.g., #). Prefer the immutable object ID.

Request example

GET /v1.0/users/abc-123
Authorization: Bearer {token}

Response example

{
  "id": "abc-123",
  "displayName": "Jane Doe",
  "userPrincipalName": "jane@contoso.com",
  "accountEnabled": true,
  "jobTitle": "Engineer"
}

Create user

  • Method: POST
  • URL: https://graph.microsoft.com/v1.0/users
  • Watch out for: displayName, userPrincipalName, mailNickname, accountEnabled, and passwordProfile are all required. The UPN domain must be a verified domain in the tenant.

Request example

POST /v1.0/users
Content-Type: application/json
{
  "displayName":"John Smith",
  "userPrincipalName":"john@contoso.com",
  "mailNickname":"john",
  "accountEnabled":true,
  "passwordProfile":{"password":"Temp!Pass1","forceChangePasswordNextSignIn":true}
}

Response example

{
  "id": "def-456",
  "displayName": "John Smith",
  "userPrincipalName": "john@contoso.com",
  "accountEnabled": true
}

Update user

  • Method: PATCH
  • URL: https://graph.microsoft.com/v1.0/users/{id}
  • Watch out for: PATCH returns 204 with no body on success. Many properties are read-only for on-premises synced users (onPremisesSyncEnabled=true); those must be updated in on-premises AD.

Request example

PATCH /v1.0/users/def-456
Content-Type: application/json
{
  "jobTitle": "Senior Engineer",
  "department": "Platform"
}

Response example

HTTP 204 No Content

Delete user

  • Method: DELETE
  • URL: https://graph.microsoft.com/v1.0/users/{id}
  • Watch out for: Deleted users are soft-deleted and moved to the deleted items container for 30 days before permanent deletion. They can be restored within that window via POST /directory/deletedItems/{id}/restore.

Request example

DELETE /v1.0/users/def-456
Authorization: Bearer {token}

Response example

HTTP 204 No Content

Disable user (block sign-in)

  • Method: PATCH
  • URL: https://graph.microsoft.com/v1.0/users/{id}
  • Watch out for: Preferred over deletion for temporary deactivation. Existing sessions may persist until token expiry (up to 1 hour for access tokens).

Request example

PATCH /v1.0/users/def-456
Content-Type: application/json
{
  "accountEnabled": false
}

Response example

HTTP 204 No Content

List group members

  • Method: GET
  • URL: https://graph.microsoft.com/v1.0/groups/{group-id}/members
  • Watch out for: Members can be users, groups, service principals, or devices. Filter by @odata.type if only users are needed.

Request example

GET /v1.0/groups/{group-id}/members?$select=id,displayName,userPrincipalName
Authorization: Bearer {token}

Response example

{
  "value": [
    {"@odata.type":"#microsoft.graph.user","id":"abc-123","displayName":"Jane Doe"}
  ]
}

Delta query (incremental user sync)

  • Method: GET
  • URL: https://graph.microsoft.com/v1.0/users/delta
  • Watch out for: Store the deltaLink token and use it on subsequent calls to get only changed users. Deleted users appear with @removed annotation. Initial call returns all users; subsequent calls return only changes.

Request example

GET /v1.0/users/delta?$select=displayName,userPrincipalName,accountEnabled
Authorization: Bearer {token}

Response example

{
  "value": [{"id":"abc-123","displayName":"Jane Doe"}],
  "@odata.deltaLink":"https://graph.microsoft.com/v1.0/users/delta?$deltatoken=..."
}

Rate limits, pagination, and events

  • Rate limits: Microsoft Graph applies per-app, per-tenant throttling. For identity and access (users/groups), the limit is 10,000 requests per 10 minutes per tenant per app. A global limit of 130,000 requests per 10 minutes per tenant across all apps also applies.
  • Rate-limit headers: Yes
  • Retry-After header: Yes
  • Rate-limit notes: When throttled, Graph returns HTTP 429 with a Retry-After header indicating seconds to wait. Headers x-ms-throttle-limit-percentage and x-ms-throttle-scope may be returned. Batch requests (up to 20 per batch) count individually against limits. Delta queries are recommended for large-scale sync to reduce request volume.
  • Pagination method: token
  • Default page size: 100
  • Max page size: 999
  • Pagination pointer: $top (page size), @odata.nextLink (continuation token in response)
Plan Limit Concurrent
All plans (per app per tenant) 10,000 requests per 10 minutes 0
All plans (global per tenant) 130,000 requests per 10 minutes 0
  • Webhooks available: Yes
  • Webhook notes: Microsoft Graph supports change notifications (webhooks) for user and group objects. Subscribe via POST /subscriptions to receive HTTP POST notifications to a specified endpoint when user objects change.
  • Alternative event strategy: For polling-based sync, use the Microsoft Graph delta query endpoint (/users/delta) to retrieve incremental changes without webhooks. For audit events, use the Entra ID audit logs API (GET /auditLogs/directoryAudits).
  • Webhook events: created (user), updated (user), deleted (user), created (group), updated (group), deleted (group), group member added, group member removed

SCIM API status

  • SCIM available: Yes

  • SCIM version: 2.0

  • Plan required: Microsoft Entra ID Premium P1 or P2 (also included in Microsoft 365 E3/E5). Entra ID acts as the SCIM provisioning SOURCE (IdP) that pushes users to SCIM-enabled target applications.

  • Endpoint: Varies per target application; configured in Entra admin center under Enterprise Applications > Provisioning. Entra ID sends SCIM requests to the target app's SCIM endpoint.

  • Supported operations: Create user (POST /Users), Read user (GET /Users/{id}), Update user (PATCH /Users/{id}), Deactivate user (PATCH /Users/{id} with active=false), Delete user (DELETE /Users/{id}), Create group (POST /Groups), Update group membership (PATCH /Groups/{id}), Delete group (DELETE /Groups/{id}), Filter users (GET /Users?filter=)

Limitations:

  • Entra ID is the SCIM client (provisioner), not a SCIM server for inbound provisioning to Entra itself (inbound SCIM to Entra is available but in a different configuration path).
  • Provisioning cycles run approximately every 40 minutes; near-real-time provisioning requires on-demand provisioning or API-triggered provisioning.
  • Attribute mapping is configurable but limited to the schema supported by the target app.
  • Requires Premium P1 or P2 license; not available on free or basic Entra ID tiers.
  • SCIM provisioning to gallery apps is generally well-supported; non-gallery apps require manual SCIM endpoint configuration.
  • Inbound SCIM provisioning (external system pushing users into Entra ID) is supported via the Entra ID inbound provisioning API but requires additional configuration.

Common scenarios

Provision a new employee: POST /v1. 0/users with displayName, userPrincipalName, mailNickname, accountEnabled=true, passwordProfile, and usageLocation (required before license assignment).

Capture the returned id, then call POST /v1. 0/users/{id}/assignLicense with the target skuId.

Retrieve available SKUs via GET /v1. 0/subscribedSkus.

Missing usageLocation returns a 400 on license assignment - set it at user creation, not after.

Incremental sync: Call GET /v1.0/users/delta?$select=id,displayName,userPrincipalName,accountEnabled,department to retrieve all users and a deltaLink token. On each subsequent cycle, call the stored deltaLink URL to retrieve only changed users. Deleted users appear with an @removed annotation. Delta tokens can expire if left unused for too long - restart with a full delta query if the token is stale.

Offboard a departing employee: PATCH /v1.0/users/{id} with accountEnabled=false to block sign-in, then POST /v1.0/users/{id}/revokeSignInSessions to invalidate refresh tokens. Remove group memberships via DELETE /v1.0/groups/{group-id}/members/{user-id}/$ref. Reclaim licenses via POST /v1.0/users/{id}/assignLicense with removeLicenses. Soft-delete via DELETE /v1.0/users/{id}; permanently delete via DELETE /v1.0/directory/deletedItems/{id} if immediate removal is required. Note: existing access tokens remain valid up to 1 hour post-revocation unless Continuous Access Evaluation (CAE) is enabled on the target resource.

Provision a new employee and assign a license

  1. POST /v1.0/users with displayName, userPrincipalName, mailNickname, accountEnabled=true, passwordProfile, usageLocation (e.g., 'US').
  2. Capture the returned user id.
  3. POST /v1.0/users/{id}/assignLicense with addLicenses array containing the skuId for the desired Microsoft 365 plan and removeLicenses as empty array.
  4. Optionally PUT /v1.0/users/{id}/manager/$ref to set the user's manager.
  5. Optionally POST /v1.0/groups/{group-id}/members/$ref to add the user to relevant security or Microsoft 365 groups.

Watch out for: usageLocation must be set before assignLicense or the license assignment will return a 400 error. Retrieve available SKUs via GET /v1.0/subscribedSkus to find the correct skuId.

Incremental user sync to an external system

  1. Make an initial GET /v1.0/users/delta?$select=id,displayName,userPrincipalName,accountEnabled,department to retrieve all users and receive a deltaLink token.
  2. Store the deltaLink token securely.
  3. On each subsequent sync cycle, call the stored deltaLink URL to retrieve only users added, updated, or deleted since the last call.
  4. Process created/updated users (present in value array) and deleted users (present with @removed annotation).
  5. Store the new deltaLink from the response for the next cycle.

Watch out for: Delta tokens can expire if not used for an extended period. If the token expires, restart with a full delta query. Do not rely on deltaLink tokens for long-term storage without periodic refresh.

Offboard a departing employee

  1. PATCH /v1.0/users/{id} with accountEnabled=false to immediately block sign-in.
  2. Revoke all refresh tokens via POST /v1.0/users/{id}/revokeSignInSessions to invalidate active sessions (access tokens still valid up to 1 hour).
  3. Remove the user from groups via DELETE /v1.0/groups/{group-id}/members/{user-id}/$ref for each group.
  4. POST /v1.0/users/{id}/assignLicense with removeLicenses containing the skuIds to reclaim licenses.
  5. DELETE /v1.0/users/{id} to soft-delete the user (recoverable for 30 days).
  6. After 30 days or when confirmed, permanently delete via DELETE /v1.0/directory/deletedItems/{id} if immediate permanent deletion is required.

Watch out for: revokeSignInSessions invalidates refresh tokens but existing access tokens remain valid until expiry (up to 1 hour). For immediate access revocation, Continuous Access Evaluation (CAE) must be enabled and the target resource must support it.

Why building this yourself is a trap

On-premises AD-synced users (onPremisesSyncEnabled=true) have most Graph-writable attributes set to read-only; PATCH calls on those fields return success but are silently overwritten on the next sync cycle. All attribute changes for synced users must originate in on-premises AD.

This affects a significant portion of enterprise tenants and is not surfaced as an error at the API level.

Application permissions used in the client credentials flow require explicit admin consent per tenant before any API call succeeds. Consent granted in one tenant does not transfer. Additionally, $filter support across user properties is inconsistent - not all fields support all filter operators, and unsupported combinations return 400 errors rather than empty result sets.

Batch requests support up to 20 sub-requests per call, but each sub-request counts individually against throttling limits. At scale, batching reduces HTTP overhead but does not increase effective throughput. For large-scale sync workloads, delta queries are the recommended pattern to minimize request volume against the 10,000 requests/10-minute per-app ceiling.

Automate Microsoft Azure / Entra ID workflows without one-off scripts

Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.

Every app coverage, including apps without APIs
60+ app integrations plus browser automation for apps without APIs
IT graph reconciliation across apps and your IdP
Less than a week to launch, maintained as APIs and admin consoles change
SOC 2 Type II. ~2 hours of your team's time

UpdatedFeb 27, 2026

* Details sourced from official product documentation and admin references.

Keep exploring

Related apps

15Five logo

15Five

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

15Five uses a fixed role-based permission model with six predefined roles: Account Admin, HR Admin, Billing Admin, Group Admin, Manager, and Employee. No custom roles can be constructed. User management lives at Settings gear → People → Manage people p

1Password logo

1Password

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

1Password's admin console at my.1password.com covers the full user lifecycle — invitations, group assignments, vault access, suspension, and deletion — without any third-party tooling. Like every app that mixes role-based and resource-level permissions

8x8 logo

8x8

Full API + SCIM
AutomationAPI + SCIM
Last updatedFeb 2026

8x8 Admin Console supports full lifecycle user management — create, deactivate, and delete — across its X Series unified communications platform. Every app a user can access (8x8 Work desktop, mobile, web, Agent Workspace) is gated by license assignmen