Salvage source: PR #10443. Branch from
master(NOT the currentimprv/x-access-token-headerbranch, which carries unrelated MongoDB-regex work). Test-first per repo TDD policy.
[x] 1.1 Create the shared token-source extractor with unit tests (test-first)
X-GROWI-ACCESS-TOKEN header > query > body; non-string / array-valued header is ignored; header key resolves case-insensitively[x] 2. Core: parser integration with header support
[x] 2.1 (P) Route the scoped access-token parser through the shared extractor
X-GROWI-ACCESS-TOKEN header with a satisfying scope authenticates the token owner[x] 2.2 (P) Route the legacy api-token parser through the shared extractor
X-GROWI-ACCESS-TOKEN header authenticates the owner; confirm the acceptLegacy gating is unchanged (legacy token ignored when the route does not opt in)[x] 3. Integration: OpenAPI advertisement of the header method
[x] 3.1 (P) Declare the accessTokenHeaderAuth security scheme in the apiv1 and apiv3 definitions
apiKey / in: header / name: x-growi-access-token scheme to the security schemes and to the top-level security array in both definition filesbearer and accessTokenInQuery schemes[x] 3.2 Apply the header auth method to every advertising route
accessTokenHeaderAuth entry after every accessTokenInQuery block across the 9 current-master route files (26 sites): activity, user-activities, bookmark-folder, import, in-app-notification, page-listing, g2g-transfer, app-settings index, and features/ai-tools/suggest-path. Do not apply PR #10443's route hunks verbatim — drive edits off a full-tree sweep (grep -rn accessTokenInQuery apps/app/src) to absorb the app-settings path drift, the missing user-activities, and the features/ suggest-path routeaccessTokenHeaderAuth lines equals 26, and every route that advertises accessTokenInQuery also advertises accessTokenHeaderAuth[x] 4. Validation: regression and spec verification
[x] 4.1 Verify OpenAPI regeneration and run end-to-end quality gates
accessTokenHeaderAuth appears in the schemes and on each route that previously advertised accessTokenInQueryX-GROWI-ACCESS-TOKEN header resolve identically to pre-change behavior@lezer/*, styled-jsx in the client bundle) — see Implementation Notes; verify the production build in CI.X-GROWI-ACCESS-TOKEN value (duplicated header → array) is coerced to undefined before the ?? chain so resolution falls through to query/body, per requirements.md 3.4. design.md was corrected to match (the initial "centralized guard at end" wording implied short-circuit-to-null).accessTokenInQuery with a FULL-tree sweep (grep -rn accessTokenInQuery apps/app/src), not just server/routes/apiv3 — the features/ tree holds the suggest-path route (26 sites / 9 files, not 25 / 8).turbo run build --filter @growi/app FAILS in this devcontainer on a PRE-EXISTING, unrelated client-bundle dependency-hoisting issue — Turbopack cannot resolve @lezer/common, @lezer/lr (transitive deps of @codemirror/lang-python/lang-yaml) and styled-jsx (import trace: ConflictDiffModal → editor → codemirror; none touched by this server-only change). pnpm install --frozen-lockfile reports "Already up to date", so the state is lockfile-defined and independent of this feature. Verified green for this change: 23/23 access-token-parser tests, lint:typecheck (exit 0), lint:openapi:apiv1+apiv3 (1 passing/0 failing, 0 query-ops missing the header method), biome on changed files (only the pre-existing res-unused warning). The production build should be confirmed in CI (reusable-app-prod.yml), where the dependency environment is correct.