feat(spa): opt-in 'https' nx serve config for dev-server TLS #263

Merged
julien merged 1 commits from feat/spa-dev-server-tls into main 2026-06-01 16:15:38 +02:00
6 changed files with 127 additions and 2 deletions
Showing only changes of commit 82d8c6972f - Show all commits
+6
View File
@@ -93,6 +93,12 @@
},
"development": {
"buildTarget": "portal-admin:build:development"
},
"https": {
"buildTarget": "portal-admin:build:development",
"ssl": true,
"sslKey": ".secrets/dev-tls.key",
"sslCert": ".secrets/dev-tls.pem"
}
},
"defaultConfiguration": "development"
+19
View File
@@ -60,6 +60,25 @@ ENTRA_CLIENT_SECRET=replace_with_real_value
# User portal — `/api/auth/callback` is the OIDC return URL; the
# post-logout URL is where Entra sends the browser after RP-initiated
# logout (typically the SPA landing page).
#
# The default values below match WSL-native dev (browser on the same
# host as the BFF, accessing http://localhost:4200/). For the
# ADR-0030 dockerised dev mode accessed via a hostname (e.g.
# https://apf-portal.dev-jg.local:4200/), override these to point at
# the SPA dev-server origin instead — `/api/auth/callback` is then
# proxied to the BFF (see apps/portal-shell/proxy.conf.js):
#
# ENTRA_REDIRECT_URI=https://apf-portal.dev-jg.local:4200/api/auth/callback
# ENTRA_POST_LOGOUT_REDIRECT_URI=https://apf-portal.dev-jg.local:4200/
# ENTRA_ADMIN_REDIRECT_URI=https://apf-portal.dev-jg.local:4300/api/admin/auth/callback
# ENTRA_ADMIN_POST_LOGOUT_REDIRECT_URI=https://apf-portal.dev-jg.local:4300/
#
# The `https:` scheme is mandatory for non-`localhost` hosts — Entra
# rejects `http:` for anything else. See the "HTTPS dev-server setup"
# section of infra/README.md for the dev-server TLS / mkcert setup.
# Each override URI must also be registered in the Entra app
# registration's Redirect URIs list (the BFF sends *one* of them per
# auth request; Entra validates it is allowed).
ENTRA_REDIRECT_URI=http://localhost:3000/api/auth/callback
ENTRA_POST_LOGOUT_REDIRECT_URI=http://localhost:4200/
# Admin portal — distinct callback per ADR-0020 §"Sessions — distinct
+6
View File
@@ -92,6 +92,12 @@
},
"development": {
"buildTarget": "portal-shell:build:development"
},
"https": {
"buildTarget": "portal-shell:build:development",
"ssl": true,
"sslKey": ".secrets/dev-tls.key",
"sslCert": ".secrets/dev-tls.pem"
}
},
"defaultConfiguration": "development"
+44
View File
@@ -226,6 +226,50 @@ How it works (see [ADR-0030](../docs/decisions/0030-dockerised-dev-mode.md)):
The three dev modes (native `nx serve`, devcontainer, this `apps` profile) and when to use each are summarised in [docs/setup/01-dev-debian-vm-setup.md](../docs/setup/01-dev-debian-vm-setup.md).
### HTTPS dev-server setup — remote-browser access via a hostname
By default the dev-servers serve plain HTTP — fine when the browser is on the same host as the BFF (`http://localhost:4200/`), which is also the only HTTP origin Entra accepts as a redirect URI. The moment you access the SPA over a **hostname** (e.g. `apf-portal.dev.local`, useful when the browser sits on a workstation and the stack runs on a shared / per-dev VM), Entra refuses the `http:` redirect URI and the dev-servers must terminate TLS.
The setup is one-time per dev:
1. **Install [mkcert](https://github.com/FiloSottile/mkcert)** on your workstation (the machine where the browser runs) and bootstrap its local CA:
```bash
# Debian / WSL Ubuntu:
sudo apt install -y libnss3-tools
# macOS:
# brew install mkcert nss
# Windows (PowerShell, choco):
# choco install mkcert
mkcert -install
```
2. **Generate the cert** for the hostname you registered in your `/etc/hosts` and in Entra. From the repo root on your workstation:
```bash
mkdir -p .secrets
mkcert -key-file .secrets/dev-tls.key -cert-file .secrets/dev-tls.pem \
apf-portal.dev-jg.local # ← replace with YOUR hostname
```
`.secrets/` is git-ignored; the bind-mount in the `apps` profile (the repo at `/workspace`) makes the files visible inside the containers at the path the `https` configuration expects.
3. **Update `apps/portal-bff/.env`** so the BFF tells Entra the matching HTTPS URIs — see the redirect-URI block in [`apps/portal-bff/.env.example`](../apps/portal-bff/.env.example) for the override pattern. The same URIs must be registered in your Entra app registration's "Redirect URIs" list (the BFF only sends one of them per auth request; Entra validates it is on the list).
4. **Enable the `https` Nx serve configuration** for the compose dev-servers by adding to `infra/local/.env`:
```env
NX_SERVE_CONFIGURATION=https
```
The compose command resolves `--configuration=${NX_SERVE_CONFIGURATION:-development}` at parse time, so the SPAs pick up the `https` config defined in `apps/portal-shell/project.json` and `apps/portal-admin/project.json`. The BFF stays HTTP behind the proxy — only the public origin is HTTPS.
5. `./infra/local/dev.sh up apps` → browser opens `https://apf-portal.dev-jg.local:4200/`. No cert warning (mkcert's CA is trusted by the workstation after step 1).
Native `nx serve` (WSL / localhost) is **unaffected** — it keeps using the `development` configuration by default, no SSL required, and the `localhost` URIs registered in Entra still work.
When real DNS + corp-CA-signed certs arrive, the hostname can be reused as-is (Entra registrations are literal strings — they don't care who signs the cert). Drop the cert files back into `.secrets/` and remove the mkcert step.
### Service endpoints (defaults)
| Service | Host port | Purpose |
+17
View File
@@ -35,3 +35,20 @@ OTEL_HTTP_PORT=4318
PGWEB_PORT=8081
JAEGER_UI_PORT=16686
SERVE_STATIC_PORT=4200
# ---------------------------------------------------------------- Apps (`--profile apps`)
# Nx serve configuration for the SPA dev-servers. Two values matter:
# - `development` (default) — plain HTTP. Use with `localhost`
# browser access; Entra accepts
# `http://localhost:*` redirect URIs.
# - `https` — TLS-terminating dev-server using the
# cert at `.secrets/dev-tls.{key,pem}`.
# Required when accessing the SPA via a
# hostname (e.g. `apf-portal.dev.local`)
# since Entra rejects `http:` for any
# non-`localhost` redirect URI. See the
# "HTTPS dev-server setup" section of
# infra/README.md for the mkcert
# procedure and how to wire the
# matching `ENTRA_REDIRECT_URI` value.
# NX_SERVE_CONFIGURATION=https
+35 -2
View File
@@ -266,7 +266,27 @@ services:
# /api proxy at the BFF container by name (Compose DNS). Native
# `nx serve` leaves BFF_TARGET unset and falls back to localhost.
BFF_TARGET: http://portal-bff:3000
command: ['pnpm', 'exec', 'nx', 'serve', 'portal-shell', '--host', '0.0.0.0', '--port', '4200']
# `--configuration=${NX_SERVE_CONFIGURATION:-development}` is
# interpolated by Compose at YAML parse time from
# `infra/local/.env`. Set `NX_SERVE_CONFIGURATION=https` there to
# serve over TLS — required when accessing via a hostname (Entra
# rejects `http:` for non-`localhost` redirect URIs). See the
# `https` configuration in apps/portal-shell/project.json + the
# "HTTPS dev-server setup" section in infra/README.md for the
# mkcert procedure.
command:
[
'pnpm',
'exec',
'nx',
'serve',
'portal-shell',
'--host',
'0.0.0.0',
'--port',
'4200',
'--configuration=${NX_SERVE_CONFIGURATION:-development}',
]
ports:
- '${SHELL_PORT:-4200}:4200'
depends_on:
@@ -279,7 +299,20 @@ services:
environment:
# See portal-shell — same proxy target for the admin SPA.
BFF_TARGET: http://portal-bff:3000
command: ['pnpm', 'exec', 'nx', 'serve', 'portal-admin', '--host', '0.0.0.0', '--port', '4300']
# See portal-shell for the NX_SERVE_CONFIGURATION rationale.
command:
[
'pnpm',
'exec',
'nx',
'serve',
'portal-admin',
'--host',
'0.0.0.0',
'--port',
'4300',
'--configuration=${NX_SERVE_CONFIGURATION:-development}',
]
ports:
- '${ADMIN_PORT:-4300}:4300'
depends_on: