From 2e28c8663ac912a9cb60bc9b696b650019e90144 Mon Sep 17 00:00:00 2001 From: Anthony Shaw Date: Mon, 15 Jul 2024 11:32:47 +1000 Subject: [PATCH 1/4] Use AVM for OpenAI deployment --- infra/main.bicep | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/infra/main.bicep b/infra/main.bicep index 4d9de25ec4..4472d1a444 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -391,18 +391,20 @@ var openAiDeployments = concat(defaultOpenAiDeployments, useGPT4V ? [ } ] : []) -module openAi 'core/ai/cognitiveservices.bicep' = if (isAzureOpenAiHost && deployAzureOpenAi) { +module openAi 'br/public:avm/res/cognitive-services/account:0.5.4' = if (isAzureOpenAiHost && deployAzureOpenAi) { name: 'openai' scope: openAiResourceGroup params: { name: !empty(openAiServiceName) ? openAiServiceName : '${abbrs.cognitiveServicesAccounts}${resourceToken}' location: openAiResourceGroupLocation tags: tags + kind: 'OpenAI' publicNetworkAccess: publicNetworkAccess - bypass: bypass - sku: { - name: openAiSkuName + networkAcls: { + defaultAction: 'Allow' + bypass: bypass } + sku: openAiSkuName deployments: openAiDeployments disableLocalAuth: true } @@ -720,7 +722,7 @@ var openAiPrivateEndpointConnection = (isAzureOpenAiHost && deployAzureOpenAi) ? groupId: 'account' dnsZoneName: 'privatelink.openai.azure.com' resourceIds: concat( - [ openAi.outputs.id ], + [ openAi.outputs.resourceId ], useGPT4V ? [ computerVision.outputs.id ] : [], !useLocalPdfParser ? [ documentIntelligence.outputs.id ] : [] ) From ac26fd278b7a43ef08c43e2ad223976ba567969f Mon Sep 17 00:00:00 2001 From: Anthony Shaw Date: Mon, 15 Jul 2024 11:35:13 +1000 Subject: [PATCH 2/4] Use AVM for CV, Speech Services and Doc Intelligence --- infra/core/ai/cognitiveservices.bicep | 60 --------------------------- infra/main.bicep | 27 +++++------- 2 files changed, 10 insertions(+), 77 deletions(-) delete mode 100644 infra/core/ai/cognitiveservices.bicep diff --git a/infra/core/ai/cognitiveservices.bicep b/infra/core/ai/cognitiveservices.bicep deleted file mode 100644 index 14276cd3d0..0000000000 --- a/infra/core/ai/cognitiveservices.bicep +++ /dev/null @@ -1,60 +0,0 @@ -metadata description = 'Creates an Azure Cognitive Services instance.' -param name string -param location string = resourceGroup().location -param tags object = {} -@description('The custom subdomain name used to access the API. Defaults to the value of the name parameter.') -param customSubDomainName string = name -param disableLocalAuth bool = false -param deployments array = [] -param kind string = 'OpenAI' - -@allowed([ 'Enabled', 'Disabled' ]) -param publicNetworkAccess string = 'Enabled' -param sku object = { - name: 'S0' -} -@allowed([ 'None', 'AzureServices' ]) -param bypass string = 'None' - -var networkAcls = { - defaultAction: 'Allow' -} - -var networkAclsWithBypass = { - defaultAction: 'Allow' - bypass: bypass -} - -resource account 'Microsoft.CognitiveServices/accounts@2023-10-01-preview' = { - name: name - location: location - tags: tags - kind: kind - properties: { - customSubDomainName: customSubDomainName - publicNetworkAccess: publicNetworkAccess - // Some services do not support bypass in network acls - networkAcls: (kind == 'FormRecognizer' || kind == 'ComputerVision' || kind == 'SpeechServices') ? networkAcls : networkAclsWithBypass - disableLocalAuth: disableLocalAuth - } - sku: sku -} - -@batchSize(1) -resource deployment 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01' = [for deployment in deployments: { - parent: account - name: deployment.name - properties: { - model: deployment.model - raiPolicyName: contains(deployment, 'raiPolicyName') ? deployment.raiPolicyName : null - } - sku: contains(deployment, 'sku') ? deployment.sku : { - name: 'Standard' - capacity: 20 - } -}] - -output endpoint string = account.properties.endpoint -output id string = account.id -output name string = account.name -output location string = account.location diff --git a/infra/main.bicep b/infra/main.bicep index 4472d1a444..f26a761870 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -301,7 +301,7 @@ module backend 'core/host/appservice.bicep' = { AZURE_SEARCH_QUERY_LANGUAGE: searchQueryLanguage AZURE_SEARCH_QUERY_SPELLER: searchQuerySpeller APPLICATIONINSIGHTS_CONNECTION_STRING: useApplicationInsights ? monitoring.outputs.applicationInsightsConnectionString : '' - AZURE_SPEECH_SERVICE_ID: useSpeechOutputAzure ? speech.outputs.id : '' + AZURE_SPEECH_SERVICE_ID: useSpeechOutputAzure ? speech.outputs.resourceId : '' AZURE_SPEECH_SERVICE_LOCATION: useSpeechOutputAzure ? speech.outputs.location : '' USE_SPEECH_INPUT_BROWSER: useSpeechInputBrowser USE_SPEECH_OUTPUT_BROWSER: useSpeechOutputBrowser @@ -412,7 +412,7 @@ module openAi 'br/public:avm/res/cognitive-services/account:0.5.4' = if (isAzure // Formerly known as Form Recognizer // Does not support bypass -module documentIntelligence 'core/ai/cognitiveservices.bicep' = { +module documentIntelligence 'br/public:avm/res/cognitive-services/account:0.5.4' = { name: 'documentintelligence' scope: documentIntelligenceResourceGroup params: { @@ -422,13 +422,11 @@ module documentIntelligence 'core/ai/cognitiveservices.bicep' = { location: documentIntelligenceResourceGroupLocation disableLocalAuth: true tags: tags - sku: { - name: documentIntelligenceSkuName - } + sku: documentIntelligenceSkuName } } -module computerVision 'core/ai/cognitiveservices.bicep' = if (useGPT4V) { +module computerVision 'br/public:avm/res/cognitive-services/account:0.5.4' = if (useGPT4V) { name: 'computerVision' scope: computerVisionResourceGroup params: { @@ -438,14 +436,11 @@ module computerVision 'core/ai/cognitiveservices.bicep' = if (useGPT4V) { kind: 'ComputerVision' location: computerVisionResourceGroupLocation tags: tags - bypass: bypass - sku: { - name: computerVisionSkuName - } + sku: computerVisionSkuName } } -module speech 'core/ai/cognitiveservices.bicep' = if (useSpeechOutputAzure) { +module speech 'br/public:avm/res/cognitive-services/account:0.5.4' = if (useSpeechOutputAzure) { name: 'speech-service' scope: speechResourceGroup params: { @@ -453,9 +448,7 @@ module speech 'core/ai/cognitiveservices.bicep' = if (useSpeechOutputAzure) { kind: 'SpeechServices' location: !empty(speechServiceLocation) ? speechServiceLocation : location tags: tags - sku: { - name: speechServiceSkuName - } + sku: speechServiceSkuName } } module searchService 'core/search/search-services.bicep' = { @@ -723,8 +716,8 @@ var openAiPrivateEndpointConnection = (isAzureOpenAiHost && deployAzureOpenAi) ? dnsZoneName: 'privatelink.openai.azure.com' resourceIds: concat( [ openAi.outputs.resourceId ], - useGPT4V ? [ computerVision.outputs.id ] : [], - !useLocalPdfParser ? [ documentIntelligence.outputs.id ] : [] + useGPT4V ? [ computerVision.outputs.resourceId ] : [], + !useLocalPdfParser ? [ documentIntelligence.outputs.resourceId ] : [] ) }] : [] var otherPrivateEndpointConnections = usePrivateEndpoint ? [ @@ -846,7 +839,7 @@ output AZURE_OPENAI_CHATGPT_DEPLOYMENT string = isAzureOpenAiHost ? chatGpt.depl output AZURE_OPENAI_EMB_DEPLOYMENT string = isAzureOpenAiHost ? embedding.deploymentName : '' output AZURE_OPENAI_GPT4V_DEPLOYMENT string = isAzureOpenAiHost ? gpt4vDeploymentName : '' -output AZURE_SPEECH_SERVICE_ID string = useSpeechOutputAzure ? speech.outputs.id : '' +output AZURE_SPEECH_SERVICE_ID string = useSpeechOutputAzure ? speech.outputs.resourceId : '' output AZURE_SPEECH_SERVICE_LOCATION string = useSpeechOutputAzure ? speech.outputs.location : '' output AZURE_VISION_ENDPOINT string = useGPT4V ? computerVision.outputs.endpoint : '' From 5f5f90a5f4db0218d4aaca67a869a6d9f82a6577 Mon Sep 17 00:00:00 2001 From: Anthony Shaw Date: Tue, 16 Jul 2024 12:47:35 +1000 Subject: [PATCH 3/4] Add network ACLs to all resource types. --- infra/main.bicep | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/infra/main.bicep b/infra/main.bicep index f26a761870..967b7b1f23 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -399,6 +399,7 @@ module openAi 'br/public:avm/res/cognitive-services/account:0.5.4' = if (isAzure location: openAiResourceGroupLocation tags: tags kind: 'OpenAI' + customSubDomainName: !empty(openAiServiceName) ? openAiServiceName : '${abbrs.cognitiveServicesAccounts}${resourceToken}' publicNetworkAccess: publicNetworkAccess networkAcls: { defaultAction: 'Allow' @@ -418,7 +419,11 @@ module documentIntelligence 'br/public:avm/res/cognitive-services/account:0.5.4' params: { name: !empty(documentIntelligenceServiceName) ? documentIntelligenceServiceName : '${abbrs.cognitiveServicesDocumentIntelligence}${resourceToken}' kind: 'FormRecognizer' + customSubDomainName: !empty(documentIntelligenceServiceName) ? documentIntelligenceServiceName : '${abbrs.cognitiveServicesDocumentIntelligence}${resourceToken}' publicNetworkAccess: publicNetworkAccess + networkAcls: { + defaultAction: 'Allow' + } location: documentIntelligenceResourceGroupLocation disableLocalAuth: true tags: tags @@ -434,6 +439,12 @@ module computerVision 'br/public:avm/res/cognitive-services/account:0.5.4' = if ? computerVisionServiceName : '${abbrs.cognitiveServicesComputerVision}${resourceToken}' kind: 'ComputerVision' + networkAcls: { + defaultAction: 'Allow' + } + customSubDomainName: !empty(computerVisionServiceName) + ? computerVisionServiceName + : '${abbrs.cognitiveServicesComputerVision}${resourceToken}' location: computerVisionResourceGroupLocation tags: tags sku: computerVisionSkuName @@ -446,6 +457,10 @@ module speech 'br/public:avm/res/cognitive-services/account:0.5.4' = if (useSpee params: { name: !empty(speechServiceName) ? speechServiceName : '${abbrs.cognitiveServicesSpeech}${resourceToken}' kind: 'SpeechServices' + networkAcls: { + defaultAction: 'Allow' + } + customSubDomainName: !empty(speechServiceName) ? speechServiceName : '${abbrs.cognitiveServicesSpeech}${resourceToken}' location: !empty(speechServiceLocation) ? speechServiceLocation : location tags: tags sku: speechServiceSkuName From 0d8e2c792c5fda7286d38c64e303551f2b704268 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Thu, 18 Jul 2024 21:06:41 +0000 Subject: [PATCH 4/4] Initial support for https --- .gitignore | 4 ++++ .vscode/launch.json | 34 ++++++++++++++++++++++++++++++++-- app/frontend/package-lock.json | 31 +++++++++++++++++++++++++++++++ app/frontend/package.json | 12 +++++++----- app/frontend/tsconfig.json | 2 +- app/frontend/vite.common.ts | 27 +++++++++++++++++++++++++++ app/frontend/vite.config.ts | 24 ++---------------------- app/frontend/vite.https.ts | 27 +++++++++++++++++++++++++++ app/start.sh | 8 +++++++- docs/localdev.md | 28 ++++++++++++++++++++++++++++ scripts/auth_init.py | 9 ++++++++- scripts/auth_update.py | 2 ++ 12 files changed, 176 insertions(+), 32 deletions(-) create mode 100644 app/frontend/vite.common.ts create mode 100644 app/frontend/vite.https.ts diff --git a/.gitignore b/.gitignore index e51f3af2e2..a437d1c790 100644 --- a/.gitignore +++ b/.gitignore @@ -149,3 +149,7 @@ static/ data/**/*.md5 .DS_Store + +localcert.pem +localcert_key.pem +*.pem diff --git a/.vscode/launch.json b/.vscode/launch.json index 5a83dfd713..a67b501486 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Python: Quart", + "name": "Backend (HTTP)", "type": "debugpy", "request": "launch", "module": "quart", @@ -26,12 +26,42 @@ "envFile": "${input:dotEnvFilePath}", }, { - "name": "Frontend: watch", + "name": "Backend (HTTPS)", + "type": "debugpy", + "request": "launch", + "module": "quart", + "cwd": "${workspaceFolder}/app/backend", + "python": "${workspaceFolder}/.venv/bin/python", + "env": { + "QUART_APP": "main:app", + "QUART_ENV": "development", + "QUART_DEBUG": "0" + }, + "args": [ + "run", + "--no-reload", + "--port=50505", + "--certfile=../../localcert.pem", + "--keyfile=../../localcert_key.pem" + ], + "console": "integratedTerminal", + "justMyCode": false, + "envFile": "${input:dotEnvFilePath}", + }, + { + "name": "Frontend (HTTP)", "type": "node-terminal", "request": "launch", "command": "npm run dev", "cwd": "${workspaceFolder}/app/frontend", }, + { + "name": "Frontend (HTTPS)", + "type": "node-terminal", + "request": "launch", + "command": "npm run dev-https", + "cwd": "${workspaceFolder}/app/frontend", + }, { "name": "Python: Debug Tests", "type": "debugpy", diff --git a/app/frontend/package-lock.json b/app/frontend/package-lock.json index 7c4117e085..5287c27e0d 100644 --- a/app/frontend/package-lock.json +++ b/app/frontend/package-lock.json @@ -26,6 +26,7 @@ "devDependencies": { "@types/dom-speech-recognition": "^0.0.4", "@types/dompurify": "^3.0.4", + "@types/node": "^20.14.11", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@types/react-syntax-highlighter": "^15.5.13", @@ -2640,6 +2641,15 @@ "@types/unist": "^2" } }, + "node_modules/@types/node": { + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@types/prop-types": { "version": "15.7.5", "license": "MIT" @@ -3556,6 +3566,12 @@ "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/update-browserslist-db": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", @@ -5444,6 +5460,15 @@ "@types/unist": "^2" } }, + "@types/node": { + "version": "20.14.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", + "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } + }, "@types/prop-types": { "version": "15.7.5" }, @@ -6010,6 +6035,12 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==" }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "update-browserslist-db": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", diff --git a/app/frontend/package.json b/app/frontend/package.json index a55c9c2e10..a497dc5bab 100644 --- a/app/frontend/package.json +++ b/app/frontend/package.json @@ -8,34 +8,36 @@ }, "scripts": { "dev": "vite --host 127.0.0.1", + "dev-https": "vite --host 127.0.0.1 --config vite.https.ts", "build": "tsc && vite build", "preview": "vite preview" }, "dependencies": { - "@azure/msal-react": "^2.0.6", "@azure/msal-browser": "^3.17.0", + "@azure/msal-react": "^2.0.6", "@fluentui/react": "^8.112.5", "@fluentui/react-components": "^9.37.3", "@fluentui/react-icons": "^2.0.221", "@react-spring/web": "^9.7.3", - "marked": "^13.0.0", "dompurify": "^3.0.6", + "marked": "^13.0.0", + "ndjson-readablestream": "^1.2.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.23.1", - "ndjson-readablestream": "^1.2.0", "react-syntax-highlighter": "^15.5.0", "scheduler": "^0.20.2" }, "devDependencies": { + "@types/dom-speech-recognition": "^0.0.4", "@types/dompurify": "^3.0.4", + "@types/node": "^20.14.11", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", + "@types/react-syntax-highlighter": "^15.5.13", "@vitejs/plugin-react": "^4.3.1", "prettier": "^3.0.3", "typescript": "^5.5.3", - "@types/react-syntax-highlighter": "^15.5.13", - "@types/dom-speech-recognition": "^0.0.4", "vite": "^4.5.3" } } diff --git a/app/frontend/tsconfig.json b/app/frontend/tsconfig.json index 39a545e919..430f2eff0b 100644 --- a/app/frontend/tsconfig.json +++ b/app/frontend/tsconfig.json @@ -15,7 +15,7 @@ "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", - "types": ["vite/client"] + "types": ["vite/client", "node"] }, "include": ["src"] } diff --git a/app/frontend/vite.common.ts b/app/frontend/vite.common.ts new file mode 100644 index 0000000000..3f27bf26bc --- /dev/null +++ b/app/frontend/vite.common.ts @@ -0,0 +1,27 @@ +import react from "@vitejs/plugin-react"; + +// https://vitejs.dev/config/ +const commonConfig = { + plugins: [react()], + build: { + outDir: "../backend/static", + emptyOutDir: true, + sourcemap: true, + rollupOptions: { + output: { + manualChunks: id => { + if (id.includes("@fluentui/react-icons")) { + return "fluentui-icons"; + } else if (id.includes("@fluentui/react")) { + return "fluentui-react"; + } else if (id.includes("node_modules")) { + return "vendor"; + } + } + } + }, + target: "esnext" + } +}; + +export default commonConfig; diff --git a/app/frontend/vite.config.ts b/app/frontend/vite.config.ts index 7fe15e7533..94fc80fea4 100644 --- a/app/frontend/vite.config.ts +++ b/app/frontend/vite.config.ts @@ -1,28 +1,8 @@ import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; +import commonConfig from "./vite.config.ts"; -// https://vitejs.dev/config/ export default defineConfig({ - plugins: [react()], - build: { - outDir: "../backend/static", - emptyOutDir: true, - sourcemap: true, - rollupOptions: { - output: { - manualChunks: id => { - if (id.includes("@fluentui/react-icons")) { - return "fluentui-icons"; - } else if (id.includes("@fluentui/react")) { - return "fluentui-react"; - } else if (id.includes("node_modules")) { - return "vendor"; - } - } - } - }, - target: "esnext" - }, + ...commonConfig, server: { proxy: { "/content/": "http://localhost:50505", diff --git a/app/frontend/vite.https.ts b/app/frontend/vite.https.ts new file mode 100644 index 0000000000..de79ff3172 --- /dev/null +++ b/app/frontend/vite.https.ts @@ -0,0 +1,27 @@ +import fs from "fs"; + +import { defineConfig } from "vite"; + +import commonConfig from "./vite.common.ts"; + +export default defineConfig({ + ...commonConfig, + server: { + proxy: { + "/content/": "https://localhost:50505", + "/auth_setup": "https://localhost:50505", + "/.auth/me": "https://localhost:50505", + "/ask": "https://localhost:50505", + "/chat": "https://localhost:50505", + "/speech": "https://localhost:50505", + "/config": "https://localhost:50505", + "/upload": "https://localhost:50505", + "/delete_uploaded": "https://localhost:50505", + "/list_uploaded": "https://localhost:50505" + }, + https: { + cert: fs.readFileSync("../../localcert.pem"), + key: fs.readFileSync("../../localcert_key.pem") + } + } +}); diff --git a/app/start.sh b/app/start.sh index ec7d64067a..5a1a81e41a 100755 --- a/app/start.sh +++ b/app/start.sh @@ -59,7 +59,13 @@ cd ../backend port=50505 host=localhost -../../.venv/bin/python -m quart --app main:app run --port "$port" --host "$host" --reload + +# optionally add certfile and keyfile args if AZURE_USE_AUTHENTICATION = "true" +if [ "$AZURE_USE_AUTHENTICATION" = "true" ]; then + certArgs="--certfile ../../localcert.pem --keyfile ../../localcert_key.pem" +fi + +../../.venv/bin/python -m quart --app main:app run --port "$port" --host "$host" --reload $certArgs if [ $? -ne 0 ]; then echo "Failed to start backend" exit $? diff --git a/docs/localdev.md b/docs/localdev.md index cb717b9d1b..f161a2fd35 100644 --- a/docs/localdev.md +++ b/docs/localdev.md @@ -40,6 +40,34 @@ Navigate to the URL shown in the terminal (in this case, `http://localhost:5173/ Then, whenever you make changes to frontend files, the changes will be automatically reloaded, without any browser refresh needed. +## Accessing localhost over HTTPS + +If you are using the user authentication feature of the app, you should only access your localhost server over HTTPS. That requires generated locally trusted certificates and then running the localhost with access to those certificates. + +### Generating certificates + +To generate certificates, you can use the `mkcert` tool. Follow the instructions on the [mkcert GitHub page](https://github.com/FiloSottile/mkcert) to install it on your operating system. + +Once installed, run the following command from the repository root: + +```shell +mkcert --key-file localcert_key.pem --cert-file localcert.pem 127.0.0.1 localhost +``` + +This will generate two files: `localcert_key.pem` and `localcert.pem`. These files will be used to run the localhost server with HTTPS. + +### Running the localhost server with HTTPS + +If you are running the localhost server by running `./start.ps1` or `./start.sh`, then it will automatically pass in the certificates to the server when `AZURE_USE_AUTHENTICATION` is true, using the `certfile` and `keyfile` arguments. + +To run the frontend server with HTTPS, you can use the following command: + +```shell +npm run dev-https +``` + +If you are using the VS Code debugger to run the local server, then use "Backend (HTTPS)" and "Frontend (HTTPS)", which are configured to use the certificates. + ## Using a local OpenAI-compatible API You may want to save costs by developing against a local LLM server, such as diff --git a/scripts/auth_init.py b/scripts/auth_init.py index e638f40f73..0786f48411 100644 --- a/scripts/auth_init.py +++ b/scripts/auth_init.py @@ -134,7 +134,14 @@ def client_app(server_app_id: str, server_app: Application, identifier: int) -> redirect_uris=["http://localhost:50505/.auth/login/aad/callback"], implicit_grant_settings=ImplicitGrantSettings(enable_id_token_issuance=True), ), - spa=SpaApplication(redirect_uris=["http://localhost:50505/redirect", "http://localhost:5173/redirect"]), + spa=SpaApplication( + redirect_uris=[ + "http://localhost:50505/redirect", + "https://localhost:50505/redirect", + "http://localhost:5173/redirect", + "https://localhost:5173/redirect", + ] + ), required_resource_access=[ RequiredResourceAccess( resource_app_id=server_app_id, diff --git a/scripts/auth_update.py b/scripts/auth_update.py index cb6cd48968..c4f2186785 100755 --- a/scripts/auth_update.py +++ b/scripts/auth_update.py @@ -34,7 +34,9 @@ async def main(): spa=SpaApplication( redirect_uris=[ "http://localhost:50505/redirect", + "https://localhost:50505/redirect", "http://localhost:5173/redirect", + "https://localhost:5173/redirect", f"{uri}/redirect", ] ),