Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Optional support for HTTPS when using authentication #1836

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,7 @@ static/
data/**/*.md5

.DS_Store

localcert.pem
localcert_key.pem
*.pem
34 changes: 32 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"version": "0.2.0",
"configurations": [
{
"name": "Python: Quart",
"name": "Backend (HTTP)",
"type": "debugpy",
"request": "launch",
"module": "quart",
Expand All @@ -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",
Expand Down
31 changes: 31 additions & 0 deletions app/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 7 additions & 5 deletions app/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
2 changes: 1 addition & 1 deletion app/frontend/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"types": ["vite/client"]
"types": ["vite/client", "node"]
},
"include": ["src"]
}
27 changes: 27 additions & 0 deletions app/frontend/vite.common.ts
Original file line number Diff line number Diff line change
@@ -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;
24 changes: 2 additions & 22 deletions app/frontend/vite.config.ts
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
27 changes: 27 additions & 0 deletions app/frontend/vite.https.ts
Original file line number Diff line number Diff line change
@@ -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")
}
}
});
8 changes: 7 additions & 1 deletion app/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 $?
Expand Down
28 changes: 28 additions & 0 deletions docs/localdev.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion scripts/auth_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions scripts/auth_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
]
),
Expand Down
Loading