# MS Entra (Azure AD) Setup Script for Miracles In Motion (PowerShell) # This script helps configure Azure AD authentication for the application param( [Parameter(Mandatory=$false)] [string]$AppName = "Miracles In Motion Web App", [Parameter(Mandatory=$false)] [string]$Domain = "mim4u.org", [Parameter(Mandatory=$false)] [string]$StaticWebAppName = "", [Parameter(Mandatory=$false)] [string]$AzureResourceGroup = "rg-miraclesinmotion-prod", [Parameter(Mandatory=$false)] [string]$KeyVaultName = "" ) $ErrorActionPreference = "Stop" Write-Host "🔐 MS Entra (Azure AD) Setup Script" -ForegroundColor Green Write-Host "==========================================" -ForegroundColor Green Write-Host "" # Check if Azure CLI is installed if (-not (Get-Command "az" -ErrorAction SilentlyContinue)) { Write-Host "❌ Azure CLI not found. Please install it first." -ForegroundColor Red Write-Host "Install from: https://docs.microsoft.com/cli/azure/install-azure-cli" -ForegroundColor Yellow exit 1 } # Check if logged in to Azure Write-Host "📋 Checking Azure login status..." -ForegroundColor Cyan $account = az account show --output json 2>$null | ConvertFrom-Json if (-not $account) { Write-Host "⚠️ Not logged in to Azure. Please log in..." -ForegroundColor Yellow az login $account = az account show --output json | ConvertFrom-Json } Write-Host "✅ Logged in as: $($account.user.name)" -ForegroundColor Green Write-Host "" # Get Azure Static Web App URL Write-Host "📋 Getting Azure Static Web App information..." -ForegroundColor Cyan if ([string]::IsNullOrEmpty($StaticWebAppName)) { # Try to find Static Web App $swa = az staticwebapp list --resource-group $AzureResourceGroup --output json | ConvertFrom-Json | Select-Object -First 1 if ($swa) { $StaticWebAppName = $swa.name } } $azureStaticWebAppUrl = "" if (-not [string]::IsNullOrEmpty($StaticWebAppName)) { $azureStaticWebAppUrl = az staticwebapp show ` --name $StaticWebAppName ` --resource-group $AzureResourceGroup ` --query "defaultHostname" -o tsv 2>$null if ($azureStaticWebAppUrl) { $azureStaticWebAppUrl = "https://$azureStaticWebAppUrl" Write-Host "✅ Static Web App URL: $azureStaticWebAppUrl" -ForegroundColor Green } } else { Write-Host "⚠️ Static Web App not found. Using default URL format." -ForegroundColor Yellow $azureStaticWebAppUrl = "https://${StaticWebAppName}.azurestaticapps.net" } $productionUrl = "https://$Domain" $wwwUrl = "https://www.$Domain" Write-Host "" # Get Tenant ID $tenantId = $account.tenantId Write-Host "✅ Tenant ID: $tenantId" -ForegroundColor Green Write-Host "" # Check if app registration already exists Write-Host "🔍 Checking for existing app registration..." -ForegroundColor Cyan $existingApp = az ad app list --display-name $AppName --output json | ConvertFrom-Json | Select-Object -First 1 if ($existingApp) { Write-Host "⚠️ App registration already exists: $($existingApp.appId)" -ForegroundColor Yellow $updateApp = Read-Host "Do you want to update it? (y/n)" if ($updateApp -ne "y") { $appId = $existingApp.appId Write-Host "✅ Using existing app registration" -ForegroundColor Green } else { $appId = $existingApp.appId Write-Host "📝 Updating app registration..." -ForegroundColor Cyan } } else { # Create app registration Write-Host "📝 Creating app registration..." -ForegroundColor Cyan $appId = az ad app create ` --display-name $AppName ` --sign-in-audience "AzureADMultipleOrgs" ` --web-redirect-uris $productionUrl $wwwUrl $azureStaticWebAppUrl ` --query "appId" -o tsv Write-Host "✅ App registration created: $appId" -ForegroundColor Green } Write-Host "" # Update redirect URIs Write-Host "📝 Updating redirect URIs..." -ForegroundColor Cyan az ad app update --id $appId ` --web-redirect-uris $productionUrl $wwwUrl $azureStaticWebAppUrl ` --enable-id-token-issuance true ` --enable-access-token-issuance false | Out-Null Write-Host "✅ Redirect URIs updated" -ForegroundColor Green Write-Host " - $productionUrl" Write-Host " - $wwwUrl" Write-Host " - $azureStaticWebAppUrl" Write-Host "" # Configure API permissions Write-Host "📝 Configuring API permissions..." -ForegroundColor Cyan $graphPermissions = @( "User.Read", "User.ReadBasic.All", "email", "openid", "profile" ) foreach ($permission in $graphPermissions) { Write-Host " Adding permission: $permission" -ForegroundColor Gray $permissionId = az ad sp show --id "00000003-0000-0000-c000-000000000000" --query "oauth2PermissionScopes[?value=='$permission'].id" -o tsv if ($permissionId) { az ad app permission add ` --id $appId ` --api "00000003-0000-0000-c000-000000000000" ` --api-permissions "${permissionId}=Scope" 2>$null | Out-Null } } Write-Host "✅ API permissions configured" -ForegroundColor Green Write-Host "" # Create service principal Write-Host "📝 Creating service principal..." -ForegroundColor Cyan $spId = az ad sp create --id $appId --query "id" -o tsv 2>$null if (-not $spId) { $spId = az ad sp show --id $appId --query "id" -o tsv } Write-Host "✅ Service principal created: $spId" -ForegroundColor Green Write-Host "" # Grant admin consent Write-Host "📝 Granting admin consent for API permissions..." -ForegroundColor Cyan $hasAdmin = Read-Host "Do you have admin privileges to grant consent? (y/n)" if ($hasAdmin -eq "y") { az ad app permission admin-consent --id $appId 2>$null if ($LASTEXITCODE -eq 0) { Write-Host "✅ Admin consent granted" -ForegroundColor Green } else { Write-Host "⚠️ Could not grant admin consent. You may need to do this manually." -ForegroundColor Yellow Write-Host " Go to: Azure Portal → Microsoft Entra ID → App registrations → $AppName → API permissions → Grant admin consent" -ForegroundColor Yellow } } else { Write-Host "⚠️ Skipping admin consent. Please grant consent manually in Azure Portal." -ForegroundColor Yellow Write-Host " Go to: Azure Portal → Microsoft Entra ID → App registrations → $AppName → API permissions → Grant admin consent" -ForegroundColor Yellow } Write-Host "" # Create client secret Write-Host "📝 Client Secret Configuration..." -ForegroundColor Cyan $createSecret = Read-Host "Do you want to create a client secret? (y/n)" $clientSecret = "" if ($createSecret -eq "y") { $secretName = "Miracles In Motion Secret $(Get-Date -Format 'yyyyMMdd')" $clientSecret = az ad app credential reset --id $appId --display-name $secretName --years 2 --query "password" -o tsv Write-Host "✅ Client secret created" -ForegroundColor Green Write-Host "⚠️ IMPORTANT: Save this secret now - it won't be shown again!" -ForegroundColor Red Write-Host "Secret: $clientSecret" -ForegroundColor Yellow Write-Host "" Read-Host "Press Enter to continue after saving the secret..." } else { Write-Host "⚠️ Skipping client secret creation" -ForegroundColor Yellow } Write-Host "" # Store configuration in Key Vault Write-Host "📝 Storing configuration in Key Vault..." -ForegroundColor Cyan if ([string]::IsNullOrEmpty($KeyVaultName)) { $KeyVaultName = az keyvault list --resource-group $AzureResourceGroup --query "[0].name" -o tsv 2>$null } if ($KeyVaultName) { Write-Host "Storing in Key Vault: $KeyVaultName" -ForegroundColor Gray az keyvault secret set --vault-name $KeyVaultName --name "azure-client-id" --value $appId 2>$null | Out-Null if ($LASTEXITCODE -eq 0) { Write-Host "✅ Client ID stored" -ForegroundColor Green } else { Write-Host "⚠️ Could not store Client ID" -ForegroundColor Yellow } az keyvault secret set --vault-name $KeyVaultName --name "azure-tenant-id" --value $tenantId 2>$null | Out-Null if ($LASTEXITCODE -eq 0) { Write-Host "✅ Tenant ID stored" -ForegroundColor Green } else { Write-Host "⚠️ Could not store Tenant ID" -ForegroundColor Yellow } if ($clientSecret) { az keyvault secret set --vault-name $KeyVaultName --name "azure-client-secret" --value $clientSecret 2>$null | Out-Null if ($LASTEXITCODE -eq 0) { Write-Host "✅ Client Secret stored" -ForegroundColor Green } else { Write-Host "⚠️ Could not store Client Secret" -ForegroundColor Yellow } } } else { Write-Host "⚠️ Key Vault not found. Skipping secret storage." -ForegroundColor Yellow } Write-Host "" # Summary Write-Host "✅ MS Entra Setup Complete!" -ForegroundColor Green Write-Host "==================================" -ForegroundColor Green Write-Host "" Write-Host "Configuration Summary:" Write-Host " App Registration ID: $appId" Write-Host " Tenant ID: $tenantId" Write-Host " Service Principal ID: $spId" Write-Host "" Write-Host "Redirect URIs:" Write-Host " - $productionUrl" Write-Host " - $wwwUrl" Write-Host " - $azureStaticWebAppUrl" Write-Host "" Write-Host "Next Steps:" Write-Host "1. Assign users to app roles in Azure Portal" Write-Host "2. Update staticwebapp.config.json with authentication configuration" Write-Host "3. Update application code to use Azure AD authentication" Write-Host "4. Test authentication flow" Write-Host "" Write-Host "Azure Portal Links:" Write-Host " App Registration: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/appId/$appId" Write-Host " API Permissions: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/CallAnAPI/appId/$appId" Write-Host "" # Export variables $configContent = @" # Azure AD Configuration AZURE_CLIENT_ID=$appId AZURE_TENANT_ID=$tenantId AZURE_CLIENT_SECRET=$clientSecret AZURE_STATIC_WEB_APP_URL=$azureStaticWebAppUrl AZURE_PRODUCTION_URL=$productionUrl "@ $configContent | Out-File -FilePath ".azure-entra-config.env" -Encoding UTF8 Write-Host "✅ Configuration saved to .azure-entra-config.env" -ForegroundColor Green Write-Host ""