MICROSOFT ENTRA AGENT PERMISSIONS — LAB PACKAGE
Companion: Microsoft Entra Agent Permissions: Audit and Revoke Access

REQUIREMENTS
Windows, PowerShell 7, current serviced .NET 10 LTS SDK, and network access to
Microsoft identity/Graph and NuGet. Confirm dotnet --version selects 10.x.
Microsoft.Identity.Web and Microsoft.Identity.Web.AgentIdentities are pinned
to 4.18.0, with exact resolved dependencies in packages.lock.json.
The original tenant measurements used .NET 8, which reached end of support
on 10 November 2026. This package's .NET 10 local checks are separate from
those original measurements. See VALIDATION.txt for the evidence boundary.

CONTENTS AND PREPARATION
Program.cs / AgentPermissionLab.csproj: synthetic API and official agent client.
Configure-LabBlueprint.ps1: separate, confirmed Certificate, Callback and
Inheritance stages. Does not create objects, grant Lab.Read or clean up.
Read-AgentLabInventory.ps1: Graph GET requests only; no login or consent request.
Manage-LabManagementConsent.ps1: capture/list/plan, then separately confirmed
cleanup of one management grant. See CONSENT-CLEANUP.txt BEFORE adding scopes.
SETUP.txt and article section 4: ordered portal steps, scopes and configuration.
Copy lab-config.example.json to lab-config.json and fill the object map first.
Application IDs, object IDs and principal IDs are distinct fields. Use the
resource's Lab.Read role GUID. The API must issue v2 access tokens.
Use a unique one-day certificate in CurrentUser/My with a non-exportable private
key. Upload only the public .cer. No passwords, private keys or tokens belong
in the JSON. Keep configuration and evidence private. EvidenceDirectory is
resolved relative to the working directory.

INVENTORY AUTHORIZATION
Application.Read.All and Directory.Read.All are the helper's OAuth scopes,
not proof that the operator may read every endpoint. The typed blueprint and
inheritance GETs document owner access and Agent ID Administrator for nonowners.
Delegated-grant GETs separately require a supported role such as Directory
Readers. Directory Readers alone is not a documented guarantee of the complete
inventory. Reuse the already authorized lab operator with read scopes; a 403
remains incomplete, never a clean permission result. Do not automatically grant
management roles to resolve a failed read.

RUN FROM THE EXTRACTED FOLDER
dotnet restore --locked-mode
dotnet build --no-restore

First PowerShell window:
dotnet .\bin\Debug\net10.0\AgentPermissionLab.dll serve .\lab-config.json

Second window in the same folder:
dotnet .\bin\Debug\net10.0\AgentPermissionLab.dll check-api .\lab-config.json
Both missingBearer and invalidBearer must be 401.

In the authorized Graph session, collect inventory A, then probe A:
.\Read-AgentLabInventory.ps1 -Label A
dotnet .\bin\Debug\net10.0\AgentPermissionLab.dll probe .\lab-config.json A

Only after A, run the consent helper and review the printed URL and both screens:
dotnet .\bin\Debug\net10.0\AgentPermissionLab.dll consent .\lab-config.json
Exact registered callback: http://localhost:52150/callback.
The helper validates state but never approves consent. Verify actual grants:
.\Read-AgentLabInventory.ps1 -Label B
dotnet .\bin\Debug\net10.0\AgentPermissionLab.dll probe .\lab-config.json B

Review every child affected by the parent grant; revoke exactly Lab.Read:
.\Read-AgentLabInventory.ps1 -Label C
dotnet .\bin\Debug\net10.0\AgentPermissionLab.dll probe .\lab-config.json C

INTERPRETATION
Each probe is a new process with an in-memory cache. A/C expect 403, no Lab.Read,
no ticket and matching child/audience. B expects 200, Lab.Read and LAB-001.
Compare independently with parent Lab.Read counts 0/1/0 and child direct roles 0.
Probe exits: 0 expected observation; 1 execution/evidence failure; 2 invalid
configuration/arguments; 3 unexpected observation. Inspect $LASTEXITCODE after
each command. An expected A/C 403 is not an execution failure. A zero exit code
still requires the independent inventory and a review of the JSON evidence.
Inventory exits: 0 complete/matching (or complete Audit); 1 incomplete query,
identity mismatch or failure; 3 complete but unexpected stage configuration.
Failed queries have null items/counts, never a successful empty list. Pagination
is followed only on the same Graph collection. A failed later page invalidates
the summary. Preserve intermediate reports; respect throttling/retry guidance
and allow for replication after grant changes. No automatic retry loop is used.
Only the configured resource's app roles are resolved; review other resources
separately. This is a lab inventory, not a tenant-wide scan.
Do not infer that all already-issued tokens stop working after revocation.

CLEANUP AND NETWORK
Ctrl+C in both API and consent windows. Remove this lab's exact grant,
blueprint credential, child, blueprint, API registration and resource principal.
Verify active inventories separately. Inspect local-certificate.json and match
both thumbprint and subject before removing that exact local certificate.
Remove only added management consent scopes and preserve the baseline.
Follow CONSENT-CLEANUP.txt for both AllPrincipals and Principal grants. The
User consent portal tab cannot revoke permissions. The included helper previews
one exact grant, supports WhatIf and preserves pre-existing/unrelated scopes.
An existing approved cleanup session is required; no new consent is requested.
Disconnect-MgGraph ends the session; it does not revoke consent.
Recheck the intended registration setting (No in the recorded lab).
API listens only on 127.0.0.1:52148; consent helper on 127.0.0.1:52150.
Do not terminate unknown processes if a port is occupied. Production needs
HTTPS, managed credentials and appropriate monitoring.

MICROSOFT REFERENCES
https://learn.microsoft.com/en-us/entra/agent-id/create-blueprint
https://learn.microsoft.com/en-us/entra/agent-id/create-delete-agent-identities
https://learn.microsoft.com/en-us/entra/agent-id/configure-inheritable-permissions-blueprints
https://learn.microsoft.com/en-us/entra/msidweb/getting-started/daemon-app
https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list-approleassignments?view=graph-rest-1.0
https://learn.microsoft.com/en-us/graph/api/serviceprincipal-list-oauth2permissiongrants?view=graph-rest-1.0
https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core
https://learn.microsoft.com/en-us/graph/api/agentidentityblueprint-list-inheritablepermissions?view=graph-rest-1.0
https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/manage-application-permissions
