Root cause: app-only Graph operations (password reset, Exchange REST) require directory roles on each SP in the customer tenant, not just admin consent. RoleManagement.ReadWrite.Directory was missing from all app manifests, making role assignment impossible without manual portal work that was never being done. Changes: - patch-tenant-admin-manifest.sh: adds RoleManagement.ReadWrite.Directory to Tenant Admin app manifest via Management app, grants home-tenant consent - onboard-tenant.sh: new script — resolves tenant, acquires Tenant Admin token, assigns Exchange Administrator to Security Investigator SP and User/Auth Administrator to User Manager SP; --dry-run supported; idempotent - get-token.sh: detects AADSTS7000229, emits consent URL + onboard-tenant.sh reminder instead of silent failure - gotchas.md: onboarding steps at top, tenant table expanded with role columns, all known tenants updated including martylryan.com (first fully onboarded) Verified: martylryan.com fully onboarded, password reset to MLR2026!! succeeded Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.7 KiB
Gotchas — Permissions, Roles, Consent
Onboarding a new tenant
Run onboard-tenant.sh after admin consents each app. This assigns required directory roles automatically.
Quick steps:
- Send consent URLs (Tenant Admin FIRST, then others)
- After admin accepts:
bash scripts/onboard-tenant.sh <domain> - Verify output shows all roles [OK]
- Update tenant table below
If Tenant Admin is not yet consented, onboard-tenant.sh will output all needed consent URLs.
App Suite (tiered architecture)
Five multi-tenant apps replace the old single over-permissioned app. Use minimum necessary tier.
| Tier | Display name in customer tenant | App ID | Vault file |
|---|---|---|---|
investigator / investigator-exo |
ComputerGuru Security Investigator | bfbc12a4-f0dd-4e12-b06d-997e7271e10c |
computerguru-security-investigator.sops.yaml |
exchange-op |
ComputerGuru Exchange Operator | b43e7342-5b4b-492f-890f-bb5a4f7f40e9 |
computerguru-exchange-operator.sops.yaml |
user-manager |
ComputerGuru User Manager | 64fac46b-8b44-41ad-93ee-7da03927576c |
computerguru-user-manager.sops.yaml |
tenant-admin |
ComputerGuru Tenant Admin | 709e6eed-0711-4875-9c44-2d3518c47063 |
computerguru-tenant-admin.sops.yaml |
defender |
ComputerGuru Defender Add-on | dbf8ad1a-54f4-4bb8-8a9e-ea5b9634635b |
computerguru-defender-addon.sops.yaml |
Deprecated (do not use): ComputerGuru - AI Remediation (fabb3421) — old single-app with 159 permissions including Defender ATP. Broke consent on tenants without MDE license. Retire/delete from portal when confirmed no active tenants depend on it.
When searching customer admin portals for a service principal (role assignments, app role assignments, CA exclusions), search by the display name for that tier (e.g., "ComputerGuru Security Investigator").
Per-tenant prerequisites
Graph API permissions alone are not enough. Most privileged operations require directory roles on the specific service principal in that tenant:
| Operation | App tier | Required directory role on that SP |
|---|---|---|
| Exchange REST read (Get-InboxRule, Get-Mailbox) | investigator-exo |
Exchange Administrator |
| Exchange REST write (Set-Mailbox, Remove-InboxRule) | exchange-op |
Exchange Administrator |
| Password reset, user property updates | user-manager |
User Administrator |
| MFA method reset | user-manager |
Authentication Administrator |
| Conditional Access reads/writes | tenant-admin |
Conditional Access Administrator OR Security Administrator |
| Teams policies | tenant-admin |
Teams Administrator |
How to assign a role to an SP in a customer tenant
- Sign into the customer's Entra admin center as Global Admin:
https://entra.microsoft.com/#@{customer-domain} - Identity -> Roles & admins -> All roles -> select the role (e.g., Exchange Administrator)
- Add assignments -> search by the app display name (e.g., "ComputerGuru Security Investigator") -> Assign (Active, permanent — service principals cannot activate eligible assignments)
Admin consent URLs
Each app must be individually consented in each customer tenant. Format:
https://login.microsoftonline.com/{tenant-id}/adminconsent?client_id={app-id}&redirect_uri=https://azcomputerguru.com&prompt=consent
Security Investigator (consent this first — needed for all breach checks):
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=bfbc12a4-f0dd-4e12-b06d-997e7271e10c&redirect_uri=https://azcomputerguru.com&prompt=consent
Exchange Operator (consent when remediation scope is needed):
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=b43e7342-5b4b-492f-890f-bb5a4f7f40e9&redirect_uri=https://azcomputerguru.com&prompt=consent
User Manager:
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=64fac46b-8b44-41ad-93ee-7da03927576c&redirect_uri=https://azcomputerguru.com&prompt=consent
Tenant Admin:
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=709e6eed-0711-4875-9c44-2d3518c47063&redirect_uri=https://azcomputerguru.com&prompt=consent
Defender Add-on (MDE-licensed tenants only — AADSTS650052 if no MDE license):
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id=dbf8ad1a-54f4-4bb8-8a9e-ea5b9634635b&redirect_uri=https://azcomputerguru.com&prompt=consent
The customer admin signs in as Global Admin, clicks Accept. Redirect lands on azcomputerguru.com — expected. Verify via /servicePrincipals/{sp-id}/appRoleAssignments (grants timestamped today confirm success).
Diagnosing "required scopes are missing"
Token returned 403 with "required scopes are missing in the token":
- Decode the JWT payload (2nd segment, base64url) and check the
rolesclaim. - If the expected scope is missing from
roles:- Confirm the scope is in the app manifest in the home tenant (saved, not just selected).
- Grant admin consent in the home tenant.
- Re-run the customer admin consent URL above for that specific app.
- If the scope IS in
rolesbut you still get 403: check for a missing directory role (see table above).
Diagnosing Exchange REST 403
- Wrong token scope: must request
https://outlook.office365.com/.default(useinvestigator-exoorexchange-optier, NOTinvestigator). - Missing Exchange Administrator role on the specific SP in that tenant.
- Propagation delay: newly assigned role can take up to 15 minutes to reach Exchange Online. If just assigned, wait and retry.
AADSTS650052 — service not licensed
If token request or API call returns AADSTS650052 referencing WindowsDefenderATP (fc780465): the tenant does not have an MDE license. Do not use the defender tier for this tenant. Security investigation proceeds with investigator + investigator-exo only.
Common, benign "failures" in sign-in logs
error 50140"Keep me signed in interrupt" — KMSI prompt, not a real failure.error 65001"has not consented to use the application" — fires during onboarding and before consent granted. IfappDisplayNamematches any ComputerGuru app, those are our own consent attempts, not attacker activity.error 50126from the sysadmin account during onboarding is typo/retry noise — checkipAddressagainst Mike's known IPs before flagging.
Tenants where apps are consented (as of 2026-04-20)
| Tenant | Tenant ID | Sec Inv | Exch Op | User Mgr | Tenant Admin | Defender | Exch Admin (Sec Inv) | User Admin (User Mgr) | Auth Admin (User Mgr) | Notes |
|---|---|---|---|---|---|---|---|---|---|---|
| Valleywide Plastering | 5c53ae9f... | old app only | — | — | — | — | — | old app only | — | Needs migration to new app suite |
| Dataforth | 7dfa3ce8... | old app only | — | — | — | — | old app only | old app only | — | Needs migration |
| Cascades Tucson | 207fa277-e9d8-4eb7-ada1-1064d2221498 | old app only | — | — | — | — | old app only | old app only | — | IdentityRiskyUser scope still not consented as of 2026-04-16 |
| Grabblaw | 032b383e-96e4-491b-880d-3fd3295672c3 | YES (2026-04-20) | — | YES (2026-04-20) | — | — | NOT ASSIGNED | NOT ASSIGNED | NOT ASSIGNED | Run onboard-tenant.sh |
| martylryan.com | (resolve via script) | — | — | YES (old app) | — | — | — | NOT ASSIGNED | NOT ASSIGNED | New SP not yet onboarded — run onboard-tenant.sh after Tenant Admin consent |
Migration note: Valleywide, Dataforth, and Cascades still use the old deprecated app. Next visit: consent Security Investigator + assign Exchange Administrator role to new SP, then retire old app consent.
Keep this table updated when rolling out to new tenants or migrating existing ones. Run onboard-tenant.sh after each consent and update the role columns from the script's final status output.