Docs menu

Entra ID Directory Accuracy: App Registrations, Service Principals and Directory Roles

App registrations show the service principal they run as. Directory roles always resolve to a name and show the scope they hold, so a narrow assignment never counts as tenant-wide. The Identity Providers page shows which Entra ID data is collected, which isn't, and why.

Roles
Viewer or Operator to see role scopes and app registration links in the graph. Admin to see what's collected from a tenant, approve permissions, or update an app registration.
Applies to
Entra ID
Updated
On this page

Overview

A sync can succeed and still misread the tenant. Three cases matter most:

  • An app registration looks like an island. Anyone who can add a credential to a registration can authenticate as the service principal it backs. Without a link between the two, that path is invisible.
  • A narrow role reads as tenant-wide. A directory role assigned over one administrative unit or one object grants far less than the same role tenant-wide. Without its scope, the two look the same.
  • A data set goes missing quietly. Sign-in activity or Conditional Access coverage that was never approved isn't collected, and the sync still reports success.

This guide covers how GraphnAI handles each case, and the Identity Providers card that shows what's collected from your tenant and what isn't.

Prerequisites

  • An Entra ID tenant added on Admin > Identity Providers, with at least one finished sync. See Entra ID Setup.
  • Admin role to see the data coverage card, grant admin consent, or update an app registration.
  • Viewer or Operator role to see role scopes and app registration links in the Graph Explorer and the identity detail panel.

What you see in the graph

App registrations show what they run as

An app registration and its service principal are one workload identity split across two directory objects. Anyone who owns the registration, or can add a client secret or certificate to it, can authenticate as its service principal. GraphnAI draws that link as a RunsAs edge, shown as Runs as in the graph.

  • An app registration's detail panel lists the service principal under Runs as service principal.
  • The service principal's detail panel lists the registration under Backed by app registration.
  • Select either entry to open the other object.

Risk analysis follows the link. If the service principal is Tier 0, its app registration is Tier 0 too, because controlling the registration means acting as the service principal. Critical Junctions analysis and blast radius simulations also follow it, so an attack path continues from the registration to everything the service principal can reach.

Who can add credentials to an app

Anyone who can add a client secret or certificate to an app or service principal can then authenticate as it (MITRE ATT&CK T1098.001, Additional Cloud Credentials). GraphnAI shows these holders, so you can find routes into privileged workload identities that no direct assignment reveals.

Most holders can reach every app in the tenant. Rather than draw an edge from each holder to each app, GraphnAI adds one node per Entra connection, Tenant-wide app credential control. Every tenant-wide holder links to it, and it links to every app registration and service principal in that tenant. A path reads: holder, Tenant-wide app credential control, app, service principal.

A holder appears from one of three sources:

Source Shown as
A directory role assigned across the tenant: Application Administrator, Cloud Application Administrator, Global Administrator, or a custom role that covers both apps and service principals Application Administrator, tenant-wide
A role scoped to one app or service principal Application Administrator for this app only
The application permission Application.ReadWrite.All, granted to a service principal Application permission Application.ReadWrite.All

A role scoped to one app credits the holder with that app only. It never counts as tenant-wide.

The deprecated Partner Tier1 Support and Partner Tier2 Support roles reach app registrations only. They link directly to each app registration and not to service principals.

Managed identities are never listed, because Microsoft doesn't let you add credentials to them. Microsoft first-party service principals are listed.

To see who holds this access, open an identity's detail panel:

  • Can add credentials to (n) lists what the identity can add credentials to. A tenant-wide holder shows Every app and service principal in your tenant.
  • Who can add credentials (n) lists the holders for an app or service principal. Each row names the source, for example Global Administrator, tenant-wide.
  • When a list has more than 10 rows, select Show all (n) to open the full list.

In Graph Explorer, select a holder-to-app edge to read it in plain words, such as "can add credentials to every app and service principal in your tenant". Select the Tenant-wide app credential control node to see how many apps and service principals it covers.

The edge can't be removed on its own. To remove it, remove the role assignment or the permission, or block the holder's sign-in. When you plan this in Select Fire, the reason reads "This access comes from" the source, followed by "Remove that assignment or permission to remove it." If a holder has several sources, remove all of them.

Built-in roles resolve by name

A directory role always shows its name, even the first time GraphnAI sees it. A privileged assignment never shows up as a blank node.

