fix(e2e): treat the http portal origin as secure so DigiD PKCE login works (refs #68)
Some checks failed
CI / lint (pull_request) Successful in 1m12s
CI / build (pull_request) Successful in 53s
CI / unit (pull_request) Successful in 1m3s
CI / frontend (pull_request) Successful in 1m47s
CI / mutation (pull_request) Successful in 4m2s
CI / verify-stack (pull_request) Failing after 7m51s

The walking-skeleton e2e timed out waiting for the Keycloak login form
(`#username`). Root cause: in the compose network the portal is served over
plain HTTP on a non-localhost origin (http://self-service), which is not a
secure context, so Web Crypto (`crypto.subtle`) is undefined. angular-auth-
oidc-client needs SubtleCrypto to build the PKCE code challenge, so
`authorize()` threw ("Cannot read properties of undefined (reading 'digest')")
and the login redirect never fired.

Production serves the portal over HTTPS, where this works. Instead of
terminating TLS in the throwaway e2e stack, tell Chromium to treat the origin
as secure via --unsafely-treat-insecure-origin-as-secure. The flag is only
honoured by the full Chromium build (new headless), not Playwright's default
headless-shell, so pin channel: 'chromium'.

Verified against a minimal in-network stack (keycloak + self-service): login
redirect now reaches the Keycloak form, and the full login → token exchange →
authenticated portal renders with no console errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-13 13:37:31 +02:00
parent 2e00ad38ba
commit 39923e0e68
2 changed files with 21 additions and 1 deletions

View File

@@ -91,5 +91,13 @@ with the submit form (S-08c, #67); any deviation from NL DS will be recorded her
runtime, so there's no Playwright-image-version pinning to keep in sync. The spec is copied in runtime, so there's no Playwright-image-version pinning to keep in sync. The spec is copied in
(`docker cp`), not mounted, so it leaves nothing root-owned on the host. Wired as `verify-e2e` in (`docker cp`), not mounted, so it leaves nothing root-owned on the host. Wired as `verify-e2e` in
the `verify-stack` CI job. the `verify-stack` CI job.
- **e2e treats the portal origin as secure.** In-network the portal is served over plain HTTP on a
non-localhost origin (`http://self-service`), which is **not a secure context**, so Web Crypto
(`crypto.subtle`) is unavailable. angular-auth-oidc-client needs it for the PKCE code challenge, so
`authorize()` throws and the login redirect never fires. Production runs behind HTTPS where this is
a non-issue; rather than terminate TLS in the throwaway stack, the Playwright config passes
`--unsafely-treat-insecure-origin-as-secure` (honoured only by the full `channel: 'chromium'`
build, not the default headless-shell). This emulates the production HTTPS secure context without
touching the app or its production config.
- `tests/e2e` is a standalone Playwright project (its own `package.json`), not an Nx project — it's a - `tests/e2e` is a standalone Playwright project (its own `package.json`), not an Nx project — it's a
live-stack check like the other `verify-*` runners, not part of the `frontend` unit lane. live-stack check like the other `verify-*` runners, not part of the `frontend` unit lane.

View File

@@ -2,6 +2,8 @@ import { defineConfig, devices } from '@playwright/test';
// The e2e runs inside the compose network (infra/run-e2e-check.sh); baseURL defaults to the // The e2e runs inside the compose network (infra/run-e2e-check.sh); baseURL defaults to the
// self-service service. Keep timeouts generous — the first navigation triggers the DigiD flow. // self-service service. Keep timeouts generous — the first navigation triggers the DigiD flow.
const baseURL = process.env.SELF_SERVICE_URL ?? 'http://self-service';
export default defineConfig({ export default defineConfig({
testDir: '.', testDir: '.',
timeout: 90_000, timeout: 90_000,
@@ -9,8 +11,18 @@ export default defineConfig({
retries: 1, retries: 1,
reporter: [['list']], reporter: [['list']],
use: { use: {
baseURL: process.env.SELF_SERVICE_URL ?? 'http://self-service', baseURL,
trace: 'on-first-retry', trace: 'on-first-retry',
// The portal is served over plain HTTP on a non-localhost origin (http://self-service) inside the
// compose network, so it is NOT a secure context — and Web Crypto (`crypto.subtle`) is undefined
// there. angular-auth-oidc-client needs SubtleCrypto to build the PKCE code challenge, so
// `authorize()` throws and the login redirect never fires (the login form never appears). In
// production the portal runs behind HTTPS, where this works. Rather than terminate TLS in the
// throwaway e2e stack, tell Chromium to treat this origin as secure — which faithfully emulates
// the production HTTPS context. This flag is only honoured by the full Chromium build (new
// headless), not Playwright's default headless-shell, so pin `channel: 'chromium'`.
channel: 'chromium',
launchOptions: { args: [`--unsafely-treat-insecure-origin-as-secure=${baseURL}`] },
}, },
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }], projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
}); });