From 2995a9c677dd7cbf1cbfb5849af3fbe4dbdee3eb Mon Sep 17 00:00:00 2001 From: Teresa Hoang <125500434+teresaqhoang@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:37:10 -0700 Subject: [PATCH] Enabling HTTPS with local WebApp development (#1311) ### Motivation and Context This PR sets up the support for HTTPS should developers choose to enable it. Some customers have production sites using HTTPS and want the option to have a local development site that behaves like HTTPS. ### Description - Update WebApp env.example with required variables - Updated README with instructions on how to generate locally signed certificate and how to update copilot config files accordingly. - Added `https://localhost:3000` to AllowedOrigins in webapi config files --- .gitignore | 1 + samples/apps/copilot-chat-app/README.md | 3 +- .../webapi/DeploymentTemplates/main.bicep | 1 + .../sk-existing-azureopenai.json | 3 +- .../sk-existing-openai.json | 3 +- .../webapi/DeploymentTemplates/sk-new.json | 3 +- .../copilot-chat-app/webapi/appsettings.json | 3 +- .../apps/copilot-chat-app/webapp/.env.example | 7 + .../apps/copilot-chat-app/webapp/.gitignore | 2 +- .../apps/copilot-chat-app/webapp/README.md | 141 ++++++++++++++++-- 10 files changed, 146 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index eec452d71e..befd8f7f75 100644 --- a/.gitignore +++ b/.gitignore @@ -407,6 +407,7 @@ FodyWeavers.xsd *.cer *.crt *.key +*.pem .env certs/ diff --git a/samples/apps/copilot-chat-app/README.md b/samples/apps/copilot-chat-app/README.md index a03cabcc36..d11305a140 100644 --- a/samples/apps/copilot-chat-app/README.md +++ b/samples/apps/copilot-chat-app/README.md @@ -109,7 +109,8 @@ First, letโ€™s set up and verify the back-end API server is running. yarn install yarn start ``` - + > To run the WebApp with HTTPs, see [How to use HTTPS for local development](./webapp/README.md#how-to-use-https-for-local-development). + 4. With the back end and front end running, your web browser should automatically launch and navigate to `http://localhost:3000` > The first time running the front-end application may take a minute or so to start. diff --git a/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/main.bicep b/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/main.bicep index ad5d68dee2..5ce8f64b6f 100644 --- a/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/main.bicep +++ b/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/main.bicep @@ -140,6 +140,7 @@ resource appServiceWebConfig 'Microsoft.Web/sites/config@2022-09-01' = { cors: { allowedOrigins: [ 'http://localhost:3000' + 'https://localhost:3000' ] supportCredentials: true } diff --git a/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-existing-azureopenai.json b/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-existing-azureopenai.json index 75613dde72..24813b185c 100644 --- a/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-existing-azureopenai.json +++ b/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-existing-azureopenai.json @@ -391,7 +391,8 @@ "alwaysOn": true, "cors": { "allowedOrigins": [ - "http://localhost:3000" + "http://localhost:3000", + "https://localhost:3000" ], "supportCredentials": true }, diff --git a/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-existing-openai.json b/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-existing-openai.json index ebf27ac3ad..1a92c5fdaa 100644 --- a/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-existing-openai.json +++ b/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-existing-openai.json @@ -386,7 +386,8 @@ "alwaysOn": true, "cors": { "allowedOrigins": [ - "http://localhost:3000" + "http://localhost:3000", + "https://localhost:3000" ], "supportCredentials": true }, diff --git a/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-new.json b/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-new.json index f020e254b8..4ff96e90bb 100644 --- a/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-new.json +++ b/samples/apps/copilot-chat-app/webapi/DeploymentTemplates/sk-new.json @@ -373,7 +373,8 @@ "alwaysOn": true, "cors": { "allowedOrigins": [ - "http://localhost:3000" + "http://localhost:3000", + "https://localhost:3000" ], "supportCredentials": true }, diff --git a/samples/apps/copilot-chat-app/webapi/appsettings.json b/samples/apps/copilot-chat-app/webapi/appsettings.json index fb5eec22d2..1765abfd5e 100644 --- a/samples/apps/copilot-chat-app/webapi/appsettings.json +++ b/samples/apps/copilot-chat-app/webapi/appsettings.json @@ -172,7 +172,8 @@ // CORS "AllowedOrigins": [ - "http://localhost:3000" + "http://localhost:3000", + "https://localhost:3000" ], // The schema information for a serialized bot that is supported by this application. diff --git a/samples/apps/copilot-chat-app/webapp/.env.example b/samples/apps/copilot-chat-app/webapp/.env.example index 2932ba73a8..ca12307604 100644 --- a/samples/apps/copilot-chat-app/webapp/.env.example +++ b/samples/apps/copilot-chat-app/webapp/.env.example @@ -6,3 +6,10 @@ REACT_APP_AAD_CLIENT_ID= # Optional Variables REACT_APP_SK_API_KEY= + +# To enable HTTPS, uncomment the following variables +# HTTPS="true" +# Replace with your locally-trusted cert file +# SSL_CRT_FILE=local-cert.crt +# Replace with your locally-trusted cert key +# SSL_KEY_FILE=local-cert.key \ No newline at end of file diff --git a/samples/apps/copilot-chat-app/webapp/.gitignore b/samples/apps/copilot-chat-app/webapp/.gitignore index 42afabfd2a..796b96d1c4 100644 --- a/samples/apps/copilot-chat-app/webapp/.gitignore +++ b/samples/apps/copilot-chat-app/webapp/.gitignore @@ -1 +1 @@ -/build \ No newline at end of file +/build diff --git a/samples/apps/copilot-chat-app/webapp/README.md b/samples/apps/copilot-chat-app/webapp/README.md index 505ccda30b..036b45bd55 100644 --- a/samples/apps/copilot-chat-app/webapp/README.md +++ b/samples/apps/copilot-chat-app/webapp/README.md @@ -1,10 +1,117 @@ # Copilot Chat Web App > This learning sample is for educational purposes only and is not recommended for -production deployments. +> production deployments. See [../README.md](../README.md) for complete instructions on setting up and running the application. +## How to use HTTPS for local development + +If you want to run Copilot Chat with HTTPS, you need to create a certificate and sign it with a Certificate Authority (CA) that is trusted locally by your device and browser. You have a couple of options on how to do this: + +1. (Recommended) Reusuing the [dotnet dev-certs](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-dev-certs) generated for the webapi app + + > Note: the `dotnet dev-certs` command does not have a built-in option to generate a certificate for a specific IP address. It only generates a cert for `localhost`. If you need to use a specific IP address, use one of the two options below. + +2. [mkcert](https://github.com/FiloSottile/mkcert#installation): a simple tool for making locally-trusted development certificates; requires no configuration +3. [Azure KeyVault certificates](https://learn.microsoft.com/en-us/azure/key-vault/certificates/certificate-scenarios): you'll need to create the certificate in Key Vault using [Portal](https://learn.microsoft.com/en-us/azure/key-vault/certificates/quick-create-portal), [Azure CLI](https://learn.microsoft.com/en-us/azure/key-vault/certificates/quick-create-cli), or [Azure PowerShell](https://learn.microsoft.com/en-us/azure/key-vault/certificates/quick-create-powershell) and then download the cert and key files to use in step 2. + +### Step 1: Creating the certificate + +Option 1: Reusuing the [dotnet dev-certs](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-dev-certs) generated for the webapi app. + +1. Open a terminal and navigate to `samples/apps/copilot-chat-app/webapi`. +1. Run + + ``` + dotnet dev-certs https -ep ../webapp/local-cert.crt --no-password --trust --format PEM + ``` + + This will create a certificate for `localhost`, trust it, and export it to a PEM file including the private key. + + > Note: The `--no-password` flag specifies that a password will not be used for the key on export. This is intended for testing use only. + +1. The certificate and key are now exported as a pair of files in PEM format at the root of this directory (/webapp): + - local-cert.crt + - local-cert.key + +Option 2: Using [mkcert](https://github.com/FiloSottile/mkcert#installation) + +1. From an elevated shell, run + + ### Windows + + On Windows, use [Chocolatey](https://chocolatey.org/) + + ``` + choco install mkcert + ``` + + ### MacOS + + On macOS, use [Homebrew](https://brew.sh/) + + ``` + brew install mkcert + ``` + + For installation on Linux, other operating systems, and advanced topics (e.g., supported root stores), see the [official mkcert installation guide](https://github.com/FiloSottile/mkcert#installation). + +1. Create a new local certificate authority (CA) by running + ``` + mkcert -install + ``` +1. Create a new certificate with all hostnames you wish to run the app on. + + > It is recommend you do this at the /webapp directory level. + + Run + + ``` + mkcert localhost 127.0.0.1 example.test + ``` + + You should see an output that looks like this: + + ``` + Created a new certificate valid for the following names ๐Ÿ“œ + - "localhost" + - "127.0.0.1" + - "example.test" + + The certificate is at "./localhost+1.pem" and the key at "./localhost+1-key.pem" โœ… + + It will expire on 1 September 2025 + ``` + + > **Warning**: (from the developers of mkcert) the rootCA-key.pem file that mkcert automatically generates gives complete power to intercept secure requests from your machine. Do not share it. + +### Step 2: Configuring Copilot Chat to use the certificate + +1. In the webapp `.env` file, uncomment the following lines and populate with your respective certificate and key files generated in the step above. + ``` + ... + # To enable HTTPS, uncomment the following lines + HTTPS="true" + # Replace with your locally-trusted cert file + SSL_CRT_FILE=local-cert.crt + # Replace with your locally-trusted cert key + SSL_KEY_FILE=local-cert.key + ``` +1. In the [webapi appsettings.json](../webapi/appsettings.json) file, find the `"AllowedOrigins"` section, and add the URLs (with ports!) that you'll be running the apps on with `https` prefixed. For instance, the `"AllowedOrigins"` section should look something like: + ``` + ... + // CORS + "AllowedOrigins": [ + "http://localhost:3000", + "https://localhost:3000", + "https://127.0.0.1:3000", + ], + ... + ``` +1. Add the same URLs (with ports!) as single-page application (SPA) redirect URIs to your Azure Active Directory (AAD) application registration. This can be done in the [Azure Portal](https://portal.azure.com). +1. Restart the `webapi` and `webapp` - Copilot Chat should be now running locally with HTTPS. + ## Authentication This sample uses the Microsoft Authentication Library (MSAL) for React to authenticate users. @@ -14,30 +121,34 @@ Learn more about it here: https://learn.microsoft.com/en-us/azure/active-directo Aside from debugging within browsers, you can launch a debug session in Visual Studio. -1. Open the webapp folder (i.e.`/samples/apps/copilot-chat-app/WebApp`) in Visual Studio Code. +1. Open the webapp folder (i.e.`/samples/apps/copilot-chat-app/webapp`) in Visual Studio Code. 2. Go to "Run and Debug" and select on the "Launch Edge against localhost". -> Go [here](https://code.visualstudio.com/docs/typescript/typescript-debugging) to learn more about debugging client-code in Visual Studio Code. + > Go [here](https://code.visualstudio.com/docs/typescript/typescript-debugging) to learn more about debugging client-code in Visual Studio Code. ## Serve a production build + By default, we run the app using `yarn start`, which starts a local development server. This enables some additional development behaviors and debuggings features, such as `React.StrictMode`, which will render the app twice to find bugs caused by impure rendering. -If you want to serve a production build of the WebApp (as static files) without any development-specific features, +If you want to serve a production build of the `webapp` (as static files) without any development-specific features, + +1. Run -1. Run - ``` - yarn build ``` - + yarn build + ``` + This will generate an optimized and minified production-ready build of the app in the `/build` directory. + 2. Once the build is complete, and you have the `/build` directory, run - ``` - yarn serve ``` - + yarn serve + ``` + This will start the server and serve the production build. You should see an output similar to: + + ``` + Serving! + - Local: http://localhost:3000 + - Network: http://192.168.0.100:3000 ``` - Serving! - - Local: http://localhost:3000 - - Network: http://192.168.0.100:3000 - ``` \ No newline at end of file