Microsoft 365 integration
Microsoft 365 integration
What it does
The Microsoft 365 integration reads the license subscriptions in your customers' Microsoft 365 tenants so xClause can compare the seats actually assigned against the quantities you bill for.
- Reads each tenant's subscribed license SKUs, with the number of seats purchased and the number assigned (consumed).
- Records the assigned seat count as the in-use count on the Licenses page, with Microsoft 365 as the source.
- Lets you map Microsoft SKUs to the products you bill. One product can hold several SKUs (for example Business Basic, Standard and Premium rolled up into one "Managed User" line).
- Supports two connection types:
- CSP partner (GDAP): one partner relationship covers many customer tenants, and no customer admin signs in.
- Delegated: a customer's Microsoft 365 admin signs in and approves access, one customer at a time.
The integration is read-only. xClause does not change anything in Microsoft 365. It does not import users: no Microsoft user, group or mailbox data is read.
For Microsoft Teams messaging, see the separate Teams integration. It is not covered here.
Before you start
In xClause
- You must be a member of the company you are connecting for, and you cannot be a client-portal user. Client users are redirected away from the Microsoft 365 pages.
- Adding a CSP customer and running Sync all now require your company to be an MSP company.
- The connect buttons are disabled when the xClause deployment has not been configured for Microsoft. In that case the page shows "Microsoft 365 isn't set up on this deployment." Contact xClause support.
On the Microsoft side
- Delegated: the customer's Microsoft 365 admin must sign in and consent. The in-app text names the permissions they approve (see Permissions). It does not say which Microsoft admin role is required.
- CSP partner: you need a Granular Delegated Admin Privileges (GDAP) relationship to the customer tenant in Partner Center that grants access to xClause's app registration. The in-app text does not say which GDAP roles are required.
- You need the customer's tenant ID (a GUID) for the CSP path.
Connect
Open Settings, then Integrations, and select the Microsoft 365 tile in the Licensing category. Select Open the full Microsoft 365 page to use the dedicated page. You can also open the Licenses page and select Connect Microsoft 365.
CSP partner (GDAP)
- Set up the GDAP relationship to the customer tenant in Partner Center.
- In the CSP partner (GDAP) section, enter the Customer tenant ID.
- Optionally enter a Customer name. This is the friendly name shown in xClause.
- Select Add CSP customer.
The customer appears under Connected customers with the connection type CSP partner. xClause creates a Microsoft access token for each sync. No consent screen is shown.
Adding a tenant ID does not test the connection. Select Sync all now to confirm xClause can read the tenant.
Delegated (one customer at a time)
- Select Connect a single tenant (the dedicated page labels the button Connect a Microsoft 365 tenant).
- You are sent to Microsoft's sign-in page, which prompts you to choose an account. The customer's Microsoft 365 admin signs in and approves the permissions.
- Microsoft returns you to xClause, and the tenant appears under Connected customers with the connection type Delegated.
The sign-in must complete within 10 minutes of selecting the button. After that, start again.
Map SKUs to products
Connecting a tenant gives you in-use seat counts. It does not give you a Difference until you map each Microsoft SKU to a product you bill.
- In the Second step: map Microsoft SKUs to the products you bill box, select Map Microsoft SKUs to products.
- For each SKU under Microsoft 365 SKUs seen in your customers' tenants, choose the product it belongs to and confirm. xClause may suggest a product, but it never applies a suggestion on its own.
Removing a mapping changes nothing in Microsoft 365. The seats just stop counting toward that product's Difference.
Permissions
Delegated connection
xClause requests these delegated scopes (authorization code flow, sign-in through Microsoft's common endpoint):
| Scope | Why |
|---|---|
openid | Returns the tenant ID in the sign-in token. |
profile | Standard sign-in profile. |
Directory.Read.All | Named in the in-app consent text. |
Organization.Read.All | Reads the organization's display name and tenant ID. |
offline_access | Lets xClause refresh access without asking the admin to sign in again. |
The in-app text shows only Directory.Read.All + Organization.Read.All as the permissions the admin approves.
CSP partner connection
xClause requests an app-only token with the scope https://graph.microsoft.com/.default. This means the app receives whatever application permissions have been granted to xClause's app registration for that tenant. The specific permissions are not set in xClause's code.
Graph calls xClause makes
| Graph endpoint | What xClause does | Access | Used by |
|---|---|---|---|
GET /v1.0/organization | Reads the organization display name when you connect a delegated tenant. Also used to find the tenant ID if the sign-in token does not carry it. | Read-only | Delegated connect |
GET /v1.0/subscribedSkus | Reads each license SKU: SKU ID, part number, capability status, purchased (enabled) seats and consumed seats. Stores a snapshot per sync and records consumed seats as the in-use count. | Read-only | Delegated and CSP syncs |
xClause makes no other Microsoft Graph calls. In particular it does not call the users, groups, devices or license-assignment endpoints, and it does not write to Microsoft 365.
Token requests go to Microsoft's sign-in service (/oauth2/v2.0/authorize and /oauth2/v2.0/token).
What syncs
Direction is one way: Microsoft 365 to xClause.
| Data | Trigger |
|---|---|
| SKU snapshots (purchased and consumed seats per SKU) | Sync all now button; every 6 hours; nightly at 03:00 UTC (the license sync that runs all license sources) |
| In-use seat counts on the Licenses page | Same triggers, for tenants assigned to an xClause client |
What gets recorded:
- Purchased and consumed seats are stored for each SKU on every sync. Consumed seats are used as the in-use count. Purchased seats are stored but not shown on the Licenses page.
- In-use counts appear with the source Microsoft 365. xClause does not set a contracted quantity from Microsoft data. The billed side comes from your PSA agreements and signed SOWs.
- Microsoft seat counts take precedence over PSA quantities when the two disagree, per the in-app text.
- Tenants must belong to a client. Seat counts reach the Licenses page only for a tenant assigned to an xClause client. Without that, the SKU snapshots are still saved (so SKU mapping works) but nothing is added to your inventory. The connect screens do not currently show a control for assigning a tenant to a client. See Troubleshooting.
- Platform administrators can switch off scheduled Microsoft syncs. When that happens, the 6-hour run reports that it is disabled and syncs nothing. Sync all now is not affected by that switch.
Troubleshooting
| What you see | What to do |
|---|---|
| "Microsoft 365 isn't set up on this deployment." | Connect buttons are disabled because the deployment is not configured for Microsoft. Contact xClause support. |
| "We couldn't load your connected customers. This list may be incomplete" | Refresh before adding a tenant, so you do not add one twice. |
Redirected back to /integrations/microsoft?error=... after signing in | Microsoft returned an error or the admin declined. The page does not display the error text. Try again and have the admin approve the request. |
| "OAuth state mismatch — restart the flow" | The sign-in expired (10 minutes) or cookies were blocked. Select Connect a single tenant again. |
| "Missing code or state", "Malformed state" | The return from Microsoft was incomplete. Start the connection again. |
| "Microsoft OAuth error: Microsoft token exchange failed: <status>" | Microsoft rejected the sign-in code. Start again. If it repeats, contact support with the status code. |
| "Microsoft OAuth error: Could not determine Microsoft tenantId from token response" | Start the connection again. Microsoft can briefly deny access right after first consent. |
| "Company not found", "Unauthorized", "Not authenticated" | Sign in again, and confirm you are a member of the company. |
| "Forbidden" on Add CSP customer or Sync all now | These actions require an MSP company. |
| "Sync finished with errors" (dedicated page) or "Could not sync Microsoft 365 licenses" (integration card), with a detail line | At least one tenant could not be read. The detail shows the first error. See the next rows. |
| "Sync completed with errors — some tenants could not be read." | Some tenants synced and some failed. |
| "Sync failed — no tenant could be read. Check the connection and admin consent." | No tenant could be read. For delegated tenants, have the admin reconnect and approve. For CSP tenants, confirm the GDAP relationship and the tenant ID. |
| "Graph subscribedSkus failed for <tenant>: <status>" | Microsoft refused or failed the license read for that tenant. A 401 or 403 usually means consent or GDAP access is missing. |
| "Microsoft refresh failed for tenant <tenant>: <status>" | xClause could not renew delegated access. Disconnect and reconnect that customer. |
| "has no refreshToken; reconnect required" or "has no access token; reconnect required" | Disconnect and reconnect that customer. |
| "Microsoft CSP token mint failed for <tenant>: <status>" | xClause could not get an app-only token for that tenant. Confirm the tenant ID and the GDAP relationship. |
| "<customer>: not assigned to a client — its licences are not reconciled. Assign it in Settings → Integrations → Microsoft." | The tenant is connected but not assigned to an xClause client, so its seat counts are not added to your inventory. This message appears on every sync until it is assigned. The connect screens do not show an assignment control, so contact xClause support. |
| "SKU <part number> is linked to N products; using the oldest link ... Unlink the duplicates so this SKU maps to one product." | Open Map Microsoft SKUs to products and remove the extra mappings so the SKU maps to one product. |
| "product mappings: ..." | The run was skipped because your SKU mappings could not be read. Try again. |
| "MICROSOFT_GRAPH_CLIENT_ID / SECRET not configured" | The deployment is not configured. Contact xClause support. |
Disconnecting
- In Connected customers, select Disconnect on the customer's row.
- Confirm Disconnect this customer? by selecting Disconnect.
What happens:
- xClause deletes the customer's connection record, including its stored access and refresh tokens, and stops pulling Microsoft 365 license usage for that customer.
- License data already collected stays in xClause, per the confirmation text. The stored SKU snapshots for that tenant are deleted with the connection.
- Disconnecting does not tell Microsoft anything. xClause makes no call to revoke the token or remove consent, and the in-app text does not mention removing the app in Microsoft. If you want to withdraw consent or end the GDAP relationship, do that on the Microsoft side.
- Product mappings are kept.
Reconnecting the same tenant later creates a new connection record.