julien 71a098b154
CI / scan (push) Successful in 2m27s
CI / commits (push) Has been skipped
CI / check (push) Successful in 3m30s
CI / a11y (push) Successful in 1m44s
CI / perf (push) Successful in 3m18s
fix(feature-auth): use AUTH_PATH_PREFIX to skip the /me endpoint in the 401 interceptor (#135)
## Summary

Regression introduced by PR #134 / merged minutes ago: opening portal-admin while anonymous fires the bootstrap `/admin/auth/me` → 401 → `bffUnauthorizedInterceptor` triggers `AuthService.refresh()` → which re-fires `/admin/auth/me` → 401 → tight loop that exhausts the BFF's 120/min rate limiter in seconds. The user lands on a `rate_limited` error instead of the "Sign in" panel.

## Root cause

[`bffUnauthorizedInterceptor`](libs/feature/auth/src/lib/bff-unauthorized.interceptor.ts) deliberately skips the `/me` endpoint to avoid the loop (the bootstrap `/me` legitimately 401s when anonymous). But the skip target was **hardcoded** to `${bffBaseUrl}/auth/me`:

```ts
!req.url.startsWith(`${bffBaseUrl}/auth/me`)
```

When portal-admin overrides `AUTH_PATH_PREFIX` to `/admin/auth` (per PR #134), the bootstrap URL becomes `${bffBaseUrl}/admin/auth/me`, which does **not** start with `${bffBaseUrl}/auth/me`. The interceptor treats it as a regular protected route, calls `refresh()`, and we're off to the races.

The reported log shows the rate-limit counter dropping `remaining=3 → 2 → 1 → 0` over four `/me` calls within ~25 ms, all 401.

## Fix

Derive the skip URL from `AUTH_PATH_PREFIX` (which the interceptor already has access to via DI — same module as the AuthService):

```ts
const meUrl = `${bffBaseUrl}${pathPrefix}/me`;
…
!req.url.startsWith(meUrl)
```

Same behaviour for portal-shell (the default `/auth` factory keeps the skip URL at `/auth/me`), correct behaviour for portal-admin (`/admin/auth/me`), and any future surface that picks a different prefix inherits the fix automatically.

## Test plan

- [x] `pnpm nx test feature-auth` — **30 specs pass** (was 29; +1 regression spec asserting that no follow-up `/me` is issued after a bootstrap 401 when the prefix is `/admin/auth`).
- [x] `pnpm exec nx affected -t format:check lint test build --base=origin/main` — clean.
- [ ] Manual: `pnpm nx serve portal-admin`, visit `http://localhost:4300/`, observe the BFF log — exactly **one** `/admin/auth/me` request (the bootstrap), 401, no follow-up, no rate-limit hit. The home page renders the "No admin session detected" + Sign in button.

## Notes for the reviewer

- The bug pattern is symmetric: any future host that overrides `AUTH_PATH_PREFIX` would have hit the same trap. Making the skip target derive from the token is the structural fix; the regression spec pins it.
- portal-shell tests still pass without changes — the default factory returns `/auth`, so the existing fixtures continue exercising `${bffBaseUrl}/auth/me` as the skip target.
- No SPA-side changes needed in portal-shell or portal-admin app code. The fix is entirely inside the lib.

---------

Co-authored-by: Julien Gautier <julien.gautier@apf.asso.fr>
Reviewed-on: #135
2026-05-14 17:23:44 +02:00

Documentation index

This is the entry point to all project documentation. It is maintained automatically: any addition, rename, or removal of a .md file under docs/ must be reflected here in the same change.

Conventions

  • Documentation is written in English.
  • One topic per file. Group related files into a folder when there are three or more.
  • Cross-reference with relative links so they keep working in GitHub, IDEs, and exported sites.
  • For architectural decisions, do not add them here — they belong in decisions/ as MADR 4.0.0 ADRs.

Sections

Daily development

  • development.md — repo layout, prerequisites, initial setup, daily commands, observability dev-loop (Jaeger UI, log ↔ trace correlation), dependency updates (Renovate), conventional commit cycle. Day-to-day reference for working on the project.

Architecture

  • architecture.md — cross-cutting Mermaid diagrams: C4 system context, C4 containers, Nx module boundaries, CI/CD pipeline. Single-decision diagrams (auth sequence, ERD, etc.) live inline in their ADR.

Onboarding & environment

Setup guides for new contributors:

Operations & runbooks

Empty — to be populated when we deploy.

Security, performance, accessibility

Empty — placeholders to be filled with rationale docs alongside their corresponding ADRs.

S
Description
No description provided
Readme 42 MiB
Languages
TypeScript 85.3%
JavaScript 5.4%
SCSS 4.3%
HTML 3.9%
Shell 0.8%
Other 0.3%