Repository navigation
Expand file tree
/
Copy pathsetup-entra-auth.ps1
More file actions
121 lines (105 loc) · 5.75 KB
/
Copy pathsetup-entra-auth.ps1
File metadata and controls
121 lines (105 loc) · 5.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#Requires -Version 7.0
<#
.SYNOPSIS
Creates a Microsoft Entra ID app registration for the GenAI Workshop.
.DESCRIPTION
Logs in to the specified tenant, creates an app registration with the correct
redirect URIs and optional claims, and outputs the .env.local block to copy.
Does not require an Azure subscription — only Entra ID tenant access.
.EXAMPLE
.\setup-entra-auth.ps1 -TenantId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -AppName "GenAI Workshop"
.EXAMPLE
.\setup-entra-auth.ps1 -TenantId "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -AppName "GenAI Workshop" `
-ProductionUrl "https://myapp.azurewebsites.net" -SecretExpiryYears 2
#>
param(
[Parameter(Mandatory = $true)]
[string]$TenantId,
[Parameter(Mandatory = $true)]
[string]$AppName,
[string]$ProductionUrl = "",
[int]$SecretExpiryYears = 1
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# ── Login (skip if already authenticated to the target tenant) ─────────────────
$currentTenant = az account show --query "tenantId" -o tsv 2>$null
if ($currentTenant -eq $TenantId) {
Write-Host "Already logged in to tenant $TenantId." -ForegroundColor Green
} else {
Write-Host "Logging in to tenant $TenantId..." -ForegroundColor Cyan
az login --tenant $TenantId --allow-no-subscriptions
if ($LASTEXITCODE -ne 0) { throw "az login failed" }
}
# ── Guard: abort if an app with this name already exists ──────────────────────
$existing = az ad app list --display-name $AppName --query "[0].appId" -o tsv 2>$null
if ($existing) {
Write-Host ""
Write-Host "ERROR: An app registration named '$AppName' already exists (appId: $existing)." -ForegroundColor Red
Write-Host "Delete it first or choose a different -AppName to avoid duplicates." -ForegroundColor Red
exit 1
}
# ── Create app registration ────────────────────────────────────────────────────
Write-Host "Creating app registration '$AppName'..." -ForegroundColor Cyan
$app = az ad app create `
--display-name $AppName `
--sign-in-audience AzureADMyOrg `
| ConvertFrom-Json
if ($LASTEXITCODE -ne 0) { throw "Failed to create app registration" }
$clientId = $app.appId
Write-Host " App ID: $clientId" -ForegroundColor Green
# ── Redirect URIs ──────────────────────────────────────────────────────────────
$callbackPath = "/api/auth/callback/microsoft-entra-id"
$redirectUris = @("http://localhost:3000$callbackPath")
if ($ProductionUrl) {
$productionUri = $ProductionUrl.TrimEnd("/") + $callbackPath
$redirectUris += $productionUri
Write-Host " Adding production redirect: $productionUri" -ForegroundColor Cyan
}
Write-Host "Setting redirect URIs..." -ForegroundColor Cyan
az ad app update --id $clientId --web-redirect-uris @redirectUris
if ($LASTEXITCODE -ne 0) { throw "Failed to set redirect URIs" }
# ── Optional claims (email + name on ID token) ─────────────────────────────────
Write-Host "Adding optional claims (email, given_name, family_name)..." -ForegroundColor Cyan
$claimsFile = [System.IO.Path]::GetTempFileName()
@{
accessToken = @()
saml2Token = @()
idToken = @(
@{ name = "email"; essential = $false }
@{ name = "given_name"; essential = $false }
@{ name = "family_name"; essential = $false }
)
} | ConvertTo-Json -Depth 5 | Set-Content -Path $claimsFile -Encoding UTF8
az ad app update --id $clientId --optional-claims "@$claimsFile"
if ($LASTEXITCODE -ne 0) {
Remove-Item $claimsFile -Force
throw "Failed to set optional claims"
}
Remove-Item $claimsFile -Force
# ── Service principal ──────────────────────────────────────────────────────────
Write-Host "Creating service principal..." -ForegroundColor Cyan
az ad sp create --id $clientId | Out-Null
if ($LASTEXITCODE -ne 0) { throw "Failed to create service principal" }
# ── Client secret ──────────────────────────────────────────────────────────────
$endDate = (Get-Date).AddYears($SecretExpiryYears).ToString("yyyy-MM-dd")
Write-Host "Creating client secret (expires $endDate)..." -ForegroundColor Cyan
$secretResult = az ad app credential reset `
--id $clientId `
--append `
--end-date $endDate `
| ConvertFrom-Json
if ($LASTEXITCODE -ne 0) { throw "Failed to create client secret" }
$clientSecret = $secretResult.password
# ── Output ─────────────────────────────────────────────────────────────────────
Write-Host ""
Write-Host "==========================================================" -ForegroundColor Green
Write-Host " App registration complete. Copy this into your .env.local:" -ForegroundColor Green
Write-Host "==========================================================" -ForegroundColor Green
Write-Host ""
Write-Host "AUTH_MICROSOFT_ENTRA_ID_ISSUER=https://login.microsoftonline.com/$TenantId/v2.0"
Write-Host "AUTH_MICROSOFT_ENTRA_ID_ID=$clientId"
Write-Host "AUTH_MICROSOFT_ENTRA_ID_SECRET=$clientSecret"
Write-Host "AUTH_SECRET= # generate with: npx auth secret"
Write-Host ""
Write-Host "WARNING: The client secret above will not be shown again. Copy it now." -ForegroundColor Yellow