Skip to content

Repository to Document and learn Graph API and script collection

Notifications You must be signed in to change notification settings

Jhope188/LearnGraphAPI

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

153 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Learn Microsoft Graph API → Microsoft Graph API Cheat Sheet

Purpose: A practical, engineer-focused reference for discovering and using Microsoft Graph endpoints that return Entra ID data.

Use this as a printable reference, a living document, or a baseline for building your own internal Graph catalog.

📚 Table of Contents

What Is Microsoft Graph?

Microsoft Graph is Microsoft’s unified REST API that provides a single endpoint to access data and actions across Microsoft cloud services.

Instead of calling many different service-specific APIs (Azure AD, Exchange, SharePoint, Intune, Teams), Microsoft Graph exposes them through one consistent API surface.

At a high level, Microsoft Graph allows you to:

  • Read and manage Entra ID (Azure AD) objects (users, groups, devices)
  • Configure authentication and security policies
  • Access Microsoft 365 data (mail, calendar, files)
  • Manage Intune / device management
  • Query audit logs, sign-ins, and reports

The Microsoft Graph Endpoint

Graph API Breakdown

All Microsoft Graph calls use a single base URL:

https://graph.microsoft.com

You then choose an API version:

  • v1.0 → production, stable
  • beta → preview, newest features (may change)

Example:

https://graph.microsoft.com/v1.0/me

How Microsoft Graph Is Structured

Microsoft Graph is built on REST + OData principles.

Key concepts:

  • Resources → users, groups, devices, policies
  • Relationships → members, owners, assignments
  • Actions → reset password, assign license

Example resource path:

/users/{id}/memberOf

Authentication: How You Are Allowed to Call Graph

Microsoft Graph uses OAuth 2.0 access tokens issued by Entra ID.

You must authenticate using one of these identities:

  • A signed-in user (delegated permissions)
  • An application / service principal (application permissions)

Delegated vs Application Permissions

Permission type Runs as Typical use
Delegated Signed-in user Graph Explorer, user tools
Application App identity Automation, background jobs

Ways to Interact and Keep up to date with Graph

Digging Into the Graph Documentation

https://learn.microsoft.com/en-us/graph/api/overview?view=graph-rest-1.0&viewFallbackFrom=graph-rest-1.0%2F%3Fwt.mc_id%3Dmsgraph_inproduct_graphexhelp

Getting familiar with upcoming Microsoft Changes

https://developer.microsoft.com/en-us/graph/changelog/?filterBy=beta,Identity%20and%20access

Daniel Bradley MS Docs Tracker

https://msdocstracker.com/#graph

Lokka

https://lokka.dev/docs/install


Ways to Call Microsoft Graph

1. Graph Explorer (Easiest)

Graph Explorer is a browser-based tool for testing Graph requests.

  • Runs as you
  • Handles tokens automatically
  • Best for learning and discovery

Example:

GET https://graph.microsoft.com/v1.0/me

Graph Explorer

https://aka.ms/ge


2. REST API (Raw HTTP)

Microsoft Graph is fundamentally an HTTP REST API.

Example:

GET /v1.0/users
Authorization: Bearer {access_token}

Used when:

  • Building custom apps
  • Calling Graph from scripts or services

3. PowerShell (Microsoft Graph SDK)

Microsoft provides PowerShell modules that wrap Graph calls.

Example:

Connect-MgGraph -Scopes User.Read.All
Get-MgUser

PowerShell is ideal for:

  • Admin automation
  • Reporting
  • Bulk operations

