scp or roles claims with the exact method’s permissions table.Capture the complete failed request
Record the HTTP method and full Graph path without secrets, the API version, request headers relevant to behavior, response body, and Microsoft request identifiers. A 403 from GET and one from PATCH against the same resource can require different permissions.
Do not log the bearer token. Decode it only in an approved local tool or trusted administrative workflow, and capture the non-secret claims needed for comparison.
Test the authorization chain in order
| Layer | Evidence | Typical correction |
|---|---|---|
| Audience | aud identifies Microsoft Graph | Acquire the token for the correct resource |
| Permission type | Delegated scp or application roles | Use a flow supported by the endpoint and workload |
| Granted permission | Claim matches a permission supported for the exact method | Grant the narrowest documented permission and consent appropriately |
| Caller authority | Signed-in user or workload identity can perform the action | Assign the necessary workload or directory authority |
| License and service | Tenant and benefiting identity are entitled to the workload | Correct licensing or target the supported service |
| Resource boundary | Object, site, mailbox, tenant, or selected-resource grant is in scope | Fix the resource-specific assignment rather than broadening globally |
Distinguish delegated and application access
With delegated access, Graph evaluates both the app permission and what the signed-in user is allowed to do. A delegated scope does not elevate the user beyond their workload or directory authority. With application access, the service principal acts without a signed-in user and the token must contain application roles supported by that endpoint.
When an endpoint supports only one permission type or requires an additional workload role, switching from delegated to application access is not a harmless workaround. Confirm the method documentation and security impact first.
Read the error shape
- Authorization_RequestDenied or insufficient privileges: compare claims, user authority, and target boundary.
- insufficient_claims: investigate Conditional Access claims challenges instead of adding Graph scopes.
- Access denied to one object: inspect resource-specific permissions, ownership, or workload policy.
- Works for one tenant only: compare service-principal consent, licensing, policy, and target object state.
- Works in Graph Explorer but not the application: compare token type, app registration, consent, and signed-in identity—not only the URL.
Retest without creating privilege drift
- Use the exact method’s Microsoft Learn permissions table.
- Select the least-privileged permission for the intended access type.
- Apply consent through the approved tenant process.
- Acquire a new token and verify the expected claim is present.
- Retest the same request against the same target.
- Remove experimental broad grants that were not required.
A successful call proves that authorization was sufficient for that request; it does not prove every granted permission was necessary. Record the final permission set and why each grant remains.
