Skip to main content

entra-id-aspire-provisioning

Provision Entra ID (Azure AD) app registrations for .NET Aspire applications and update configuration. Use after adding Microsoft.Identity.Web authentication code to create or update app registrations, configure scopes, credentials, and update appsettings.json files. Triggers: "provision entra id", "create app registration", "register azure ad app", "configure entra id apps", "set up authentication apps".

Ir a la instalación

Datos de origen

Repositorio
AzureAD/microsoft-identity-web
Última actividad en el origen
2 de febrero de 2026 a las 14:21
Idioma detectado de SKILL.md
inglés
Estrellas
787
Forks
273

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
entra-id-aspire-provisioning
description
Provision Entra ID (Azure AD) app registrations for .NET Aspire applications and update configuration. Use after adding Microsoft.Identity.Web authentication code to create or update app registrations, configure scopes, credentials, and update appsettings.json files. Triggers: "provision entra id", "create app registration", "register azure ad app", "configure entra id apps", "set up authentication apps".
# Entra ID Provisioning for .NET Aspire Provision Entra ID app registrations for Aspire solutions and update `appsettings.json` configuration. ## Prerequisites ### Install Microsoft Graph PowerShell ```powershell # Install the required modules (only if needed, one-time setup) Install-Module Microsoft.Graph.Applications -Scope CurrentUser -Force Install-Module Microsoft.Graph.Identity.SignIns -Scope CurrentUser -Force # Note: Microsoft.Graph.Users is NOT required - this skill uses Invoke-MgGraphRequest # to get current user info, which avoids module version compatibility issues. ``` ### Connect to Microsoft Graph ```powershell # Connect with required scopes Connect-MgGraph -Scopes "Application.ReadWrite.All", "Directory.ReadWrite.All" # Verify connection Get-MgContext ``` > **Note**: You may be prompted to consent to permissions on first use. ## Provisioning Checklist Use this checklist to verify all provisioning steps are complete: ### For Each Web API Project - [ ] App registration created (or existing one found or user-provided) - [ ] App ID URI set (`api://{clientId}`) - [ ] `access_as_user` scope configured - [ ] Service principal created - [ ] Current user added as owner - [ ] `appsettings.json` updated with `TenantId` and `ClientId` ### For Each Web App Project - [ ] App registration created (or existing one found or user-provided) - [ ] Redirect URIs configured (from `launchSettings.json`) - [ ] Client secret generated and stored in user-secrets - [ ] API permission added (to call the web API) - [ ] Admin consent granted (or manual steps provided) - [ ] Service principal created - [ ] Current user added as owner - [ ] `appsettings.json` updated with `TenantId`, `ClientId`, and `Scopes` ### Final Verification - [ ] API provisioned **before** web app (web app needs API's ClientId and ScopeId) - [ ] All `appsettings.json` files have real GUIDs (no placeholders) - [ ] Client secret stored in user-secrets (not in `appsettings.json`) - [ ] `Disconnect-MgGraph` called when done ## When to Use This Skill Use this skill **after** the `entra-id-aspire-authentication` skill has added authentication code. This skill: - Creates or updates Entra ID app registrations - Configures App ID URIs and scopes for APIs - Sets up redirect URIs for web apps - Generates client secrets and stores them securely - Updates `appsettings.json` with `TenantId`, `ClientId`, and scopes ## Workflow ### Step 1: Detect Project Types Scan `Program.cs` files to identify which projects need app registrations: ```powershell # Detect projects with Microsoft.Identity.Web Get-ChildItem -Recurse -Filter "Program.cs" | ForEach-Object { $content = Get-Content $_.FullName -Raw $projectDir = Split-Path $_.FullName -Parent $projectName = Split-Path $projectDir -Leaf if ($content -match "AddMicrosoftIdentityWebApi") { Write-Host "API: $projectName" } elseif ($content -match "AddMicrosoftIdentityWebApp") { Write-Host "WebApp: $projectName" } } ``` ### Step 2: Gather Configuration Before provisioning, the agent MUST gather required information interactively. #### 2a. Get Tenant ID First, detect the default tenant from the current connection if Microsoft Graph powershell is connected: ```powershell $context = Get-MgContext if ($context) { $defaultTenant = $context.TenantId Write-Host "Connected to tenant: $defaultTenant" } else { Write-Host "Not connected. Run: Connect-MgGraph -TenantId '<tenant-id>' -Scopes 'Application.ReadWrite.All'" } ``` **AGENT: Ask the user:** > "I detected tenant ID `{defaultTenant}`. Should I use this tenant, or would you like to specify a different one?" - If user confirms → use `$defaultTenant` - If user provides different ID → use that value - If not connected → instruct user to run `Connect-MgGraph` first #### 2b. Check for Existing ClientIds in appsettings.json Before asking about new vs. existing apps, scan `appsettings.json` files: ```powershell # === Detect existing ClientIds from appsettings.json === $projects = @() Get-ChildItem -Recurse -Filter "Program.cs" | ForEach-Object { $content = Get-Content $_.FullName -Raw $projectDir = Split-Path $_.FullName -Parent $projectName = Split-Path $projectDir -Leaf # Skip AppHost and ServiceDefaults if ($projectName -match "AppHost|ServiceDefaults") { return } $appSettingsPath = Join-Path $projectDir "appsettings.json" $existingClientId = $null $isPlaceholder = $false if (Test-Path $appSettingsPath) { $appSettings = Get-Content $appSettingsPath -Raw | ConvertFrom-Json if ($appSettings.AzureAd.ClientId) { $clientId = $appSettings.AzureAd.ClientId # Check if it's a placeholder value if ($clientId -match "^<.*>$" -or $clientId -match "YOUR_" -or $clientId -eq "") { $isPlaceholder = $true } else { $existingClientId = $clientId } } } $projectType = $null if ($content -match "AddMicrosoftIdentityWebApi") { $projectType = "API" } elseif ($content -match "AddMicrosoftIdentityWebApp") { $projectType = "WebApp" } if ($projectType) { $projects += @{ Name = $projectName Path = $projectDir Type = $projectType ExistingClientId = $existingClientId IsPlaceholder = $isPlaceholder } } } # Output findings $projects | ForEach-Object { if ($_.ExistingClientId) { Write-Host "$($_.Type): $($_.Name) - EXISTING ClientId: $($_.ExistingClientId)" -ForegroundColor Yellow } elseif ($_.IsPlaceholder) { Write-Host "$($_.Type): $($_.Name) - Placeholder ClientId (needs provisioning)" -ForegroundColor Cyan } else { Write-Host "$($_.Type): $($_.Name) - No ClientId configured" -ForegroundColor Cyan } } ``` **AGENT: Based on findings, ask the user:** **If existing ClientIds found:** > "I found existing app registrations in your configuration: > - **API** (`{apiProjectName}`): ClientId `{apiClientId}` > - **Web App** (`{webProjectName}`): ClientId `{webClientId}` > > Should I: > 1. **Use these existing apps** and complement them if needed (add missing scopes, redirect URIs)? > 2. **Create new app registrations** and update the configuration?" **If only placeholders or no ClientIds:** > "No existing app registrations found in `appsettings.json`. I'll create new ones." - If user chooses **existing** → use the "Existing App Flow" section with detected ClientIds - If user chooses **new** → proceed to Step 3 #### 2c. Confirm or Provide ClientIds Based on the detection results, present options to the user: **AGENT: Ask the user:** > "I found the following configuration: > - **API** (`{apiProjectName}`): {`ClientId: {id}` OR `No ClientId configured`} > - **Web App** (`{webProjectName}`): {`ClientId: {id}` OR `No ClientId configured`} > > What would you like to do? > 1. **Create new app registrations** for projects without valid ClientIds > 2. **Use existing app registrations** — provide ClientIds if not detected > 3. **Replace all** — create new apps even if ClientIds exist" **If user provides ClientIds manually:** > "Please provide the ClientIds: > - API ClientId: ___ > - Web App ClientId: ___" Store the final decision: ```powershell # Final configuration after user input $apiConfig = @{ ProjectName = "MyService.ApiService" ProjectPath = "path/to/api" ClientId = $null # Or user-provided/detected GUID Action = "Create" # Or "UseExisting" } $webConfig = @{ ProjectName = "MyService.Web" ProjectPath = "path/to/web" ClientId = $null # Or user-provided/detected GUID Action = "Create" # Or "UseExisting" } ``` **Decision logic:** - If `Action = "Create"` → proceed to Step 3 (provision new app) - If `Action = "UseExisting"` → use the "Existing App Flow" section with the ClientId (detected or user-provided) > **Important for existing apps:** > - **Web APIs**: The Existing App Flow checks for and adds `access_as_user` scope if missing > - **Web Apps**: Run Step 5 (Discover Redirect URIs) first, then pass URIs to Existing App Flow to add any missing redirect URIs > - **Both**: App ID URI and service principal are created if missing ### Step 3: Provision API App Registration For each project with `AddMicrosoftIdentityWebApi`: ```powershell # === Provision API App Registration === param( [Parameter(Mandatory=$true)][string]$TenantId, [Parameter(Mandatory=$true)][string]$DisplayName, [string]$SignInAudience = "AzureADMyOrg" ) Write-Host "Creating API app registration: $DisplayName" -ForegroundColor Cyan # Create the app registration $apiApp = New-MgApplication -DisplayName $DisplayName -SignInAudience $SignInAudience $apiClientId = $apiApp.AppId $apiObjectId = $apiApp.Id Write-Host "Created app: $apiClientId" # Set App ID URI $appIdUri = "api://$apiClientId" Update-MgApplication -ApplicationId $apiObjectId -IdentifierUris @($appIdUri) Write-Host "Set App ID URI: $appIdUri" # Expose scope: access_as_user $scopeId = [guid]::NewGuid().ToString() $scope = @{ Id = $scopeId AdminConsentDescription = "Allow the application to access $DisplayName on behalf of the signed-in user." AdminConsentDisplayName = "Access $DisplayName" IsEnabled = $true Type = "User" UserConsentDescription = "Allow the application to access $DisplayName on your behalf." UserConsentDisplayName = "Access $DisplayName" Value = "access_as_user" } $api = @{ Oauth2PermissionScopes = @($scope) } Update-MgApplication -ApplicationId $apiObjectId -Api $api Write-Host "Added scope: access_as_user (id: $scopeId)" # Create service principal New-MgServicePrincipal -AppId $apiClientId | Out-Null Write-Host "Created service principal" # Add current user as owner (using Invoke-MgGraphRequest for robustness - avoids module version issues) $currentUser = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/v1.0/me" if ($currentUser) { $ownerRef = @{ "@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$($currentUser.id)" } New-MgApplicationOwnerByRef -ApplicationId $apiObjectId -BodyParameter $ownerRef Write-Host "Added owner: $($currentUser.userPrincipalName)" } # Output for next steps Write-Host "" Write-Host "=== API Provisioning Complete ===" -ForegroundColor Green Write-Host "ClientId: $apiClientId" Write-Host "AppIdUri: $appIdUri" Write-Host "ScopeId: $scopeId" Write-Host "Owner: $($currentUser.userPrincipalName)" ``` ### Step 4: Update API appsettings.json Update the API project's `appsettings.json`: ```json { "AzureAd": { "Instance": "https://login.microsoftonline.com/", "TenantId": "<tenant-id>", "ClientId": "<api-client-id>", "Audiences": ["api://<api-client-id>"] } } ``` ### Step 5: Discover Redirect URIs Parse `Properties/launchSettings.json` for the web project: ```powershell # === Discover Redirect URIs === param( [Parameter(Mandatory=$true)][string]$ProjectPath ) $launchSettingsPath = Join-Path $ProjectPath "Properties/launchSettings.json" $launchSettings = Get-Content $launchSettingsPath | ConvertFrom-Json $redirectUris = @() foreach ($profile in $launchSettings.profiles.PSObject.Properties) { $appUrl = $profile.Value.applicationUrl if ($appUrl) { $urls = $appUrl -split ";" foreach ($url in $urls) { if ($url -match "^https://") { $redirectUris += "$url/signin-oidc" } } } } Write-Host "Redirect URIs: $($redirectUris -join ', ')" $redirectUris ``` ### Step 6: Provision Web App Registration For each project with `AddMicrosoftIdentityWebApp`: ```powershell # === Provision Web App Registration === param( [Parameter(Mandatory=$true)][string]$TenantId, [Parameter(Mandatory=$true)][string]$DisplayName, [Parameter(Mandatory=$true)][string]$ApiClientId, [Parameter(Mandatory=$true)][string]$ApiScopeId, [Parameter(Mandatory=$true)][string[]]$RedirectUris, [string]$SignInAudience = "AzureADMyOrg" ) Write-Host "Creating Web app registration: $DisplayName" -ForegroundColor Cyan # Configure web platform with redirect URIs and enable ID tokens $webConfig = @{ RedirectUris = $RedirectUris ImplicitGrantSettings = @{ EnableIdTokenIssuance = $true } } # Create the app registration $webApp = New-MgApplication ` -DisplayName $DisplayName ` -SignInAudience $SignInAudience ` -Web $webConfig $webClientId = $webApp.AppId $webObjectId = $webApp.Id Write-Host "Created app: $webClientId" # Add API permission for access_as_user scope # First, get the Microsoft Graph resource ID for the API $apiServicePrincipal = Get-MgServicePrincipal -Filter "appId eq '$ApiClientId'" $requiredResourceAccess = @{ ResourceAppId = $ApiClientId ResourceAccess = @( @{
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub