Scopes & Permissions

Scopes define what your application can access using an access token. Understanding scopes is critical for requesting the right permissions and troubleshooting authorization issues.


What Are Scopes?

A scope is a permission that grants access to specific resources or operations in an API.

Format

https://api.example.com/.default
https://graph.microsoft.com/User.Read
https://management.azure.com/user_impersonation

Parts:

  • Resource URI: The API you’re accessing (https://graph.microsoft.com)
  • Permission: The specific capability (User.Read, .default)

Common Scope Patterns

Microsoft Graph API

1
2
3
4
5
6
7
8
9
# Read user profile
https://graph.microsoft.com/User.Read

# Read user profile and email
https://graph.microsoft.com/User.Read
https://graph.microsoft.com/Mail.Read

# All configured permissions
https://graph.microsoft.com/.default

Azure Management API

1
2
3
4
5
# Azure Resource Manager access
https://management.azure.com/.default

# With user impersonation
https://management.azure.com/user_impersonation

Custom APIs

1
2
3
4
5
# Your custom API
https://api.contoso.com/.default

# Specific scopes
api://12345678-1234-1234-1234-123456789abc/access_as_user

Azure Key Vault

1
https://vault.azure.net/.default

Azure Storage

1
https://storage.azure.com/.default

The .default Scope

What It Means

The .default suffix requests all permissions configured in your app registration.

Example: If your app is configured with:

  • User.Read
  • Mail.Read
  • Calendars.Read

Then requesting https://graph.microsoft.com/.default includes all three.

When to Use

Use .default when:

  • Working with service principals (Client Credentials flow)
  • You want all configured permissions
  • Building automation scripts

⚠️ Avoid .default when:

  • Requesting minimal permissions
  • Building user-facing apps (use explicit scopes)
  • Different operations need different scopes

Example

1
2
3
# Request all configured Graph permissions
entratool get-token -p service-principal \
  --scope "https://graph.microsoft.com/.default"

Profile Scopes vs Runtime Scopes

Profile Scopes

Scopes stored in your profile configuration:

1
2
3
4
{
  "name": "my-profile",
  "scope": "https://graph.microsoft.com/User.Read Mail.Read"
}

Used by default when running:

1
entratool get-token -p my-profile

Runtime Scope Override

Override profile scopes with --scope or -s:

1
2
3
# Override to request different scope
entratool get-token -p my-profile \
  --scope "https://graph.microsoft.com/Calendar.Read"

Use cases:

  • Different operations need different permissions
  • Testing with minimal scopes
  • Temporary scope changes without editing profile

Multiple Scopes

Space-Separated Format

1
2
entratool get-token -p myprofile \
  --scope "https://graph.microsoft.com/User.Read Mail.Read Calendars.Read"

Comma-Separated Format

1
2
entratool get-token -p myprofile \
  --scope "https://graph.microsoft.com/User.Read,Mail.Read,Calendars.Read"

The tool normalizes both formats automatically.


Scope Requirements by Flow

Client Credentials Flow

Requires: Application permissions configured in Azure Portal

1
2
3
# App registration → API permissions → Add permission
# Select: Application permissions (not Delegated)
# Grant admin consent ✓

Example scopes:

1
2
https://graph.microsoft.com/.default
https://management.azure.com/.default

User-Interactive Flows

Requires: Delegated permissions configured in Azure Portal

1
2
3
# App registration → API permissions → Add permission
# Select: Delegated permissions
# User consent required (or admin consent)

Example scopes:

1
2
https://graph.microsoft.com/User.Read
https://graph.microsoft.com/Mail.Read

Inspecting Token Scopes

Use inspect to see what scopes are included in your token:

1
entratool inspect -t "eyJ0eXAiOiJKV1QiLCJhbGci..."

Output:

1
2
3
4
{
  "scp": "User.Read Mail.Read",
  "roles": ["User.Read.All"]
}

Fields:

  • scp: Delegated permissions (user context)
  • roles: Application permissions (app context)

Common Scope Patterns

Reading User Data

1
2
3
4
# Microsoft Graph
https://graph.microsoft.com/User.Read          # Basic profile
https://graph.microsoft.com/User.Read.All      # All users (admin)
https://graph.microsoft.com/User.ReadWrite     # Modify profile

Email Access

1
2
3
https://graph.microsoft.com/Mail.Read          # Read email
https://graph.microsoft.com/Mail.Send          # Send email
https://graph.microsoft.com/Mail.ReadWrite     # Full email access

Calendar Access

1
2
https://graph.microsoft.com/Calendars.Read
https://graph.microsoft.com/Calendars.ReadWrite

Azure Resource Management

1
2
https://management.azure.com/.default
https://management.azure.com/user_impersonation

SharePoint

1
2
https://graph.microsoft.com/Sites.Read.All
https://graph.microsoft.com/Files.ReadWrite.All

Scope Configuration

Setting Scopes in Profile

During Creation

1
2
3
entratool config create
# ... prompts ...
Scope: https://graph.microsoft.com/.default

During Edit

1
2
3
entratool config edit -p myprofile
# Select: Scope
# Enter new: https://management.azure.com/.default

Manual JSON Edit

Edit ~/.entratool/profiles.json:

1
2
3
4
5
6
7
8
{
  "profiles": [
    {
      "name": "myprofile",
      "scope": "https://graph.microsoft.com/User.Read Mail.Read"
    }
  ]
}

Scope Troubleshooting

“Invalid scope”

Cause: Scope format is incorrect

Fix:

1
2
3
4
5
# ❌ Wrong
--scope "User.Read"

# ✓ Correct
--scope "https://graph.microsoft.com/User.Read"

Cause: User hasn’t consented to delegated permissions

Fix:

  1. Use interactive flow (Authorization Code or Interactive Browser)
  2. User will be prompted to consent
  3. Or: Admin grants consent in Azure Portal

“AADSTS70011: Invalid scopes”

Cause: Scope not configured in app registration

Fix:

  1. Go to Azure Portal → App registrations
  2. Select your app → API permissions
  3. Add the required permission
  4. Grant admin consent (if Application permission)

“Insufficient privileges”

Cause: Token has scope but user/app lacks underlying permission

Fix:

  1. For users: Assign appropriate role (e.g., Global Reader)
  2. For apps: Grant admin consent for Application permissions
  3. Verify permission configuration in Azure Portal

Best Practices

✅ Principle of Least Privilege

Request only the scopes you need:

1
2
3
4
5
# ❌ Over-privileged
--scope "https://graph.microsoft.com/.default"

# ✓ Minimal scopes
--scope "https://graph.microsoft.com/User.Read Mail.Read"

✅ Use Explicit Scopes for User Apps

For user-facing applications, request specific scopes:

1
2
entratool get-token -p user-app \
  --scope "https://graph.microsoft.com/User.Read"

✅ Use .default for Service Principals

For automation and service accounts:

1
2
entratool get-token -p automation \
  --scope "https://graph.microsoft.com/.default"

✅ Separate Profiles for Different Scopes

Create profiles for different scenarios:

1
2
3
4
5
# Profile: graph-readonly
scope: https://graph.microsoft.com/User.Read

# Profile: graph-admin
scope: https://graph.microsoft.com/.default

❌ Don’t Hard-Code Tokens

Always request fresh tokens with appropriate scopes:

1
2
3
# ✓ Request token per operation
TOKEN=$(entratool get-token -p myprofile --scope "...")
curl -H "Authorization: Bearer $TOKEN" ...

Scope Discovery

Finding Available Scopes

  1. Azure Portal:

    • App registrations → API permissions → Add permission
    • Browse Microsoft APIs or your custom APIs
    • View available Delegated and Application permissions
  2. Microsoft Graph Explorer:

  3. API Documentation:

Using discover Command

1
entratool discover -t "eyJ0eXAiOiJKV1Qi..."

Output shows:

  • Token audience
  • Issued scopes
  • Roles
  • Expiration time

Scope Combinations

Common Combinations

Graph API Read-Only Access

1
--scope "https://graph.microsoft.com/User.Read Mail.Read Calendars.Read"

Graph API Admin Access

1
--scope "https://graph.microsoft.com/.default"

Azure Management + Graph

1
2
3
# Request separately (different audiences)
TOKEN_GRAPH=$(entratool get-token -p graph --scope "https://graph.microsoft.com/.default")
TOKEN_AZURE=$(entratool get-token -p azure --scope "https://management.azure.com/.default")

Next Steps