How To

How to Fix “403 Access Denied” for SharePoint Sites.Selected Applications (Complete Microsoft Graph Troubleshooting Guide)

How to Fix “403 Access Denied” for SharePoint Sites.Selected Applications (Complete Microsoft Graph Troubleshooting Guide)

Microsoft introduced the Sites.Selected application permission to help organizations follow the principle of least privilege when accessing SharePoint Online.

Unlike Sites.Read.All, Sites.ReadWrite.All, or Sites.FullControl.All, which grant an application access to every SharePoint site in a tenant, Sites.Selected allows administrators to grant access only to specific SharePoint sites.

This is the recommended approach for Azure Functions, Logic Apps, Power Automate, background services, and other app-only integrations.

However, many administrators encounter the same frustrating issue.

“I have granted Sites.Selected permission, assigned the site permission, granted admin consent, but my application still receives 403 Access Denied.”

If you’ve experienced this problem, you’re not alone.

This article walks through the complete setup process and, more importantly, the troubleshooting steps we used during a real production investigation to identify and resolve the SharePoint Sites.Selected 403 Access Denied issue.

How Sites.Selected Works?

Many administrators assume this is enough:

App Registration

Microsoft Graph
    Sites.Selected

Admin Consent

Unfortunately, it isn’t. Sites.Selected does not automatically grant access to any SharePoint site.

Instead, it simply allows administrators to grant access later.

Think of it like this:

Tenant

├── HR
├── Finance
├── Engineering
└── InfoSec

App Registration
        │
        └── Sites.Selected

Result:

No access to any SharePoint site

The application still cannot read or write SharePoint content.

The Two-Step Permission Model

Microsoft uses a two-step security model.

Step 1

Grant the application:

Microsoft Graph

Application Permission

Sites.Selected

Grant Admin Consent.

The application still has zero SharePoint access.

Step 2

Grant the application permission to a specific SharePoint site.

Example:

https://contoso.sharepoint.com/sites/InfoSecDocumentGovernanceRepository

Only after assigning the site permission can the application access SharePoint.

Required API Permissions

For Microsoft Graph-based applications, the App Registration should have:

Microsoft Graph

Application

Sites.Selected

If your application also uses the SharePoint REST API (/_api/...) or SharePoint SDKs, you should also grant:

SharePoint

Application

Sites.Selected

Grant Admin Consent for both permissions.

SharePoint Sites.Selected 403 Access Denied

Common Symptoms

You may receive errors like:

403 Access Denied

or

401 Unauthorized

or

AADSTS7000215
Invalid client secret provided

or

Either scp or roles claim need to be present.

Each error points to a different layer of the authentication process.

Prerequisites

Before continuing, ensure:

  • Azure App Registration exists.
  • Microsoft Graph Sites.Selected permission added.
  • SharePoint Sites.Selected permission added (recommended if using SharePoint REST).
  • Admin Consent granted.
  • Microsoft Graph PowerShell installed.
  • SharePoint Administrator or Global Administrator permissions.

Install the Graph SDK.

Install-Module Microsoft.Graph -Scope CurrentUser

Connect to Microsoft Graph.

Connect-MgGraph -Scopes "Sites.FullControl.All"

Granting Site Permission

Retrieve the SharePoint Site.

$SiteUrl = "contoso.sharepoint.com:/sites/SharePointSiteName"

$site = Get-MgSite -SiteId $SiteUrl

Grant permission.

$params = @{
    roles = @("write")
    grantedToIdentities = @(
        @{
            application = @{
                id = "YOUR-APP-ID"
                displayName = "My Automation"
            }
        }
    )
}

New-MgSitePermission `
    -SiteId $site.Id `
    -BodyParameter $params

Verify the Permission

Always verify the assignment.

Get-MgSitePermission -SiteId $site.Id

Expected:

Roles

write

Application

My Automation

Real-World Troubleshooting

Now comes the part that most documentation skips.

Our application still returned:

403 Access Denied

even though:

  • Admin Consent was granted.
  • Site permission existed.
  • App Registration looked correct.

The problem turned out to be something completely different.

Step 1 — Verify Authentication

Before troubleshooting SharePoint, verify authentication.

Acquire a token.

Expected:

HTTP Status : 200

If authentication fails:

AADSTS7000215

the issue is not SharePoint.

Common causes:

  • Wrong Client Secret
  • Secret ID used instead of Secret Value
  • Expired Secret

Step 2 — Decode the JWT

Never assume your application is using the correct App Registration.