Every role assignment shows its real scope

Entra ID scopes a directory role assignment to the whole tenant, one administrative unit, or one object. GraphnAI keeps that scope. A Privileged Authentication Administrator assigned over one administrative unit doesn't look the same as one assigned tenant-wide.

An identity's Directory roles section marks every role whose scope isn't the whole tenant. A tenant-wide role has no badge.

Badge Meaning
Administrative unit The role applies only to members of the listed administrative units. It doesn't make the identity Tier 0.
Single object The role applies only to the listed object. It doesn't make the identity Tier 0.
Scope not recognized Microsoft reported a scope GraphnAI doesn't recognize. It counts as tenant-wide.
Scope not collected The assignment's scope wasn't collected. It counts as tenant-wide.

Only the two narrow scopes keep a role holder out of Tier 0. An unproven scope never hides a privileged account.

A narrow assignment also never masks a broad one. A principal that holds Global Administrator tenant-wide and again over one administrative unit stays Tier 0.

Revoking one assignment leaves the others alone

A principal can hold the same directory role more than once, at different scopes. When you revoke one of those assignments with Select Fire, only that assignment is removed. The principal's other assignments of the role stay as they were, including a tenant-wide one.


Data collected from this tenant

Go to Admin > Identity Providers and choose your Entra ID tenant from the provider menu. The Data collected from this tenant card lists four optional data sets. Its header gives the date of the collection it describes.

Row What it adds Permission License
Delegated permission grants OAuth 2.0 consent grants between users and applications Directory.Read.All (optional) None
Conditional Access policies Which users and groups your Conditional Access policies apply to Policy.Read.All (optional) None
Privileged Identity Management PIM eligible roles: roles a principal can activate on demand but doesn't hold right now RoleManagement.Read.Directory (required, so already requested) Microsoft Entra ID P2 or Microsoft Entra ID Governance
Sign-in activity Last sign-in dates on Entra ID users AuditLog.Read.All (requested by the setup wizard) Microsoft Entra ID P1 or P2

Each row shows one of these badges:

Badge Meaning
Collected Collected normally. The line under it gives a count, such as "12 policies". With no Conditional Access policies, it reads "No Conditional Access policies found."
Approved The permission was approved after the last sync. The line reads "Collected from the next sync."
Turned off Collection of this data set is off for the tenant. Turn it on in Sync attributes, from the gear icon at the top of the page.
Not requested The app registration doesn't request the permission. The line names it, such as "Needs Policy.Read.All".
Not approved The app registration requests the permission, but no administrator has approved it.
Not on this license The tenant doesn't have the license. The line names it. Nothing in GraphnAI changes this.
Failed or Incomplete The last collection failed or returned partial data. The line gives the reason. Check the sync history, or wait for the next sync.

Users, groups, roles and app permissions are always collected. A gap in any of these four data sets never fails the sync. It shows here instead.

When something is missing, the card offers one next step for all rows:

  • Update the app registration when a permission isn't requested. See Updating an existing app registration.
  • Grant admin consent when a permission isn't approved. It opens Microsoft's consent page.
  • Open API permissions opens the app registration's API permissions page in the Microsoft Entra admin center.

Select Check again to reload the card. If GraphnAI can't reach Microsoft, the card says so and shows the results of the last collection.


Updating an existing app registration

An app registration created before these data sets existed may not request every optional permission. Fix it in one of two ways.

Option 1: Update it yourself in the Entra admin center

  1. Select Open API permissions on the coverage card or the directory access card.
  2. In the Microsoft Entra admin center, add the missing permission.
  3. Grant admin consent.

Option 2: Let GraphnAI update it for you

  1. Select Update the app registration.
  2. In the dialog, select Sign in with Microsoft. Allow pop-ups for the GraphnAI address if your browser asks.
  3. Sign in to Microsoft in the pop-up as an Application Administrator or Cloud Application Administrator. A Global Administrator can too. The sign-in needs a valid license and a browser that can reach https://api.graphnai.com. If it can't, use Add the permissions in the Microsoft Entra admin center in the same dialog.
  4. When the dialog lists the added permissions, select Grant admin consent.

GraphnAI adds only the missing read permissions, from a fixed list of the permissions it uses. It never removes anything. If the registration already asks for everything, the dialog says "The app registration already requests every permission GraphnAI uses."