4. SDKs (C#, Python, JavaScript)

Microsoft provides SDKs that abstract raw HTTP calls.

Supported languages include:

  • C# / .NET
  • JavaScript / TypeScript
  • Python
  • Java

SDKs handle:

  • Authentication
  • Paging
  • Serialization

Common HTTP Methods Used in Graph

Method Purpose
GET Read data
POST Create objects or trigger actions
PATCH Update existing objects
DELETE Remove objects

Example:

PATCH /v1.0/users/{id}

Microsoft Graph /me and /$value – Quick Reference

Base /me endpoint

GET https://graph.microsoft.com/v1.0/me

Returns the signed-in user’s directory object as JSON.


What does /$value mean?

In Microsoft Graph, /$value tells the service:

Return the raw value of the resource, not the JSON wrapper.

It is used when the resource represents:

  • A binary stream (photo, file)
  • A primitive value (string, number)
  • A collection of primitive values

GraphExplorerMe


Where /$value works with /me

User profile photo

GET /v1.0/me/photo/$value
  • Returns raw binary image (JPEG/PNG)
  • No JSON response
  • Browser downloads or renders the image

Profile photo size variants

GET /v1.0/me/photos/48x48/$value

Primitive property example

GET /v1.0/me/mailboxSettings/timeZone/$value

Returns a plain string, not JSON metadata.


Where /$value does NOT work

GET /v1.0/me/$value

❌ Invalid because /me is a complex object, not a primitive or stream.

Typical error:

{
  "error": {
    "code": "BadRequest",
    "message": "Cannot use $value on a complex type."
  }
}

Mental model

Resource type /$value supported
Binary (photo, file)
Primitive (string, int)
Primitive collection
Complex object (user)
Navigation object (manager, memberOf)

Common /me + /$value patterns

Endpoint Result
/me/photo/$value Raw profile image
/me/photos/{size}/$value Sized photo
/me/mailboxSettings/timeZone/$value Plain string
/me/manager/$value ❌ Not supported

Permissions

  • User.Read (basic signed-in user)
  • User.Read.All (reading other users)

TL;DR

/$value = raw output
No JSON wrapper
Use for photos, files, and primitive values
Never use it on /me itself

Microsoft Graph Identity – Quick Reference

🔐 Identity Core

GET /v1.0/users
GET /v1.0/groups
GET /v1.0/devices
GET /v1.0/directoryObjects

Common User Queries

GET /v1.0/users/{id}
GET /v1.0/users/{id}/memberOf
GET /v1.0/users/{id}/transitiveMemberOf
GET /v1.0/users/{id}/manager
GET /v1.0/users/{id}/directReports
GET /v1.0/users/{id}/registeredDevices
GET /v1.0/users/{id}/ownedDevices
GET /v1.0/users/{id}/authentication/methods

Get the Users Object ID

https://graph.microsoft.com/v1.0/users/user1@acme.com?$select=userPrincipalName,id

Get the users Roles Assigned

https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments?$filter=principalId eq 'userobjectid'

Get the Role ID Name for the User

https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions/{roleDefinitionId}?$select=id,displayName,description

Groups

GET /v1.0/groups/{id}
GET /v1.0/groups/{id}/members
GET /v1.0/groups/{id}/transitiveMembers
GET /v1.0/groups/{id}/owners
GET v/1.0/groups/$count (Count requires a consistency level header)
GET https://graph.microsoft.com/v1.0/groups/$count?$filter=securityEnabled eq true

HEADER:
ConsistencyLevel: eventual

NOTE This is a more real world scenario to pull back the count for total security groups

Get https://graph.microsoft.com/v1.0/groups/$count?$filter=startswith(displayName,'ACME')

HEADER:
ConsistencyLevel: eventual

Consistency Level Example

NOTE This is a more real world scenario to pull back the count for total groups that meet a naming convention

Return all Groups by DisplayName


https://graph.microsoft.com/v1.0/groups?$select=displayName

Expand Groups and Select Owner property


https://graph.microsoft.com/v1.0/groups?$select=displayName&$expand=owners($select=displayName,userPrincipalName)

Get All Groups by DisplayName and type then filter on Dynamic

https://graph.microsoft.com/beta/groups?$select=displayname,grouptypes&$filter=groupTypes/any(c:c eq 'DynamicMembership')

Filter Groups by names that start with ACME-AUTH


https://graph.microsoft.com/v1.0/groups?$filter=startswith(displayName,'ACME-AUTH')&$select=id,displayName
What this does

/groups → queries all groups

$filter=startswith(displayName,'ACME-AUTH') → returns only groups whose names start with ACME-AUTH

$select=id,displayName → returns only: id (object ID)/displayName

Have to switch to Beta to report on Group Owner value

https://graph.microsoft.com/beta/groups/0e4b5629-83d8-4aae-a5cb-5f0c31836116?$expand=owners
##Grab the user account object ID: Cant patch a group owner with UserPrincipalName

https://graph.microsoft.com/beta/users/jhope@acmebaseline.onmicrosoft.com?$select=id

##Now its multiple steps to patch the odata with the updated owner

POST /v1.0/groups/{GROUP_OBJECT_ID}/owners/$ref
> Replace Group Object with the ID Above

Request body update with odata and user object id:

{
  "@odata.id": "https://graph.microsoft.com/v1.0/users/USER_OBJECT_ID"
}

{
  "@odata.id": "https://graph.microsoft.com/v1.0/users/eaf72a07-8d1f-4324-b8dd-35d906b86d6d"
}

Check for the updated group owner information

GET https://graph.microsoft.com/beta/groups/0e4b5629-83d8-4aae-a5cb-5f0c31836116?$expand=owners

How to filter better for just the Owner Display name and id
https://graph.microsoft.com/beta/groups/0e4b5629-83d8-4aae-a5cb-5f0c31836116?$select=id,displayName&$expand=owners($select=id,displayName)


NOTE: Groups self service sign up features:
https://learn.microsoft.com/en-us/entra/identity/users/groups-self-service-management?WT.mc_id=Portal-Microsoft_AAD_IAM#group-settings
Locate the Group to convert:
https://graph.microsoft.com/v1.0/groups?$filter=startswith(displayName,'AD')&$select=id,displayName

Document Group ID: (AD-AVDUsers)
GET https://graph.microsoft.com/v1.0/groups/abc11e5a-7aa8-4412-932d-f6d7c946cf7e/onPremisesSyncBehavior?$select=isCloudManaged

fce75b28-01cd-4270-b529-4989b1daf0db

Change the SOA from OnPrem to Cloud
PATCH https://graph.microsoft.com/v1.0/groups/abc11e5a-7aa8-4412-932d-f6d7c946cf7e/onPremisesSyncBehavior

REQUEST BODY:
{
     "isCloudManaged": true
}  

Group SOA https://learn.microsoft.com/en-us/entra/identity/hybrid/how-to-group-source-of-authority-configure


ConsistencyLevel Eventual in Microsoft Graph

What Is ConsistencyLevel: eventual?

ConsistencyLevel: eventual is an HTTP request header that enables advanced queries in Microsoft Graph by allowing slightly delayed data.

ConsistencyLevel: eventual

Why It Exists

Microsoft Graph runs across globally distributed services. To support scalability, some queries require eventual consistency.

What It Enables

  • $count
  • startswith()
  • endswith()
  • contains()
  • Advanced $filter queries

Example

GET https://graph.microsoft.com/v1.0/groups?$filter=startswith(displayName,'ACME')&$count=true
ConsistencyLevel: eventual

Practical Meaning

  • Data may lag briefly
  • Results converge quickly
  • Ideal for reporting, auditing, and inventory

Security Impact

None. Permissions and authorization remain unchanged.

Key Takeaways

  • Required for $count and advanced filters
  • Trades immediacy for scalability
  • Essential for tenant-wide analysis

Common Use Cases

Typical scenarios where these Microsoft Graph query patterns are used:

  • Tenant-wide reporting and inventory
  • Auditing Entra ID objects (users, groups, devices)
  • Conditional Access and security posture reviews
  • License usage and assignment analysis
  • CI/CD validation and drift detection
  • Large-scale automation across tenants

Common Mistakes

Common pitfalls when working with Microsoft Graph queries:

  • Forgetting to include ConsistencyLevel: eventual when using $count
  • Assuming real-time accuracy when using eventual consistency
  • Treating collection properties as single values instead of using any()
  • Over-fetching data instead of using $select
  • Not testing queries in both v1.0 and beta endpoints

Why $count Requires Eventual Consistency

Counting objects in Microsoft Graph often requires:

  • Scanning multiple partitions
  • Aggregating results across regions
  • Querying large, distributed datasets

Strong consistency cannot guarantee performance at this scale.

By using ConsistencyLevel: eventual, Microsoft Graph can efficiently compute counts while maintaining global scalability.

This tradeoff enables accurate reporting while preserving service reliability.


Understanding the any() Function in Microsoft Graph Queries

What does /any(c:c eq 'DynamicMembership') do?

Example Query

https://graph.microsoft.com/beta/groups?$select=displayName,groupTypes&$filter=groupTypes/any(c:c eq 'DynamicMembership')

Plain English Explanation

This filter means:

  • Return only groups where the groupTypes collection contains the value DynamicMembership.
  • This query retrieves only dynamic groups from Microsoft Entra ID.

Why is any() Required?

  • The groupTypes property is not a single value, it is a collection (array).
  • Examples of values returned by Microsoft Graph:
"groupTypes": []
"groupTypes": ["Unified"]
"groupTypes": ["DynamicMembership"]
"groupTypes": ["Unified", "DynamicMembership"]
  • Because groupTypes is a collection, you cannot filter it like this:
groupTypes eq 'DynamicMembership'
  • OData requires evaluating each element in the collection, which is why the any() function is required.

Breaking Down the Syntax

groupTypes/any(c:c eq 'DynamicMembership')
Component Description
groupTypes The collection property on the group object
any(...) OData function that evaluates elements in a collection
c Temporary variable representing each element
c eq 'DynamicMembership' Condition applied to each element

How to read this expression:

  • For each value c in groupTypes, return the group if any value equals DynamicMembership.
  • If at least one element matches, the group is included in the response.

What Groups Does This Query Return?

This query returns:

  • Dynamic Security Groups
  • Dynamic Microsoft 365 Groups

Both group types include the following value:

"groupTypes": ["DynamicMembership"]

Microsoft 365 dynamic groups may also include:

"groupTypes": ["Unified", "DynamicMembership"]

Common Filter Variations

All Dynamic Groups

groupTypes/any(c:c eq 'DynamicMembership')

Microsoft 365 (Unified) Groups Only

groupTypes/any(c:c eq 'Unified')

Dynamic Microsoft 365 Groups Only

groupTypes/any(c:c eq 'Unified') and groupTypes/any(c:c eq 'DynamicMembership')

Non-Dynamic Groups

not(groupTypes/any(c:c eq 'DynamicMembership'))

Why This Matters in Real-World Graph Usage

The any() function is used throughout Microsoft Graph when filtering collection properties, including:

  • assignedLicenses/any(...)
  • proxyAddresses/any(...)
  • members/any(...)
  • authenticationMethods/any(...)

Understanding any() allows you to:

  • Reverse engineer Entra ID, Intune, and Microsoft 365 portal behavior
  • Write precise and safe Microsoft Graph queries
  • Avoid targeting unintended objects
  • Confidently filter large datasets at scale

Key Takeaways

  • groupTypes is a collection, not a single value
  • any() checks whether at least one element matches a condition
  • This query returns only dynamic groups
  • Mastering any() is essential for effective Microsoft Graph filtering

Applications and Enterprise Apps

App Registrations

GET /v1.0/applications
GET /v1.0/applications/{id}

Enterprise Applications (Service Principals)

GET /v1.0/servicePrincipals
GET /v1.0/servicePrincipals/{id}
GET /v1.0/servicePrincipals/{id}/appRoleAssignments
GET /v1.0/servicePrincipals/{id}/oauth2PermissionGrants

Conditional Access and Protection

GET /v1.0/identity/conditionalAccess/policies
GET /v1.0/identity/conditionalAccess/namedLocations
GET /v1.0/identity/conditionalAccess/authenticationStrengths
https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies

Response: Returns all Conditional Access policies with full details including:

Policy ID, display name, state (enabled/disabled/report-only)
Conditions (users, groups, applications, locations, platforms, etc.)
Grant controls (MFA, compliant device, approved app, etc.)
Session controls (sign-in frequency, persistent browser, etc.)
Authentication strength requirements

?$select=id,displayName,state
?$filter=state eq 'enabled'
(https://graph.microsoft.com/beta/identity/conditionalAccess/policies?$select=id,displayName,state&$filter=startswith(displayName,'ACME')&$orderby=displayName)

You’re running into a Microsoft Graph beta limitation / bug, not a syntax issue on your side.

For Conditional Access policies, the /beta/identity/conditionalAccess/policies endpoint does not reliably enforce startswith() server-side. When this happens, Graph returns all policies and applies only partial or no filtering internally — which is why you’re seeing policies that do not start with ACME.

Key point (important)

There is currently no 100% reliable server-side way to return only CA policies whose displayName starts with a string.

> **Rule**: If the Entra blade is under **Protection**, the Graph path usually starts with `/identity`.

Authentication and Passwordless

Tenant-wide Authentication Policies

GET /v1.0/authenticationMethodsPolicy
GET /beta/authenticationMethodsPolicy
GET /beta/policies/authenticationMethodsPolicy
GET /beta/policies/authorizationPolicy

Policies/AuthorizationsPolicy

  • defaultUserRolePermissions (create apps, security groups, tenants)
  • allowInvitesFrom (guest invite restrictions)
  • allowUserConsentForRiskyApps
  • blockMsolPowerShell
  • allowedToUseSSPR
  • allowEmailVerifiedUsersToJoinOrganization
  • guestUserRoleId

Permissions required: Policy.Read.All

Policies/AuthenticationMethodsPolicy

**This endpoint returns a single singleton policy, not a collection.**

So:

❌ $filter

❌ $select for sub-objects

❌ “enabled only”

…are not supported, because there is only one policy object per tenant.

Getting Familiar with different Authentication types

https://learn.microsoft.com/en-us/graph/api/resources/authenticationmethod?view=graph-rest-beta

FIDO2 & Passkeys

GET /beta/authenticationMethodsPolicy/authenticationMethodConfigurations

GET /beta/authenticationMethodsPolicy/authenticationMethodConfigurations/FIDO2
GET /beta/authenticationMethodsPolicy/authenticationMethodConfigurations/microsoftAuthenticator
GET /beta/authenticationMethodsPolicy/authenticationMethodConfigurations/temporaryAccessPass
GET /beta/authenticationMethodsPolicy/authenticationMethodConfigurations/sms
GET /beta/authenticationMethodsPolicy/authenticationMethodConfigurations/voice
GET /beta/authenticationMethodsPolicy/authenticationMethodConfigurations/email
GET /beta/authenticationMethodsPolicy/authenticationMethodConfigurations/softwareOath
GET /beta/authenticationMethodsPolicy/authenticationMethodConfigurations/hardwareOath
GET /beta/authenticationMethodsPolicy/authenticationMethodConfigurations/x509Certificate
authenticationMethodsPolicy
└── authenticationMethodConfigurations
    ├── fido2
    ├── microsoftAuthenticator
    ├── temporaryAccessPass
    ├── softwareOath
    ├── hardwareOath
    ├── sms
    ├── voice
    ├── email
    └── x509Certificate

Beta vs V1 Endpoint with FIDO2

🔑 Permissions required

Read: Policy.Read.AuthenticationMethod

Write: Policy.ReadWrite.AuthenticationMethod

(Global Admin or Authentication Policy Admin role required)

Per-user Authentication Methods

GET /v1.0/users/{id}/authentication/methods

Audit Logs and Reports

Audit Logs

GET /v1.0/auditLogs/signIns
GET /v1.0/auditLogs/directoryAudits

Reports

GET /v1.0/reports/authenticationMethodsUserRegistrationDetails
GET /v1.0/reports/credentialUserRegistrationDetails
GET /v1.0/reports/signInActivity

Identity Governance

Access Reviews

GET /v1.0/identityGovernance/accessReviews/definitions
GET /v1.0/identityGovernance/accessReviews/instances

Entitlement Management

GET /v1.0/identityGovernance/entitlementManagement/catalogs
GET /v1.0/identityGovernance/entitlementManagement/accessPackages

Tenant and Directory Settings

GET /v1.0/organization
GET /v1.0/domains
GET /v1.0/directoryRoles
GET /v1.0/subscribedSkus
GET /beta/settings
GET /beta/directorySettingTemplates

Microsoft Graph /beta/settings Endpoint

What Does /beta/settings Show?

GET https://graph.microsoft.com/beta/settings

The /settings endpoint in Microsoft Graph exposes tenant-wide directory settings in Microsoft Entra ID (Azure AD).

These settings control global identity and directory behavior and are represented as directorySetting objects.

They are not the same as users, groups, Conditional Access policies, or Intune configurations.


What Types of Settings Live Here?

The endpoint returns objects of type directorySetting.

Each setting:

  • Is created from a directorySettingTemplate
  • Has a displayName
  • Contains configurable name/value pairs

Common Categories of Settings

Depending on what has been explicitly configured in the tenant, you may see settings related to:

Security & Identity

  • User consent behavior
  • Password and sign-in related defaults
  • Guest access restrictions

Group Behavior

  • Microsoft 365 group creation permissions
  • Naming policies
  • Classification enforcement
  • Guest ownership rules

App Consent & Governance

  • User consent to applications
  • Admin consent workflow configuration

Feature Flags

  • Preview or legacy tenant-wide features
  • Settings enabled before appearing in the portal UI

Why /beta/settings Often Returns Nothing

Many tenants see this response:

{
  "value": []
}

This is expected behavior.

Important behavior to understand:

  • Directory settings only exist if they have been explicitly configured
  • Default settings → ❌ not returned
  • Explicitly configured settings → ✅ returned
  • No object exists until a template is instantiated

How to Discover All Available Settings

To see every possible setting that could exist, query the templates:

GET https://graph.microsoft.com/beta/directorySettingTemplates

This endpoint returns:

  • All supported directory setting templates
  • Setting names
  • Descriptions
  • Allowed values

This is the authoritative way to understand:

  • What settings are available
  • What can be configured
  • What the portal may be modifying behind the scenes

How Settings and Templates Relate

directorySettingTemplate
        ↓
directorySetting (instance)
        ↓
Configured name/value pairs

You only see /settings entries after:

  • A template is instantiated
  • Values are explicitly set

Example Directory Setting Object

{
  "id": "abcd-1234",
  "displayName": "Group.Unified",
  "values": [
    {
      "name": "EnableGroupCreation",
      "value": "false"
    },
    {
      "name": "AllowGuestsToBeGroupOwner",
      "value": "false"
    }
  ]
}

Required Permissions

Typically required permissions include:

  • Directory.Read.All — read-only
  • Directory.ReadWrite.All — create or update settings

When Should You Use /beta/settings?

This endpoint is especially useful for:

  • Auditing tenant-wide identity configuration
  • Detecting hidden configuration drift
  • Automating security baselines
  • Reverse engineering Entra ID portal behavior
  • Comparing settings across multiple tenants

What /beta/settings Does NOT Contain

This endpoint does not include:

  • Conditional Access policies
  • Authentication method policies
  • Intune configuration profiles
  • Per-user or per-group settings

Those live in other Microsoft Graph namespaces.


Key Takeaways

  • /beta/settings shows only explicitly configured directory settings
  • Empty results are normal in many tenants
  • /directorySettingTemplates shows everything that can exist
  • These settings control global Entra ID behavior

Entra Portal to Graph Mapping Rules

Entra Portal Area Likely Graph Root
Users / Groups /users, /groups
Enterprise Apps /servicePrincipals
App Registrations /applications
Protection /identity
Policies /policies, /authenticationMethodsPolicy
Reports /reports
Logs /auditLogs

Graph Discovery Workflow (Reusable)

  1. Identify the Entra blade (Users, Protection, Identity, Policies)
  2. Open Graph Explorer and start with /beta
  3. Inspect the response for @odata.type
  4. Validate properties in $metadata
  5. Confirm permissions in Graph Explorer
  6. Prefer /v1.0 for automation when available
  7. Track beta → v1.0 promotion

Reverse-Engineering Entra Portal Calls

Why sorting by XHR is the best way to reverse Graph API calls

When you open DevTools → Network in Entra, Microsoft 365, or Intune portals, you’ll see hundreds of requests:

  • JavaScript bundles
  • Fonts
  • Images
  • CSS
  • Telemetry
  • API calls

Why XHR matters

All Microsoft Graph REST calls are sent as XHR / Fetch requests. This includes:

  • List queries
  • $count calls
  • Policy reads
  • Portal data loads
  • Validation checks

Filtering to XHR removes UI noise and surfaces only data-fetching requests.


Step-by-step: Finding the correct Graph query

1. Open a Microsoft portal

2. Open DevTools

  • Press F12
  • Go to Network
  • Enable Preserve log

3. Filter by XHR

Click Fetch/XHR to isolate Graph calls.


What to look for in XHR requests

Signal Why it matters
graph.microsoft.com Actual Graph call
/v1.0/ or /beta/ API version
$count Server-side counting
$filter= Server-side filtering
$select= Payload shaping
ConsistencyLevel Advanced query support

Example: Discovering a group count query

Portal shows:

“123 Groups”

XHR request:

GET https://graph.microsoft.com/v1.0/groups/$count?$filter=securityEnabled eq true

Headers:

ConsistencyLevel: eventual

This is the exact API call the portal uses.


How to extract a reusable API call

  1. Click the XHR request
  2. Copy the Request URL
  3. Note required headers:
    • ConsistencyLevel
  4. Ignore:
    • client-request-id
    • x-ms-* headers
    • Telemetry values

Server-side vs client-side filtering

Server-side (preferred)

  • $filter
  • $count
  • $orderby

Appears directly in the URL.

Client-side

  • No filters in the URL
  • Data processed in JavaScript after retrieval

This distinction is critical for performance and scale.


Why this matters

Reverse-engineering Graph via XHR allows you to:

  • Discover undocumented endpoints
  • Identify real count queries
  • Understand Graph limitations
  • Reproduce portal behavior in automation
  • Avoid unsupported query patterns

Common Graph patterns seen in portals

Count

/{resource}/$count

Filter

?$filter=startswith(displayName,'ACME')

Expand

?$expand=owners($select=id,displayName)

Beta-only features

/beta/identity/...

Mental model

Portal UI
  ↓
XHR request
  ↓
Microsoft Graph endpoint
  ↓
Same call you can automate

The portal is simply a Graph client.


Key takeaway

If the portal can display it, Graph can return it.
XHR is the fastest and most reliable way to discover the correct endpoint, headers, and query parameters.

Reverse Engineering API with DevTools


Microsoft Graph Batch API Request

$batch is a Microsoft Graph batching endpoint that allows the client (portal, admin center, or your code) to send multiple Graph requests in a single HTTP call.

Instead of issuing dozens of individual REST calls, the UI bundles them together and sends them as one request.


Why the Entra / M365 Portal Uses $batch

When you open something like:

  • Users blade
  • Groups overview
  • Conditional Access
  • Authentication methods
  • Intune pages

…the portal often needs many different pieces of data at once:

  • Object details
  • Counts
  • Policy state
  • Related objects
  • Feature flags

Rather than making multiple calls like:

GET /users
GET /users/$count
GET /directory/settings
GET /policies/conditionalAccessPolicies

The portal sends one $batch call containing all of them.


What a $batch Request Looks Like

Request (Simplified)

POST https://graph.microsoft.com/beta/$batch
Content-Type: application/json
{
  "requests": [
    {
      "id": "1",
      "method": "GET",
      "url": "/users?$select=id,displayName"
    },
    {
      "id": "2",
      "method": "GET",
      "url": "/groups/$count?$consistencyLevel=eventual"
    }
  ]
}

Response

{
  "responses": [
    {
      "id": "1",
      "status": 200,
      "body": {
        "value": [ ... ]
      }
    },
    {
      "id": "2",
      "status": 200,
      "body": 412
    }
  ]
}

Each response maps back to its request by ID.


Why $batch Is Important When Reverse-Engineering Graph

1. You Rarely See Clean Single Calls in DevTools

Most modern portal blades use $batch, so the real API endpoints are nested inside the request body.

2. $batch Hides the Real Endpoints

When you expand the payload, you’ll find entries like:

"url": "/policies/conditionalAccessPolicies?$filter=..."

That url value is the exact endpoint you can call directly.


How to Extract the Real API Endpoint

In DevTools → Network → XHR:

  1. Click the $batch request
  2. Open the Request Payload
  3. Expand requests[]
  4. Look for:
    • method
    • url
  5. Copy the url value
  6. Prepend:
https://graph.microsoft.com/beta

✅ That’s the real API call.


Why $batch Is Not Just for the Portal

You can use $batch yourself to:

  • Reduce API throttling
  • Improve performance
  • Make atomic-style read operations
  • Query multiple related resources efficiently

Limits to Know

Limit Value
Requests per batch 20
Same tenant only Yes
Mixed methods GET, POST, PATCH, DELETE
Cross-request dependency Limited

When NOT to Use $batch

Avoid $batch for:

  • Large exports
  • Pagination-heavy queries
  • Long-running reports
  • Simple single-object calls

For those scenarios, direct endpoints are cleaner and easier to manage.


How This Ties Back to Your Graph Learning Journey

This explains why:

  • Sorting by XHR works
  • Portal actions feel “magic”
  • Graph looks imperative in PowerShell
  • Lokka and MCP tools are so powerful

Everything funnels through Graph — $batch is just the transport optimization layer.


TL;DR

  • $batch bundles multiple Graph calls into one
  • The portal uses it everywhere
  • The real endpoints are inside the request body
  • Copy the url value to reproduce the call
  • Understanding $batch is essential for reverse-engineering Graph

BatchAPICalls


Common Read Permissions

Data Type Permission
Users User.Read.All
Groups Group.Read.All
Directory Directory.Read.All
Policies Policy.Read.All
Auth Methods AuthenticationMethod.Read.All
Logs AuditLog.Read.All
Reports Reports.Read.All

📌 Notes

  • Most Entra innovation appears in /beta first
  • $metadata is always authoritative
  • Portal network calls reveal undocumented APIs

Audience: Entra ID engineers, identity architects, security engineers

Maintenance Tip: Review this document quarterly and diff /beta/$metadata for new resource types

Microsoft Graph OData Metadata – Reference & Usage Guide

This document explains what the Microsoft Graph $metadata endpoint is, how to read it, and how to translate metadata into practical OData query usage when working with Microsoft Entra (Azure AD) resources.


1. What is $metadata in Microsoft Graph

The $metadata endpoint exposes the entire service schema for Microsoft Graph using the OData v4 EDMX (Entity Data Model XML) format.

GET https://graph.microsoft.com/v1.0/$metadata
GET https://graph.microsoft.com/beta/$metadata

It describes:

  • Entity types (users, groups, devices, etc.)
  • Properties and their data types
  • Navigation properties (relationships)
  • Inheritance
  • Collections vs singletons
  • Actions and functions

Think of $metadata as the authoritative contract for Graph.


2. Why $metadata matters (especially for Entra)

You use metadata to:

  • Discover all properties (even undocumented ones)
  • Understand relationships between resources
  • Determine what can be selected, expanded, or filtered
  • Build SDKs, schemas, or automation safely
  • Explain why a query fails (unsupported filters/orderby)

The Entra Admin Center is built directly on this schema.


3. High-level structure of the metadata file

The metadata document is XML and follows this hierarchy:

Edmx
 └── DataServices
      └── Schema (Namespace="microsoft.graph")
           ├── EntityType
           ├── ComplexType
           ├── EnumType
           ├── EntityContainer

4. EntityType → Graph Resource Mapping

Each EntityType maps to a Graph resource.

Example: User

<EntityType Name="user" BaseType="graph.directoryObject">
  <Property Name="displayName" Type="Edm.String" />
  <Property Name="accountEnabled" Type="Edm.Boolean" />
  <Property Name="userPrincipalName" Type="Edm.String" />
  <NavigationProperty Name="memberOf" Type="Collection(graph.directoryObject)" />
</EntityType>

Graph endpoint

/users
/users/{id}

5. Property → OData $select

Every <Property> element is selectable.

Metadata

<Property Name="displayName" Type="Edm.String" />

OData usage

GET /users?$select=id,displayName

If it appears in metadata, it can be selected.


6. Property types and OData behavior

EDM Type Meaning OData impact
Edm.String Text Filterable sometimes
Edm.Boolean true/false Often filterable
Edm.DateTimeOffset Timestamp Filterable & sortable
Edm.Guid Object ID Filterable
Collection(...) Array Limited filter support

7. NavigationProperty → $expand

Navigation properties define relationships.

Metadata

<NavigationProperty Name="memberOf" Type="Collection(graph.directoryObject)" />

OData usage

GET /users/{id}/memberOf

or

GET /users/{id}?$expand=memberOf

⚠️ $expand is heavily restricted in Graph and often capped or blocked.


8. Inheritance (BaseType)

Many Entra objects inherit from directoryObject.

<EntityType Name="user" BaseType="graph.directoryObject" />

This means users inherit:

  • id
  • deletedDateTime

Available to all directory objects.


9. EntityContainer → Root endpoints

The EntityContainer defines top-level Graph paths.

<EntityContainer Name="GraphService">
  <EntitySet Name="users" EntityType="graph.user" />
</EntityContainer>

Maps directly to:

/users

10. Actions & Functions

Metadata also defines callable operations.

Example

<Action Name="assignLicense" IsBound="true">

Graph call

POST /users/{id}/assignLicense

If it exists in metadata → it exists in Graph.


11. Metadata vs OData query options

Metadata element OData feature
Property $select, $filter
NavigationProperty $expand, child endpoints
EntitySet Root endpoint
EntityType Resource schema
Action POST operation
Function GET operation

12. Why metadata does NOT guarantee query support

Important limitation:

Metadata shows what exists — not what is indexed.

So even if a property exists:

  • $filter may fail
  • $orderby may fail
  • $expand may be blocked

Example:

<Property Name="accountEnabled" Type="Edm.Boolean" />

But:

$filter=accountEnabled eq true   ✅
$orderby=accountEnabled          ❌

Indexing is a service-level decision, not metadata.


13. v1.0 vs beta metadata

Version Purpose
v1.0 Production-supported schema
beta Preview, experimental, incomplete

Always compare:

/v1.0/$metadata
/beta/$metadata

Beta often exposes:

  • New authentication methods
  • Passkey / FIDO2 extensions
  • Governance features

14. Practical workflow (recommended)

  1. Inspect $metadata
  2. Identify EntityType
  3. Identify Properties & NavigationProperties
  4. Build $select first
  5. Add $filter
  6. Assume client-side $orderby
  7. Follow @odata.nextLink

15. Mental model summary

  • $metadata = schema truth
  • OData = query language
  • Graph = restricted OData implementation
  • Portal = Graph + client-side logic

16. Key takeaway

If you understand $metadata, you can:

  • Predict Graph behavior
  • Reverse engineer portal calls
  • Avoid unsupported queries
  • Build resilient Entra automation

Microsoft Graph Intune Device Management – Metadata & OData Usage Guide

This document explains how Microsoft Intune (device management) endpoints are modeled in Microsoft Graph, how to read the metadata, and how to safely use OData query options against Intune resources.

It is intentionally parallel to the Entra OData guide, but focused on:

  • deviceManagement/*
  • Intune-backed resources
  • Intune-specific OData constraints

1. Intune in Microsoft Graph (big picture)

All Intune APIs live under the deviceManagement namespace in Microsoft Graph.

https://graph.microsoft.com/v1.0/deviceManagement
https://graph.microsoft.com/beta/deviceManagement

Unlike Entra directory objects, Intune data is service-backed, not directory-backed.

This distinction explains why:

  • $orderby often works in Intune
  • $filter is more permissive
  • $expand is still limited

2. Intune $metadata endpoints

GET https://graph.microsoft.com/v1.0/$metadata
GET https://graph.microsoft.com/beta/$metadata

Search within metadata for:

Namespace="microsoft.graph"
EntityType Name="managedDevice"
EntityType Name="deviceConfiguration"

All Intune entities are defined here.


3. Core Intune entity types (most used)

EntityType Graph endpoint Portal blade
managedDevice /deviceManagement/managedDevices Devices → All devices
deviceConfiguration /deviceManagement/deviceConfigurations Devices → Configuration profiles
deviceCompliancePolicy /deviceManagement/deviceCompliancePolicies Devices → Compliance policies
mobileApp /deviceManagement/mobileApps Apps → All apps
deviceManagementScript /deviceManagement/deviceManagementScripts Devices → Scripts
deviceHealthScript /deviceManagement/deviceHealthScripts Devices → Proactive remediations

4. Example: managedDevice metadata

<EntityType Name="managedDevice">
  <Property Name="id" Type="Edm.String" />
  <Property Name="deviceName" Type="Edm.String" />
  <Property Name="operatingSystem" Type="Edm.String" />
  <Property Name="osVersion" Type="Edm.String" />
  <Property Name="complianceState" Type="graph.complianceState" />
  <Property Name="managementAgent" Type="graph.managementAgentType" />
  <NavigationProperty Name="users" Type="Collection(graph.user)" />
</EntityType>

5. Property → $select (Intune)

Every <Property> is selectable.

GET /deviceManagement/managedDevices?
$select=id,deviceName,operatingSystem,complianceState

Best practice:

  • Always $select
  • Intune objects are large

6. $filter support (much better than Entra)

Intune supports filtering on many properties.

Common examples

GET /deviceManagement/managedDevices?
$filter=operatingSystem eq 'Windows'
$filter=complianceState eq 'compliant'
$filter=startswith(deviceName,'AVD')

Enums (like complianceState) are defined in metadata as EnumType.


7. $orderby (generally supported)

Unlike Entra directory objects, Intune supports server-side sorting.

GET /deviceManagement/managedDevices?
$orderby=deviceName asc

⚠️ Sorting still requires:

  • Property to be scalar
  • No complex navigation expansion

8. Pagination and @odata.nextLink

Default page size is 100 (varies by endpoint).

"@odata.nextLink": "https://graph.microsoft.com/..."

Rules:

  • Always follow nextLink
  • Never assume $top returns everything

9. NavigationProperty → child endpoints

Navigation properties define supported child routes.

Metadata

<NavigationProperty Name="deviceCompliancePolicyStates"
  Type="Collection(graph.deviceCompliancePolicyState)" />

Graph usage

GET /deviceManagement/managedDevices/{id}/deviceCompliancePolicyStates

Intune strongly prefers child endpoints over $expand.


10. $expand (use sparingly)

Some Intune resources support $expand, but many do not.

GET /deviceManagement/managedDevices?$expand=users

Common outcomes:

  • Partial expansion
  • Throttling
  • UnsupportedQuery errors

➡️ Prefer separate calls.


11. Actions in Intune metadata

Actions are POST operations defined in metadata.

Metadata

<Action Name="syncDevice" IsBound="true" />

Graph

POST /deviceManagement/managedDevices/{id}/syncDevice

Portal buttons almost always map to actions.


12. Assignments (critical Intune pattern)

Assignments are modeled as child collections, not properties.

Example: App assignments

GET /deviceManagement/mobileApps/{id}/assignments

Same pattern for:

  • Configuration profiles
  • Compliance policies
  • Scripts

13. v1.0 vs beta (Intune reality)

Version Reality
v1.0 Stable, lagging features
beta Required for most new Intune features

Examples only in beta:

  • Endpoint Privilege Management
  • Advanced reporting
  • Some remediation APIs

14. Common Intune OData pitfalls

Issue Cause
UnsupportedQuery $expand or invalid filter
Throttling Large tenant + no $select
Missing data Not following nextLink
Enum filter fails Wrong enum string

15. Safe query pattern (recommended)

GET /deviceManagement/managedDevices?
$select=id,deviceName,operatingSystem,complianceState
&$filter=operatingSystem eq 'Windows'
&$orderby=deviceName

Then:

  • Page with nextLink
  • Join related data client-side

16. Mental model (Intune vs Entra)

Aspect Entra Intune
Backend Directory Service DB
$orderby Rare Common
$filter Restricted Flexible
$expand Limited Very limited
Pagination Required Required

17. Key takeaways

  • Intune Graph is OData-friendly but opinionated
  • Metadata tells you what exists, not limits
  • Prefer child endpoints over $expand
  • Always $select and page

18. Recommended next steps

  • Annotated metadata walkthrough for managedDevice
  • Assignment model deep dive
  • Portal blade → Graph → metadata mapping
  • PowerShell SDK vs raw REST comparison

Understanding Intune metadata + OData gives you portal-level automation without guessing.

Example Usage

  • Scopes required:

Pulling all powershell scripts from Intune using the API

https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts

Get Avaialable Intune Platform Scripts

https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts/{deviceManagementScript-id}$select=scriptContent

Get Script Platform Script Content

Here you would copy the script content from its base64 encoding into an editor

https://www.base64decode.org/

This would give you the content of the script for review

Decode content in Base64 decoder

Working Example

https://graph.microsoft.com/beta/deviceManagement/deviceManagementScripts/c7cd4ba5-ccbf-4c9a-9be5-e22cda7379b0?$select=scriptContent

Microsoft Graph $select Query Option

❓ What does the ? before $select mean?

In Microsoft Graph, the ? indicates the start of query options for an HTTP request. Everything after ? modifies how data is returned, not what endpoint you are calling.


📌 Basic Structure

GET https://graph.microsoft.com/v1.0/users?$select=id,displayName
  • /usersresource path (what you are querying)
  • ?start of query string
  • $selectOData query option

🔍 Why $select needs ?

HTTP URLs follow a standard structure:

/path?queryKey=value&queryKey=value

In Microsoft Graph:

  • ? starts the query section
  • & chains multiple query options

Example with multiple query options

GET /v1.0/users?$select=id,displayName,userPrincipalName&$top=10

🧪 Common OData Query Options

Query Option Purpose Example
$select Return specific properties ?$select=id,displayName
$filter Filter results ?$filter=accountEnabled eq true
$expand Include related objects ?$expand=memberOf
$top Limit results ?$top=25
$orderby Sort results ?$orderby=displayName
$count Include count ?$count=true

📦 Example: Without vs With $select

❌ Without $select

GET /v1.0/users

Returns many default properties per user, resulting in a larger payload.


✅ With $select

GET /v1.0/users?$select=id,displayName,userPrincipalName

Returns only the properties you explicitly request.

Benefits:

  • Smaller response payloads
  • Faster queries
  • Clear, intentional documentation

⚠️ Important Rules and Limitations

  • $select does not grant or change permissions

  • Some properties:

    • Require additional permissions
    • Are not selectable on certain endpoints
  • $select=* is not supported in Microsoft Graph


🧠 Mental Model

/users           → what data you are requesting
?                → how the data should be returned
$select=prop     → which fields are included
&$filter=...     → which records are returned

✍️ Documentation-Friendly Example

### Example: Select Specific User Properties

```http
GET /v1.0/users?$select=id,displayName,userPrincipalName

Description: Returns a list of users with only ID, display name, and user principal name.

Permissions Required:

  • User.Read.All

Notes:

  • Use $select to reduce payload size
  • Combine with $filter for targeted queries

---

## 📌 Summary

- `?` starts the query string in a Graph request
- `$select` controls which properties are returned
- Using `$select` improves performance and clarity
- Always pair `$select` with the minimum required permissions

---

**Audience**: Entra ID engineers, security engineers, Graph API consumers

**Recommended Use**: Internal documentation, team wikis, API reference guides

HTTP Methods Overview for Microsoft Graph API

This document provides a concise reference for the main HTTP methods used in Microsoft Graph, their purposes, and behavior.


1️⃣ GET

  • Purpose: Retrieve data from a resource.
  • Idempotent: ✅ (safe to call multiple times without changing server state)
  • Request Body: Not typically used
  • Response: Returns the resource(s) in JSON format

Example:

GET /v1.0/users?$select=displayName,userPrincipalName

2️⃣ POST

  • Purpose: Create a new resource or invoke an action.
  • Idempotent: ❌ (calling multiple times may create multiple resources)
  • Request Body: Required, contains data for creation or action parameters
  • Response: Returns the created resource or action result

Example:

POST /v1.0/groups
Content-Type: application/json

{
  "displayName": "New Team",
  "mailEnabled": false,
  "mailNickname": "newteam",
  "securityEnabled": true
}

3️⃣ PUT

  • Purpose: Replace an existing resource entirely.
  • Idempotent: ✅ (replacing the resource with the same data multiple times has no additional effect)
  • Request Body: Required, must contain full resource representation
  • Response: Usually returns 204 No Content

Example:

PUT /v1.0/groups/{id}
Content-Type: application/json

{
  "displayName": "Updated Team Name",
  "mailEnabled": false,
  "mailNickname": "updatedteam",
  "securityEnabled": true
}

4️⃣ PATCH

  • Purpose: Update parts of an existing resource.
  • Idempotent: ✅ (updating the same properties with same values multiple times has no effect)
  • Request Body: Contains only the fields to update
  • Response: Usually returns 204 No Content

Example:

PATCH /v1.0/groups/{id}
Content-Type: application/json

{
  "displayName": "Partially Updated Name"
}

5️⃣ DELETE

  • Purpose: Remove a resource.
  • Idempotent: ✅ (deleting the same resource multiple times has no effect)
  • Request Body: Not used
  • Response: Usually returns 204 No Content

Example:

DELETE /v1.0/groups/{id}

Quick Comparison Table

Method Purpose Idempotent Body Required Response
GET Retrieve resource(s) No JSON data
POST Create resource / invoke action Yes Created resource / action result
PUT Replace resource entirely Yes 204 No Content
PATCH Update part of resource Yes 204 No Content
DELETE Remove resource No 204 No Content

Notes:

  • Idempotent methods are safe for retries.
  • POST is used for creation and actions that may have side effects.
  • PATCH is preferred for partial updates to reduce payload and avoid overwriting unchanged properties.
  • Always check required permissions for each operation in Microsoft

Continuous Access Evaluation and Microsoft Graph

Overview

Continuous Access Evaluation (CAE) is one of the most misunderstood features in Microsoft Entra ID because it behaves differently than most policy-driven features exposed through Microsoft Graph.

A common point of confusion is:

“I thought CAE was enabled by default — so why does the Graph endpoint return ResourceNotFound?”

Both statements can be true at the same time.

This document explains what CAE actually is, how it works, and why the Graph API behaves the way it does.


What Is Continuous Access Evaluation (CAE)?

Continuous Access Evaluation is a runtime enforcement capability that allows Microsoft services to re-evaluate access during an active session, rather than waiting for token expiration.

Instead of relying solely on token lifetime, CAE allows services to react immediately to security-relevant events.

Examples include:

  • Password reset
  • Account disabled
  • User or sign-in risk change
  • Conditional Access policy updates
  • Role or group membership changes

When these events occur, CAE-enabled workloads can invalidate access mid-session and force reauthentication.


Is CAE Enabled by Default?

Yes — CAE is enabled by default, but not in the way most people expect.

What “enabled by default” actually means

  • Microsoft workloads automatically use CAE where supported
  • No tenant-level configuration is required
  • No admin action is needed to activate baseline CAE behavior

What it does not mean

  • There is no default CAE policy object
  • There is no visible tenant-wide CAE toggle
  • There is no Graph resource created automatically

CAE Enforcement vs CAE Configuration

This distinction is critical.

CAE Enforcement

  • Built into Microsoft services
  • Always active where supported
  • Driven by service-side logic
  • Requires no policy object

CAE Configuration

  • Optional
  • Exposed through Microsoft Graph
  • Represented by a singleton policy resource
  • Only exists if explicitly created or configured

CAE enforcement exists without CAE configuration.


The Microsoft Graph CAE Endpoint

GET https://graph.microsoft.com/beta/identity/continuousAccessEvaluationPolicy

If the policy has never been configured, Microsoft Graph returns:

{
  "error": {
    "code": "ResourceNotFound",
    "message": "CAE settings not found."
  }
}

This response is expected behavior.

It does not mean:

  • The endpoint is invalid
  • CAE is disabled
  • You lack permissions

It means:

  • The CAE policy object does not exist in the tenant

Why the CAE Policy Object Does Not Exist by Default

The continuousAccessEvaluationPolicy is a singleton resource.

Characteristics of singleton identity policies:

  • Only one instance per tenant
  • Not automatically created
  • Materialized only when configured

Microsoft designed CAE as:

  • Implicit
  • Service-driven
  • Feature-gated
  • Lazy-created

Graph only returns objects that exist.
If the CAE policy has never been initialized, Graph correctly returns 404.

CAEGraphResponse


What the CAE Policy Actually Controls

The CAE policy does not turn CAE on or off.

It exists primarily to:

  • Control migration behavior
  • Manage compatibility scenarios
  • Configure advanced CAE participation settings

Example response once the policy exists:

{
  "id": "continuousAccessEvaluationPolicy",
  "migrate": false
}

This configuration fine-tunes how workloads interact with CAE — it does not enable it.


Permissions Required

To read or manage the CAE policy (if it exists), you typically need one of the following permissions:

  • Policy.Read.All
  • Policy.ReadWrite.ConditionalAccess
  • Directory.Read.All

Admin consent is required.

Permissions alone will not create the policy object.


Why This Confuses Graph Learners

Most Graph features follow a predictable pattern:

  1. Feature exists
  2. Policy exists
  3. Graph returns an object

CAE breaks this assumption.

It behaves more like:

  • Token issuance logic
  • Risk evaluation pipelines
  • Service-side enforcement mechanisms

Graph exposes only a thin configuration layer, not the enforcement engine itself.


How to Validate That CAE Is Working

CAE is not validated by querying the policy endpoint.

Instead, validate CAE by observing behavior:

  • Sign-in logs
  • Mid-session access revocation
  • Forced reauthentication after:
    • Password reset
    • Account disablement
    • Risk elevation
    • Conditional Access changes

That is where CAE truly operates.


Key Takeaways

  • CAE is enabled by default at the service level
  • There is no default CAE policy object
  • The Graph endpoint returns 404 if the policy does not exist
  • CAE enforcement is not policy-driven
  • The policy endpoint represents optional configuration only
  • This is expected and correct Graph behavior

Why This Matters for Learning Microsoft Graph

This is a textbook example of how Microsoft Graph exposes APIs:

  • Before GUI controls exist
  • Before objects are created
  • Sometimes only as optional configuration layers

Understanding this behavior:

  • Prevents misdiagnosing 404 errors
  • Helps reverse engineer portal behavior
  • Improves confidence when exploring new Graph endpoints

CAE is a perfect example of why learning Graph teaches you how Microsoft actually builds and ships features.

About

Repository to Document and learn Graph API and script collection

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors