Delegated, always
CloudSergeant is a public client using delegated permissions. Every call it makes to Microsoft Graph or Exchange carries a token issued for you, so every action is attributable to your account in the Microsoft audit log, and every restriction that applies to you applies to the app.
There is deliberately no alternative:
- No application permissions. The app cannot act without a signed-in person.
- No service account. Nothing runs when the app is closed.
- No client secret on your machine. A public client has none to steal.
One consequence is worth stating plainly, because it defines what the product can and cannot do: mailbox content is reachable only as the mailbox's owner or as someone with Full Access to it. No administrative role grants access to the contents of someone else's mailbox. That is why the mailbox tools ask you to pick how you are reaching a mailbox, and why their partner-token path cannot work in a delegated customer tenant. A separate sign-in as a customer-tenant mailbox user is the only content path there.
Two tokens, one sign-in
Some of what the app does — mailbox settings, permissions, distribution groups, mail contacts — is not available in Microsoft Graph at all, and has to go through the Exchange Online admin API. That endpoint only accepts tokens issued to Microsoft's own Exchange administration client, so the app acquires a second token for it behind the same sign-in. You will not normally notice, except that the first Exchange operation in a session can take a moment longer, and that Exchange work needs an Exchange role rather than a directory one.
The permissions the app requests
These are requested at sign-in and must be admin-consented on the app registration in your tenant:
| Permission | What it is for |
|---|---|
User.Read | Reading who you are. |
User.Read.All | The user list and the user card. |
User.ReadWrite.All | Editing, creating and deleting users; password reset; profile picture. |
User.Create | The new user wizard. |
User-Phone.ReadWrite.All | Mobile and business phone numbers — a separate permission from User.ReadWrite.All, because a phone can be an MFA method. |
User-LifeCycleInfo.ReadWrite.All | Employee hire and leave dates. |
Directory.Read.All | Reading groups, devices, roles and directory attributes. |
AuditLog.Read.All | The exact last successful sign-in attempted first for the Users list and shown in the Attributes section of a user card. It also needs Microsoft Entra ID P1 or P2 and a role that may read sign-in activity; the Users list automatically falls back to Microsoft 365 activity when the read is refused. |
Group.ReadWrite.All | Creating, editing and deleting groups. |
GroupMember.ReadWrite.All | Group membership and owners. |
Organization.Read.All | Your verified domains, used by the username editor and the create wizard. |
BitLockerKey.Read.All | Revealing a device's BitLocker recovery key. |
Files.ReadWrite.All | A user's OneDrive address and storage, the OneDrive Copy / Move, Export / Import and filtered Cleanup tools, and handing files to someone else. Covers the read, so there is no separate Files.Read.All. |
RoleManagement.ReadWrite.Directory | Assigning and removing admin roles. |
UserAuthenticationMethod.ReadWrite.All | The Authentication section on the user card, including Reset MFA. |
Directory.AccessAsUser.All | Enabling, disabling and deleting devices. |
Reports.Read.All | The OneDrive list and the Users list's licence-free activity fallback when exact Entra sign-in is unavailable — Microsoft's own usage reports, one read per whole tenant report. |
ReportSettings.ReadWrite.All | Checking whether your tenant anonymises names in those reports — so the OneDrive list and Users activity column never treat meaningless identifiers as real — and turning that off from either page when you choose to. |
Mail.ReadWrite | The mailbox tools, on your own mailbox. |
Mail.ReadWrite.Shared | The mailbox tools, on a mailbox you have Full Access to. |
DelegatedAdminRelationship.Read.All | Listing your GDAP customer tenants. |
DelegatedAdminRelationship.ReadWrite.All | Optional and requested only when you create, edit, finalize, terminate, or delete a GDAP relationship from Partner ▸ Relationships (GDAP). |
CrossTenantInformation.ReadBasic.All | Showing each customer's domain beside its name in the tenant picker. |
Plus two permissions on other Microsoft APIs, which are requested against those services
rather than against Graph — so neither of them can affect a Graph sign-in:
Exchange.ManageV2 on Office 365 Exchange Online, for the
Exchange side described above, and AllSites.FullControl on
Office 365 SharePoint Online, for the OneDrive settings.
A OneDrive's external sharing, lock state, unmanaged-device access, storage quota, recycle bin and site collection administrators have no equivalent in Microsoft Graph at all — they are properties of the SharePoint site, so CloudSergeant reads and writes them through SharePoint's own admin endpoint. Without that permission the OneDrive list and its report figures still work, but SharePoint-backed values and changes do not. Reading or emptying the recycle bin is restricted further to the home tenant and primary sign-in. These administrative operations also need the SharePoint Administrator role.
With SharePoint Administrator in the relationship, a delegated partner can list a customer's OneDrives and change quota, sharing and lock settings through SharePoint's tenant-admin endpoint. Adding a site collection administrator works too. Microsoft does not let that partner identity reach the files themselves, so Graph drive details and the list of existing site administrators are not available there. The OneDrive tools can instead use a separate, session-only sign-in as a customer-tenant account that already has file access; recycle-bin emptying remains home-tenant only. See the exact capability split.
Tokens are requested with that exact list, so a single permission the registration has
not admin-consented fails every Graph call — not just the feature that
needs it. The symptom is "nothing loads at all", and the error is
AADSTS65001. Grant admin consent for the whole list, then sign in again.
The privileged permissions are in the same list
CloudSergeant used to keep its four most privileged permissions out of the baseline and ask for each one the first time you used the feature. They are now part of the single list above, so there is nothing optional to add separately — but they are worth knowing about, because each one still needs a directory role that no app can grant itself.
| Permission | Feature | Role you also need |
|---|---|---|
RoleManagement.ReadWrite.Directory |
Assigning or removing an admin role | Privileged Role Administrator |
UserAuthenticationMethod.ReadWrite.All |
The Authentication section: phone and recovery email, Temporary Access Pass, deleting methods, requiring MFA re-registration | Authentication Administrator — Privileged Authentication Administrator when the account itself holds an admin role |
Files.ReadWrite.All |
Reading an existing drive, OneDrive Copy / Move, ZIP Export / Import and filtered Cleanup, and handing a leaver's files to someone else. It covers the read, so there is no separate Files.Read.All, and it is part of the baseline rather than requested on demand. |
No role for a drive the user can already open; SharePoint Administrator to grant administrative access to another internal drive |
Directory.AccessAsUser.All |
Enabling, disabling or deleting a device | A device-administrator role — Cloud Device Administrator or Intune Administrator |
Consent is per tenant. A delegated (GDAP) customer tenant approves CloudSergeant separately from your own, whatever your home tenant has already granted, so a write there can still open a consent prompt. That is unrelated to the list above and is not a sign that anything is missing from the app registration.
Permissions are not enough on their own
An admin-consented permission lets the app ask. Whether the request succeeds depends on the directory role you hold, and no app can consent itself a role. So most write operations need both.
There is no way to test this in advance — Microsoft exposes no API that answers "would this write succeed?" — so CloudSergeant attempts the operation and explains the refusal. When something is denied you get the Graph permission it needed, the Exchange or directory role it needed, the roles you actually hold, and a verdict naming what looks to be missing. The full list of operations and their requirements is in the capability matrix.
Two escalations catch people out:
- Acting on an account that itself holds an admin role needs more. Resetting the password, managing the authentication methods, resetting the immutable ID or deleting such an account requires Privileged Authentication Administrator. A 403 on one specific user while every other user works is almost always this.
- A role-assignable group needs Privileged Role Administrator to delete. Again: one group fails, the rest are fine.
Global Administrator covers everything. If you hold it and something is still refused, the cause is a missing consent or a protected property, not a role gap — and the app says so.
Troubleshooting
Nothing loads at all, anywhere
A baseline permission has not been admin-consented, and every Graph call is failing with
AADSTS65001. Grant admin consent for the full baseline list above, then sign
out and back in. Adding a permission to the registration without consenting it produces
exactly this.
Everything works except the Exchange pages
Mailboxes, mail contacts and distribution-group settings run Exchange cmdlets, which need an Exchange role — Exchange Administrator, or the Recipient Management role group. A directory role such as User Administrator does not cover them.
Ordinary fields save, but the phone number will not
Phone numbers need User-Phone.ReadWrite.All and Authentication
Administrator (or Privileged Authentication Administrator, if the target holds an admin
role). User.ReadWrite.All does not include it.
A new customer tenant needs administrator consent
When you switch tenant, CloudSergeant checks the baseline permissions without opening a browser. If consent is missing, choose either to sign in as that tenant's Global Administrator or copy the tenant-specific consent link and send it to them. Ordinary page loads never launch that sign-in unexpectedly. After approval, reopen the page and the app verifies the new token directly with Microsoft.
A removal is refused and it is not about permissions
Microsoft Entra refuses two role removals no matter what you hold, and neither arrives as a permission error: removing the last Global Administrator, and removing an assignment that is not a direct membership — one that is PIM-eligible, or held through a role-assignable group. CloudSergeant only shows and changes direct, active assignments.
Something failed and the message is not specific
Technical detail is deliberately kept out of the interface — no stack traces, HTTP status
codes or response bodies. All of it goes to the day's file in
%LocalAppData%\CloudSergeant\logs, which you can open from
Settings ▸ Activity log. Permission and consent messages are the
exception and are shown in full, because those are the ones you can act on.