The credential GraphnAI syncs with stays read-only. Only this sign-in can change the app registration, and GraphnAI records every update attempt in its audit log.

If the update fails, the dialog shows why:

Message What to do
"This Microsoft account belongs to a different tenant. Sign in as an administrator of {tenant}." Select Try again and sign in with an account from the tenant you're updating.
"This Microsoft account can't change the app registration. Sign in as an Application Administrator or a Cloud Application Administrator." Select Try again and sign in with an account that holds one of those roles.
"Microsoft declined the sign-in for this account. Sign in as an Application Administrator or a Cloud Application Administrator." Microsoft refused the sign-in, often because of a Conditional Access policy on that account. Select Try again with another eligible account.
"The sign-in window timed out. Start again." Select Start again to sign in again.
"Microsoft accepted the change, but GraphnAI couldn't confirm it. Check API permissions in the Microsoft Entra admin center." The update probably went through. Check the app registration's API permissions page.
"No app registration in this tenant uses this client ID." or "More than one app registration uses this client ID. Update it in the Microsoft Entra admin center." Add the permissions in the Microsoft Entra admin center.
"Automatic updates aren't available on this installation. Add the permissions in the Microsoft Entra admin center." This server can't run the sign-in. Use Option 1.

Last Activity on Entra users

The Last activity cell in an Entra ID user's detail panel says why a date is missing. Hover over it for the reason.

Cell Reason
Not on this license Sign-in activity needs Microsoft Entra ID P1 or P2.
Not approved An administrator hasn't approved AuditLog.Read.All for this tenant.
Not requested The app registration doesn't request AuditLog.Read.All.
Turned off Collection of sign-in activity is off for this tenant.
Not collected The last collection of sign-in activity failed.

A date marked Not current came from an earlier sync. The latest sync couldn't collect sign-in activity, so the date is the last one collected. A missing or old date here means the data wasn't collected. It never means the user hasn't signed in.


How stale permissions are cleaned up

When a role assignment, group membership or other permission is removed in Entra ID, GraphnAI removes the matching edge. The cleanup acts only on real evidence of removal:

  • Two complete syncs in a row must both miss the edge. One sync is never enough, because Microsoft Graph can leave something out of a single response.
  • No cleanup after a sync with problems. The cleanup skips any sync where a write failed or where removing deleted objects didn't finish. A failed read from Microsoft is never treated as a deletion.
  • A limit on how much goes at once. Sometimes too large a share of one edge type looks removed in a single run. GraphnAI then keeps that whole type. The sync history row then warns, for example: "Stale Entra ID group memberships were kept: more looked removed at once than the safety limit allows. If the drop is real, raise the limit. The server log names the setting."

An edge whose other end no longer exists is removed regardless of the limit.

[!NOTE] For administrators: A deployment environment setting controls the limit, as a percentage of each edge type. It defaults to 50, and it has no UI. Raise it if a real large-scale removal is being kept.


Troubleshooting

An app registration has no "Runs as service principal" entry

GraphnAI matches a registration to its service principal by application ID, within the same tenant. A registration created moments ago may not have a service principal yet. A service principal for an app registered in another tenant has no registration in yours. Select Sync now on Admin > Identity Providers and check again.

A role shows "Scope not collected" or "Scope not recognized"

Microsoft didn't return a scope GraphnAI can confirm as narrow. Both badges count as tenant-wide, so the holder isn't excluded from Tier 0 on that assignment. This is expected.

A coverage row still says "Not approved" after you approved

Microsoft can take up to a minute to report an approval. Select Check again. Once the row reads Approved, the data arrives with the next sync. Select Sync now to collect it right away.

The coverage card says "Not collected yet"

No sync has finished for this tenant. Select Sync now on Admin > Identity Providers. The card fills in when the sync finishes.

A list says credential control appears after the next sync

The Can add credentials to and Who can add credentials sections show "Credential control appears after the next Entra ID sync." until the first Entra ID sync after an upgrade finishes. Select Sync now on Admin > Identity Providers to collect it right away.

After a sync that couldn't read everything, the list shows a note that it may be missing someone. The note clears after the next complete sync. Check the data coverage card for the data set that wasn't collected.

    ↑↓ to move, Enter to open