Skip to content

Bug: "a365 setup blueprint" missing CustomClientAppId — inheritable permissions fail (especially macOS/Linux) #271

@pratapladhani

Description

@pratapladhani

Bug Description

a365 setup blueprint (standalone) fails to configure inheritable permissions for Microsoft Graph because graphApiService.CustomClientAppId is never set in the command handler. This causes Connect-MgGraph to omit the -ClientId parameter, falling back to the default Graph PowerShell SDK client app (14d82eec-204b-4c2f-b7e8-296a70dab67e), which lacks the required AgentIdentityBlueprint.UpdateAuthProperties.All permission.

Error Message

Failed to configure Microsoft Graph inheritable permissions: AADSTS65001: 
The user or administrator has not consented to use the application with ID '14d82eec-204b-4c2f-b7e8-296a70dab67e' 
named 'Microsoft Graph Command Line Tools'. Send an interactive authorization request for this user and resource.

Root Cause

In BlueprintSubcommand.cs, the SetHandler block does not set graphApiService.CustomClientAppId = setupConfig.ClientAppId before calling CreateBlueprintImplementationAsync. Every other command that uses the Graph API correctly sets this property:

Command Sets CustomClientAppId? Location
a365 setup all Yes AllSubcommand.cs line ~138
a365 setup permissions Yes PermissionsSubcommand.cs lines ~84, ~162
a365 deploy Yes DeployCommand.cs line ~224
a365 cleanup Yes CleanupCommand.cs lines ~99, ~446
a365 setup blueprint No — missing BlueprintSubcommand.cs SetHandler block

Call chain when CustomClientAppId is null

  1. BlueprintSubcommand.SetHandlerdoes not set graphApiService.CustomClientAppId
  2. CreateBlueprintImplementationAsync → passes graphApiService to CompleteBlueprintConfigurationAsync
  3. CompleteBlueprintConfigurationAsync → calls EnsureAdminConsentAsync
  4. EnsureAdminConsentAsync → calls SetupHelpers.EnsureResourcePermissionsAsync with setInheritablePermissions: true
  5. EnsureResourcePermissionsAsync → calls blueprintService.SetInheritablePermissionsAsync with requiredScopes: ["AgentIdentityBlueprint.UpdateAuthProperties.All", "Application.ReadWrite.All"]
  6. AgentBlueprintService.SetInheritablePermissionsAsync → calls _graphApiService.GraphGetAsync/GraphPatchAsync
  7. GraphApiService.EnsureGraphHeadersAsync → calls _tokenProvider.GetMgGraphAccessTokenAsync(tenantId, scopes, false, CustomClientAppId, ct) where CustomClientAppId is null
  8. MicrosoftGraphTokenProvider (line ~200): omits -ClientId from Connect-MgGraph because clientAppId is null/empty:
    var clientIdParam = !string.IsNullOrWhiteSpace(clientAppId) 
        ? $" -ClientId '{CommandStringHelper.EscapePowerShellString(clientAppId)}'"
        : "";  // ← empty when CustomClientAppId is null
  9. Connect-MgGraph without -ClientId → defaults to SDK app 14d82eec-204b-4c2f-b7e8-296a70dab67e
  10. That app lacks AgentIdentityBlueprint.UpdateAuthProperties.AllAADSTS65001 error

Why macOS/Linux Shows the Symptom More Frequently

The bug exists on all platforms, but the symptom manifests differently:

macOS/Linux (no WAM broker)

  • Connect-MgGraph without -ClientId has no WAM broker to fall back to
  • Uses browser-based interactive auth with the default SDK client app
  • The default SDK app 14d82eec-204b-4c2f-b7e8-296a70dab67e does not have the required beta permission AgentIdentityBlueprint.UpdateAuthProperties.All
  • Result: Always fails on the inheritable permissions step

Windows (WAM broker available)

  • WAM (Web Account Manager) broker can reuse cached tokens from earlier interactive authentication that happened earlier in the same CLI session (e.g., during blueprint creation)
  • Those cached tokens were acquired using the correct custom client app (from MsalBrowserCredential in GetTokenFromGraphClient)
  • WAM can silently return a token for the same account, masking the missing -ClientId
  • Result: Often works due to cached tokens, but can fail on fresh machines, after token expiry, or in CI/CD environments

Additional reproduction factor

  • a365 setup all is not affected — it correctly sets CustomClientAppId at line 138 of AllSubcommand.cs
  • The bug only manifests when running standalone a365 setup blueprint
  • On a first-time setup via a365 setup all, everything works. The bug appears when users re-run just the blueprint step (e.g., to fix endpoint issues or recreate a blueprint)

Steps to Reproduce

  1. Have a tenant with a custom client app registration that has AgentIdentityBlueprint.UpdateAuthProperties.All (beta) permission consented
  2. Have a365.config.json configured with valid clientAppId and tenantId
  3. Run a365 setup blueprint --verbose (standalone, not a365 setup all)
  4. Observe that inheritable permissions step fails with AADSTS65001

More reliably reproduced on macOS/Linux where WAM is not available.

Proposed Fix

Add one line in BlueprintSubcommand.cs SetHandler block, after loading the config and before calling CreateBlueprintImplementationAsync:

var setupConfig = await configService.LoadAsync(config.FullName);

// ADD THIS LINE - matches pattern used by AllSubcommand, PermissionsSubcommand, etc.
graphApiService.CustomClientAppId = setupConfig.ClientAppId;

This is consistent with every other command handler in the codebase that uses graphApiService.

Environment

  • CLI Version: 1.1.62-preview+35cd754bfe
  • Platforms affected: All (macOS/Linux always fails; Windows intermittently masked by WAM)
  • Reported on: macOS ARM64 (Apple Silicon)

Workaround

Users can work around this by running a365 setup all --skip-infrastructure instead of standalone a365 setup blueprint, since AllSubcommand correctly sets CustomClientAppId.

Metadata

Metadata

Assignees

Labels

P1Very high prioritybugSomething isn't workingsecuritySecurity-related issue

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions