From 0e6c7d20663d48e06b54c3428a2e83a2b6f38b0f Mon Sep 17 00:00:00 2001 From: Niek Otten Date: Mon, 13 Jul 2026 14:09:15 +0200 Subject: [PATCH] fix(portal-self-service): attach the DigiD token to relative BFF calls (refs #68) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After login the submit silently did nothing: the confirmation ("...is ontvangen...") never rendered because the POST to the BFF went out with no Authorization header, so the BFF rejected it and the no-error-handler subscribe left the page unchanged. Root cause: angular-auth-oidc-client's interceptor attaches the token when `req.url.startsWith(secureRoute)`. The api-client calls the BFF with RELATIVE URLs (same-origin via the nginx proxy), so `req.url` is `/self-service/...` — but secureRoutes was configured as the app ORIGIN (`http://self-service`), which a relative URL never starts with. No match → no token. Configure secureRoutes with the relative `/self-service/` prefix instead. The unit test mocked the api-client, so only the walking-skeleton e2e exercises the real token attachment — now green. Verified against a focused stack (keycloak + self-service + real BFF + stub domain): the submit now carries the bearer token, the BFF forwards to the domain, and the portal shows the confirmation with the returned reference. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/self-service/src/app/app.config.ts | 10 ++++++---- libs/auth/src/lib/digid-auth.providers.ts | 11 ++++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/self-service/src/app/app.config.ts b/apps/self-service/src/app/app.config.ts index a4b7577..c60e7bf 100644 --- a/apps/self-service/src/app/app.config.ts +++ b/apps/self-service/src/app/app.config.ts @@ -14,9 +14,11 @@ export interface RuntimeConfig { } /** - * Build the app providers from runtime config. `redirectUrl` and `secureApiOrigin` are the app's own - * origin: the app is served same-origin as the BFF (nginx proxies /self-service + /openbaar), so the - * api-client's relative calls stay same-origin and the token interceptor attaches to them. + * Build the app providers from runtime config. `redirectUrl` is the app's own origin (where Keycloak + * redirects back). The app is served same-origin as the BFF (nginx proxies /self-service + /openbaar), + * so the api-client uses **relative** URLs — hence `secureRoutes` is the relative `/self-service/` + * prefix (the guarded BFF route), not the origin: the interceptor matches on `req.url`, which stays + * relative, so an origin would never match and the token would not be attached. */ export function appConfig(runtime: RuntimeConfig): ApplicationConfig { const origin = typeof window !== 'undefined' ? window.location.origin : '/'; @@ -28,7 +30,7 @@ export function appConfig(runtime: RuntimeConfig): ApplicationConfig { provideDigiadAuth({ authority: runtime.authority, redirectUrl: origin, - secureApiOrigin: origin, + secureRoutes: ['/self-service/'], }), ], }; diff --git a/libs/auth/src/lib/digid-auth.providers.ts b/libs/auth/src/lib/digid-auth.providers.ts index 0f1cb21..15f5ec2 100644 --- a/libs/auth/src/lib/digid-auth.providers.ts +++ b/libs/auth/src/lib/digid-auth.providers.ts @@ -13,8 +13,13 @@ export interface DigiadAuthOptions { authority: string; /** Where Keycloak redirects back to after login (usually the app origin). */ redirectUrl: string; - /** The BFF origin whose requests get the bearer token attached (secure route). */ - secureApiOrigin: string; + /** + * Route prefixes whose requests get the bearer token attached. The api-client calls the BFF with + * **relative** URLs (same-origin via the nginx proxy), so these must be relative path prefixes + * (e.g. `/self-service/`) — angular-auth-oidc-client matches `req.url.startsWith(route)`, and a + * relative `req.url` never starts with an absolute origin. + */ + secureRoutes: string[]; } /** @@ -35,7 +40,7 @@ export function provideDigiadAuth(options: DigiadAuthOptions): EnvironmentProvid responseType: 'code', silentRenew: true, useRefreshToken: true, - secureRoutes: [options.secureApiOrigin], + secureRoutes: options.secureRoutes, logLevel: LogLevel.Warn, }, },