From 8e9e0552f2d0f0b8a12aaaabc944ac42a2209e22 Mon Sep 17 00:00:00 2001 From: Gina Triolo <51341242+gitri-ms@users.noreply.github.com> Date: Sat, 12 Aug 2023 01:22:48 -0700 Subject: [PATCH] Update scripts and bug fixes --- scripts/Configure.ps1 | 2 +- scripts/deploy/README.md | 10 ++++++---- scripts/deploy/deploy-azure.ps1 | 6 +++--- scripts/deploy/deploy-azure.sh | 10 +++++----- scripts/deploy/deploy-webapp.ps1 | 19 +++++++++++------- scripts/deploy/deploy-webapp.sh | 31 ++++++++++++++++++----------- webapp/src/libs/auth/TokenHelper.ts | 2 +- 7 files changed, 47 insertions(+), 33 deletions(-) diff --git a/scripts/Configure.ps1 b/scripts/Configure.ps1 index 756f2031b..eb1540de3 100644 --- a/scripts/Configure.ps1 +++ b/scripts/Configure.ps1 @@ -172,7 +172,7 @@ Set-Content -Path $webappEnvFilePath -Value "REACT_APP_BACKEND_URI=https://local if ($authType -eq $varAzureAd) { Write-Host "Configuring Azure AD authentication..." Add-Content -Path $webappEnvFilePath -Value "REACT_APP_AUTH_TYPE=AzureAd" - Add-Content -Path $webappEnvFilePath -Value "REACT_APP_AAD_AUTHORITY=https://$($Instance.Trim("/"))/$TenantId" + Add-Content -Path $webappEnvFilePath -Value "REACT_APP_AAD_AUTHORITY=$($Instance.Trim("/"))/$TenantId" Add-Content -Path $webappEnvFilePath -Value "REACT_APP_AAD_CLIENT_ID=$FrontendClientId" Add-Content -Path $webappEnvFilePath -Value "REACT_APP_AAD_API_SCOPE=api://$BackendClientId/access_as_user" } diff --git a/scripts/deploy/README.md b/scripts/deploy/README.md index b20aad0cf..3fd507f50 100644 --- a/scripts/deploy/README.md +++ b/scripts/deploy/README.md @@ -30,16 +30,18 @@ You will need two Azure Active Directory (AAD) application registrations -- one > For details on creating an application registration, go [here](https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app). +> NOTE: Other account types can be used to allow multitenant and personal Microsoft accounts to use your application if you desire. Doing so may result in more users and therefore higher costs. + ### Frontend app registration - Select `Single-page application (SPA)` as platform type, and set the redirect URI to `http://localhost:3000` -- Select `Accounts in any organizational directory and personal Microsoft Accounts` as supported account types. +- Select `Accounts in this organizational directory only ({YOUR TENANT} only - Single tenant)` as supported account types. - Make a note of the `Application (client) ID` from the Azure Portal for use in the `Deploy Frontend` step below. ### Backend app registration - Do not set a redirect URI -- Select `Accounts in any organizational directory and personal Microsoft Accounts` as supported account types. +- Select `Accounts in this organizational directory only ({YOUR TENANT} only - Single tenant)` as supported account types. - Make a note of the `Application (client) ID` from the Azure Portal for use in the `Deploy Azure infrastructure` step below. ### Linking the frontend to the backend @@ -85,7 +87,7 @@ The examples below assume you are using an existing Azure OpenAI resource. See t ## PowerShell ```powershell -./deploy-azure.ps1 -Subscription {YOUR_SUBSCRIPTION_ID} -DeploymentName {YOUR_DEPLOYMENT_NAME} -AIService {AzureOpenAI or OpenAI} -AIApiKey {YOUR_AI_KEY} -AIEndpoint {YOUR_AZURE_OPENAI_ENDPOINT} -WebApiClientId {YOUR_BACKEND_APPLICATION_ID} -TenantId {YOUR_TENANT_ID} +./deploy-azure.ps1 -Subscription {YOUR_SUBSCRIPTION_ID} -DeploymentName {YOUR_DEPLOYMENT_NAME} -AIService {AzureOpenAI or OpenAI} -AIApiKey {YOUR_AI_KEY} -AIEndpoint {YOUR_AZURE_OPENAI_ENDPOINT} -BackendClientId {YOUR_BACKEND_APPLICATION_ID} -TenantId {YOUR_TENANT_ID} ``` - To use an existing Azure OpenAI resource, set `-AIService` to `AzureOpenAI` and include `-AIApiKey` and `-AIEndpoint`. @@ -96,7 +98,7 @@ The examples below assume you are using an existing Azure OpenAI resource. See t ```bash chmod +x ./deploy-azure.sh -./deploy-azure.sh --subscription {YOUR_SUBSCRIPTION_ID} --deployment-name {YOUR_DEPLOYMENT_NAME} --ai-service {AzureOpenAI or OpenAI} --ai-service-key {YOUR_AI_KEY} --ai-endpoint {YOUR_AZURE_OPENAI_ENDPOINT} --client-id{YOUR_BACKEND_APPLICATION_ID} --tenant-id {YOUR_TENANT_ID} +./deploy-azure.sh --subscription {YOUR_SUBSCRIPTION_ID} --deployment-name {YOUR_DEPLOYMENT_NAME} --ai-service {AzureOpenAI or OpenAI} --ai-service-key {YOUR_AI_KEY} --ai-endpoint {YOUR_AZURE_OPENAI_ENDPOINT} --client-id {YOUR_BACKEND_APPLICATION_ID} --tenant-id {YOUR_TENANT_ID} ``` - To use an existing Azure OpenAI resource, set `--ai-service` to `AzureOpenAI` and include `--ai-service-key` and `--ai-endpoint`. diff --git a/scripts/deploy/deploy-azure.ps1 b/scripts/deploy/deploy-azure.ps1 index 82fb4201b..92ed9d76f 100644 --- a/scripts/deploy/deploy-azure.ps1 +++ b/scripts/deploy/deploy-azure.ps1 @@ -17,7 +17,7 @@ param( [Parameter(Mandatory)] [string] # Azure AD client ID for the Web API backend app registration - $WebApiClientId, + $BackendClientId, [Parameter(Mandatory)] [string] @@ -56,7 +56,7 @@ param( [string] # Azure AD cloud instance for authenticating users - $AzureAdInstance = "https://login.microsoftonline.com/", + $AzureAdInstance = "https://login.microsoftonline.com", [ValidateSet("Volatile", "AzureCognitiveSearch", "Qdrant")] [string] @@ -110,7 +110,7 @@ $jsonConfig = " `\`"aiEndpoint`\`": { `\`"value`\`": `\`"$AIEndpoint`\`" }, `\`"azureAdInstance`\`": { `\`"value`\`": `\`"$AzureAdInstance`\`" }, `\`"azureAdTenantId`\`": { `\`"value`\`": `\`"$TenantId`\`" }, - `\`"webApiClientId`\`": { `\`"value`\`": `\`"$WebApiClientId`\`"}, + `\`"webApiClientId`\`": { `\`"value`\`": `\`"$BackendClientId`\`"}, `\`"deployNewAzureOpenAI`\`": { `\`"value`\`": $(If ($DeployAzureOpenAI) {"true"} Else {"false"}) }, `\`"memoryStore`\`": { `\`"value`\`": `\`"$MemoryStore`\`" }, `\`"deployCosmosDB`\`": { `\`"value`\`": $(If (!($NoCosmosDb)) {"true"} Else {"false"}) }, diff --git a/scripts/deploy/deploy-azure.sh b/scripts/deploy/deploy-azure.sh index 702fc2252..76b544ef6 100755 --- a/scripts/deploy/deploy-azure.sh +++ b/scripts/deploy/deploy-azure.sh @@ -5,12 +5,12 @@ set -e usage() { - echo "Usage: $0 -d DEPLOYMENT_NAME -s SUBSCRIPTION -c WEBAPI_CLIENT_ID -t AZURE_AD_TENANT_ID -ai AI_SERVICE_TYPE -aikey AI_SERVICE_KEY [OPTIONS]" + echo "Usage: $0 -d DEPLOYMENT_NAME -s SUBSCRIPTION -c BACKEND_CLIENT_ID -t AZURE_AD_TENANT_ID -ai AI_SERVICE_TYPE -aikey AI_SERVICE_KEY [OPTIONS]" echo "" echo "Arguments:" echo " -d, --deployment-name DEPLOYMENT_NAME Name for the deployment (mandatory)" echo " -s, --subscription SUBSCRIPTION Subscription to which to make the deployment (mandatory)" - echo " -c, --client-id WEBAPI_CLIENT_ID Azure AD client ID for the Web API backend app registration (mandatory)" + echo " -c, --client-id BACKEND_CLIENT_ID Azure AD client ID for the Web API backend app registration (mandatory)" echo " -t, --tenant-id AZURE_AD_TENANT_ID Azure AD tenant ID for authenticating users (mandatory)" echo " -ai, --ai-service AI_SERVICE_TYPE Type of AI service to use (i.e., OpenAI or AzureOpenAI)" echo " -aikey, --ai-service-key AI_SERVICE_KEY API key for existing Azure OpenAI resource or OpenAI account" @@ -44,7 +44,7 @@ while [[ $# -gt 0 ]]; do shift ;; -c|--client-id) - WEBAPI_CLIENT_ID="$2" + BACKEND_CLIENT_ID="$2" shift shift ;; @@ -122,7 +122,7 @@ while [[ $# -gt 0 ]]; do done # Check mandatory arguments -if [[ -z "$DEPLOYMENT_NAME" ]] || [[ -z "$SUBSCRIPTION" ]] || [[ -z "$WEBAPI_CLIENT_ID" ]] || [[ -z "$AZURE_AD_TENANT_ID" ]] || [[ -z "$AI_SERVICE_TYPE" ]]; then +if [[ -z "$DEPLOYMENT_NAME" ]] || [[ -z "$SUBSCRIPTION" ]] || [[ -z "$BACKEND_CLIENT_ID" ]] || [[ -z "$AZURE_AD_TENANT_ID" ]] || [[ -z "$AI_SERVICE_TYPE" ]]; then usage exit 1 fi @@ -195,7 +195,7 @@ JSON_CONFIG=$(cat << EOF "aiEndpoint": { "value": "$([ ! -z "$AI_ENDPOINT" ] && echo "$AI_ENDPOINT")" }, "azureAdInstance": { "value": "$AZURE_AD_INSTANCE" }, "azureAdTenantId": { "value": "$AZURE_AD_TENANT_ID" }, - "webApiClientId": { "value": "$WEBAPI_CLIENT_ID" }, + "webApiClientId": { "value": "$BACKEND_CLIENT_ID" }, "deployNewAzureOpenAI": { "value": $([ "$NO_NEW_AZURE_OPENAI" = true ] && echo "false" || echo "true") }, "memoryStore": { "value": "$MEMORY_STORE" }, "deployCosmosDB": { "value": $([ "$NO_COSMOS_DB" = true ] && echo "false" || echo "true") }, diff --git a/scripts/deploy/deploy-webapp.ps1 b/scripts/deploy/deploy-webapp.ps1 index a47cbe27f..5d631c87c 100644 --- a/scripts/deploy/deploy-webapp.ps1 +++ b/scripts/deploy/deploy-webapp.ps1 @@ -21,13 +21,18 @@ param( [Parameter(Mandatory)] [string] - # Client application id - $ApplicationClientId, + # Client application id for the frontend web app + $FrontendClientId, + + [Parameter(Mandatory)] + [string] + # Azure AD tenant id + $TenantId, [Parameter(Mandatory = $false)] [string] - # Authority for client applications that are not configured as multi-tenant. - $Authority = "https://login.microsoftonline.com/common" + # Azure cloud instance for authenticating users + $Instance = "https://login.microsoftonline.com" ) Write-Host "Setting up Azure credentials..." @@ -67,8 +72,8 @@ $envFilePath = "$PSScriptRoot/../../webapp/.env" Write-Host "Writing environment variables to '$envFilePath'..." "REACT_APP_BACKEND_URI=https://$webapiUrl/" | Out-File -FilePath $envFilePath "REACT_APP_AUTH_TYPE=AzureAd" | Out-File -FilePath $envFilePath -Append -"REACT_APP_AAD_AUTHORITY=$Authority" | Out-File -FilePath $envFilePath -Append -"REACT_APP_AAD_CLIENT_ID=$ApplicationClientId" | Out-File -FilePath $envFilePath -Append +"REACT_APP_AAD_AUTHORITY=$($Instance.Trim("/"))/$TenantId" | Out-File -FilePath $envFilePath -Append +"REACT_APP_AAD_CLIENT_ID=$FrontendClientId" | Out-File -FilePath $envFilePath -Append "REACT_APP_AAD_API_SCOPE=api://$webapiClientId/$webapiScope" | Out-File -FilePath $envFilePath -Append Write-Host "Generating SWA config..." @@ -109,7 +114,7 @@ if (-not ((az webapp cors show --name $webapiName --resource-group $ResourceGrou } Write-Host "Ensuring '$origin' is included in AAD app registration's redirect URIs..." -$objectId = (az ad app show --id $ApplicationClientId | ConvertFrom-Json).id +$objectId = (az ad app show --id $FrontendClientId | ConvertFrom-Json).id $redirectUris = (az rest --method GET --uri "https://graph.microsoft.com/v1.0/applications/$objectId" --headers 'Content-Type=application/json' | ConvertFrom-Json).spa.redirectUris if ($redirectUris -notcontains "$origin") { $redirectUris += "$origin" diff --git a/scripts/deploy/deploy-webapp.sh b/scripts/deploy/deploy-webapp.sh index fcbb87730..6d6fcf671 100755 --- a/scripts/deploy/deploy-webapp.sh +++ b/scripts/deploy/deploy-webapp.sh @@ -7,14 +7,15 @@ set -e SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" usage() { - echo "Usage: $0 -d DEPLOYMENT_NAME -s SUBSCRIPTION --ai AI_SERVICE_TYPE -aikey AI_SERVICE_KEY [OPTIONS]" + echo "Usage: $0 -d DEPLOYMENT_NAME -s SUBSCRIPTION -rg RESOURCE_GROUP -c FRONTEND_CLIENT_ID -t AZURE_AD_TENANT_ID [OPTIONS]" echo "" echo "Arguments:" echo " -s, --subscription SUBSCRIPTION Subscription to which to make the deployment (mandatory)" echo " -rg, --resource-group RESOURCE_GROUP Resource group name from a 'deploy-azure.sh' deployment (mandatory)" echo " -d, --deployment-name DEPLOYMENT_NAME Name of the deployment from a 'deploy-azure.sh' deployment (mandatory)" - echo " -a, --application-id APPLICATION_ID Client application ID (mandatory)" - echo " -au, --authority Authority to use for client applications that are not configured as multi-tenant. Defaults to (https://login.microsoftonline.com/common) if not specified." + echo " -c, --client-id FRONTEND_CLIENT_ID Client application ID for the frontend web app (mandatory)" + echo " -t, --tenant-id AZURE_AD_TENANT_ID Azure AD tenant ID (mandatory)" + echo " -i, --instance AZURE_AD_INSTANCE Azure cloud instance for authenticating users. Defaults to (https://login.microsoftonline.com/) if not specified." echo " -nr, --no-redirect Do not attempt to register redirect URIs with the client application" } @@ -37,13 +38,18 @@ while [[ $# -gt 0 ]]; do shift shift ;; - -a|--application-id) - APPLICATION_ID="$2" + -c|--client-id) + FRONTEND_CLIENT_ID="$2" shift shift ;; - -au|--authority) - AUTHORITY="$2" + -t|--tenant-id) + TENANT_ID="$2" + shift + shift + ;; + -i|--instance) + INSTANCE="$2" shift shift ;; @@ -60,7 +66,7 @@ while [[ $# -gt 0 ]]; do done # Check mandatory arguments -if [[ -z "$DEPLOYMENT_NAME" ]] || [[ -z "$SUBSCRIPTION" ]] || [[ -z "$RESOURCE_GROUP" ]] || [[ -z "$APPLICATION_ID" ]]; then +if [[ -z "$DEPLOYMENT_NAME" ]] || [[ -z "$SUBSCRIPTION" ]] || [[ -z "$RESOURCE_GROUP" ]] || [[ -z "$FRONTEND_CLIENT_ID" ]] || [[ -z "$TENANT_ID" ]]; then usage exit 1 fi @@ -71,8 +77,8 @@ if [ $? -ne 0 ]; then az login --use-device-code fi -if [[ -z "$AUTHORITY" ]]; then - AUTHORITY="https://login.microsoftonline.com/common" +if [[ -z "$INSTANCE" ]]; then + INSTANCE="https://login.microsoftonline.com" fi az account set -s "$SUBSCRIPTION" @@ -98,8 +104,9 @@ ENV_FILE_PATH="$SCRIPT_ROOT/../../webapp/.env" echo "Writing environment variables to '$ENV_FILE_PATH'..." echo "REACT_APP_BACKEND_URI=https://$WEB_API_URL/" > $ENV_FILE_PATH echo "REACT_APP_AUTH_TYPE=AzureAd" >> $ENV_FILE_PATH -echo "REACT_APP_AAD_AUTHORITY=$AUTHORITY" >> $ENV_FILE_PATH -echo "REACT_APP_AAD_CLIENT_ID=$APPLICATION_ID" >> $ENV_FILE_PATH +# TODO: trim trailing slash from instance +echo "REACT_APP_AAD_AUTHORITY=$INSTANCE/$TENANT_ID" >> $ENV_FILE_PATH +echo "REACT_APP_AAD_CLIENT_ID=$FRONTEND_CLIENT_ID" >> $ENV_FILE_PATH echo "REACT_APP_AAD_API_SCOPE=api://$WEB_API_CLIENT_ID/$WEB_API_SCOPE" >> $ENV_FILE_PATH echo "Writing swa-cli.config.json..." diff --git a/webapp/src/libs/auth/TokenHelper.ts b/webapp/src/libs/auth/TokenHelper.ts index f1d8960d3..74b320c51 100644 --- a/webapp/src/libs/auth/TokenHelper.ts +++ b/webapp/src/libs/auth/TokenHelper.ts @@ -22,7 +22,7 @@ export const getAccessTokenUsingMsal = async ( // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const account = msalInstance.getActiveAccount()!; const accessTokenRequest: PopupRequest = { - authority: `https://login.microsoftonline.com/${account.tenantId}`, + authority: process.env.REACT_APP_AAD_AUTHORITY, scopes, extraScopesToConsent, account,