GROWI's API authentication currently accepts an access token in only two ways: as a
Bearer token in the Authorization header, or as an access_token query parameter
(see https://docs.growi.org/en/api/rest-v3.html).
When the Authorization header is already consumed by something else (e.g. Basic
authentication on a reverse proxy), callers are forced to fall back to the query
parameter. Putting the token in a GET query string is insecure — it leaks into URLs,
server logs, browser history, and referrers
(see https://owasp.org/www-community/vulnerabilities/Information_exposure_through_query_strings_in_url).
There is also no spec governing the access-token-parser middleware, so future changes
have no requirements/design baseline to maintain against (cc-sdd).
access-token-parser middleware is already implemented at
apps/app/src/server/middlewares/access-token-parser/:
index.ts — accessTokenParser(scopes, opts) orchestrator; runs
parserForAccessToken(scopes) and, when opts.acceptLegacy, parserForApiToken.access-token.ts — parserForAccessToken: scope-checked AccessToken model lookup.api-token.ts — parserForApiToken: legacy User.apiToken lookup.extract-bearer-token.ts — pulls the Bearer token from Authorization.*.integ.ts integration tests.bearerToken ?? req.query.access_token ?? req.body.access_token.
There is no header source between Bearer and query.support/api-token-header, base master,
+114/-6, 13 files) by ryu-sato adds exactly the missing X-GROWI-ACCESS-TOKEN
header support. This PR is the salvage source for the current deliverable.access-token-parser spec exists yet.x-growi-access-token
request header, with priority directly after the Authorization Bearer token and
before the query/body sources — for both the scoped AccessToken path and the legacy
api-token path.accessTokenHeaderAuth security scheme and applied to the relevant routes.access-token-parser changes can be maintained
via cc-sdd (requirements → design → tasks → impl).Salvage PR #10443 onto a fresh branch cut from master (NOT from the current
imprv/x-access-token-header branch, which carries unrelated MongoDB-regex work), then
open a new PR to master. The technical change is small and well understood:
?? req.headers['x-growi-access-token'] between the Bearer token and the
query/body sources in both access-token.ts and api-token.ts.accessTokenHeaderAuth (type: apiKey, in: header,
name: x-growi-access-token) security scheme to bin/openapi/definition-apiv1.js
and definition-apiv3.js, and to the top-level security array.- accessTokenHeaderAuth: [] to the per-route OpenAPI security blocks.Salvage hygiene: copy only the meaningful changes. PR #10443 also contains
incidental import reordering (the SCOPE import moved) caused by its older base —
do not carry that noise. Re-verify the route list against current master, since routes
added/changed since the PR was opened may also need the accessTokenHeaderAuth: [] line
for consistency.
Workflow: hybrid. Lock intent in brief + requirements first; implement the salvage and open the PR; then finalize design/tasks so the spec stands as the maintenance baseline that matches what shipped.
x-growi-access-token header as a token source in parserForAccessToken and
parserForApiToken, with correct priority ordering.accessTokenHeaderAuth OpenAPI security scheme (apiv1 + apiv3) and its application
to the affected routes.@growi/core).@growi/core interfaces (Scope, AccessTokenParser*, IUserHasId),
the AccessToken Mongoose model, serializeUserSecurely. Salvage source: PR #10443.accessTokenParser; OpenAPI consumers
reading the generated security schemes.master, not the current imprv/x-access-token-header branch.spec.json.language: en).req.headers['x-growi-access-token'].master; use gh CLI for all GitHub operations.