Decode the JWT.

Example:

{
    "appid": "e52e3a09-1bc1-4fa8-bdc2-ca1af9ddf39d",
    "roles": [
        "Sites.Selected"
    ],
    "aud": "https://graph.microsoft.com"
}

This immediately tells you:

  • Which application requested the token.
  • Whether the token contains Sites.Selected.
  • Whether the audience is Microsoft Graph.

Step 3 — Verify the App ID

This was the root cause during our investigation.

We granted SharePoint permission to:

6c03b235-c060-4e9a-bb98-4e86218c5f30

But the application authenticated as:

e52e3a09-1bc1-4fa8-bdc2-ca1af9ddf39d

Graph correctly returned:

403 Access Denied

because the application requesting the token had never been granted access.

Always compare:

JWT appid

vs

GrantedToIdentities.Application.Id

If they don’t match, SharePoint will reject the request.

Step 4 — Test Site Access

Never start with folders.

Start with the site.

GET

/sites/{site-path}

Expected:

200 OK

Then:

GET

/sites/{site-id}

Expected:

200 OK

Then:

GET

/sites/{site-id}/drives

Expected:

200 OK

Only after those succeed should you attempt folder operations.

Step 5 — List Document Libraries

Expected output:

Documents

Teams Wiki Data

Preservation Hold Library

If this works, your application has successfully accessed SharePoint.

Why Does GET /permissions Return 403?

Many administrators think this indicates a configuration issue.

It usually doesn’t.

Applications granted Sites.Selected can access SharePoint content but cannot enumerate or manage site permissions.

Therefore:

GET

/sites/{site-id}/permissions

may return:

403 Access Denied

This is expected.

Only administrators or applications with broader permissions can retrieve site permission assignments.

Diagnostic Flow

403 Access Denied
        │
        ▼
Can you obtain an OAuth token?
        │
   No ─────────► Authentication Issue
        │
       Yes
        │
        ▼
Decode JWT
        │
AppId correct?
        │
   No ─────────► Wrong App Registration
        │
       Yes
        │
        ▼
Roles contain Sites.Selected?
        │
   No ─────────► Missing API Permission
        │
       Yes
        │
        ▼
Retrieve Site
        │
403?
        │
        ▼
Verify Site Permission Assignment
        │
        ▼
Permission Exists?
        │
No ─────────► Grant Site Permission
        │
Yes
        │
        ▼
Retrieve Drives
        │
200?
        │
Yes
        │
        ▼
Application Successfully Connected

Common Mistakes

Wrong App Registration

The most common cause.

Always compare:

JWT AppId

vs

Granted Site Permission AppId

Using Secret ID

Never use:

Secret ID

Always use:

Secret Value

Reusing Old Tokens

Always request a new access token after:

  • Admin Consent
  • New Client Secret
  • New Site Permission

Forgetting Site Permission

Sites.Selected alone grants no SharePoint access.

You must grant permission to each site individually.

Wrong Site URL

Ensure the URL exactly matches the site.

Correct

/sites/SharePointSiteName

Not:

/production

Assuming 403 on /permissions Means Failure

It doesn’t.

Applications with Sites.Selected typically cannot enumerate permission assignments.

Security Best Practices

Avoid granting:

  • Sites.Read.All
  • Sites.ReadWrite.All
  • Sites.FullControl.All

unless absolutely necessary.

Instead:

  • Use Sites.Selected.
  • Grant access only to the required site.
  • Assign the minimum required role (read or write).

This significantly reduces the impact if application credentials are compromised.

Conclusion

The biggest misconception about Sites.Selected is believing that granting the API permission automatically grants SharePoint access.

It doesn’t.

A working configuration requires all of the following:

  • Microsoft Graph Sites.Selected
  • (Optional) SharePoint Sites.Selected if using SharePoint REST
  • Admin Consent
  • Site-specific permission assignment
  • Correct Client ID and Client Secret
  • A freshly issued access token
  • Verification that the JWT appid matches the application that was granted access

During our investigation, the configuration was correct, but the application was requesting an access token for a different App Registration than the one that had been granted site access. Comparing the JWT appid with the SharePoint permission assignment immediately revealed the mismatch. Once the correct application was used, the site and document libraries became accessible through Microsoft Graph without requiring any tenant-wide SharePoint permissions.

This approach follows Microsoft’s least-privilege security model while providing a repeatable troubleshooting process for administrators who encounter 403 Access Denied when working with Sites.Selected.