Skip to content

fix(appkit): trim x-forwarded-user in core OBO path#427

Open
atilafassina wants to merge 2 commits into
mainfrom
analytics-infra
Open

fix(appkit): trim x-forwarded-user in core OBO path#427
atilafassina wants to merge 2 commits into
mainfrom
analytics-infra

Conversation

@atilafassina

@atilafassina atilafassina commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Trims x-forwarded-user at both core OBO read sites (Plugin.resolveUserId + asUser) so surrounding whitespace can't fork user identity or the per-user analytics cache key; a whitespace-only value takes the missing-header path (prod throws, dev falls back). Mirrors the existing files-plugin precedent.

Includes 7 regression tests, notably one asserting that two OBO requests differing only by header whitespace share a single analytics cache key.

This covers a small edge-case where white-space in the user ID would generate a separate cache and telemetry entry.

resolveUserId and asUser now trim the x-forwarded-user header at read time, so
surrounding whitespace can't fork user identity or the per-user analytics cache key.
Mirrors the existing files-plugin precedent; whitespace-only values resolve to the
missing-header path (prod throws, dev falls back).

Co-authored-by: Isaac
Signed-off-by: Atila Fassina <atila@fassina.eu>
Lock the Phase 1 trim: resolveUserId/asUser normalize a padded x-forwarded-user to
the bare id; whitespace-only takes the missing-header path (prod throws, dev falls back);
and two OBO analytics requests differing only by header whitespace share one cache key.

Co-authored-by: Isaac
Signed-off-by: Atila Fassina <atila@fassina.eu>
@atilafassina atilafassina marked this pull request as ready for review June 9, 2026 10:04
@atilafassina atilafassina requested a review from a team as a code owner June 9, 2026 10:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the core “on-behalf-of user” (OBO) identity resolution by trimming x-forwarded-user at both read sites, preventing whitespace variants from forking user identity and per-user analytics caching/telemetry.

Changes:

  • Trim x-forwarded-user in Plugin.resolveUserId(req) and Plugin.asUser(req).
  • Add regression tests to pin whitespace normalization behavior (including prod vs dev behavior for whitespace-only values).
  • Add an analytics regression test ensuring OBO requests with whitespace-only differences share the same per-user cache key.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
packages/appkit/src/plugin/plugin.ts Trims x-forwarded-user in core OBO identity resolution (resolveUserId, asUser).
packages/appkit/src/plugin/tests/asUser-proxy.test.ts Adds tests asserting header trimming behavior and whitespace-only handling paths.
packages/appkit/src/plugins/analytics/tests/analytics.test.ts Adds regression test ensuring whitespace variants of x-forwarded-user do not fork OBO cache keys.
Comments suppressed due to low confidence (1)

packages/appkit/src/plugin/plugin.ts:418

  • resolveUserId throws AuthenticationError.missingToken(...) but passes a full sentence starting with "Missing ..." as the tokenType, which results in a duplicated/awkward message ("Missing Missing ... in request headers"). This should use missingUserId() (consistent with asUser) or pass just the header name to missingToken.
    throw AuthenticationError.missingToken(
      "Missing x-forwarded-user header. Cannot resolve user ID.",
    );

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 432 to 434
const token = req.header("x-forwarded-access-token");
const userId = req.header("x-forwarded-user");
const userId = req.header("x-forwarded-user")?.trim();
const userEmail = req.header("x-forwarded-email");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants