Skip to content

refactor(pds-core): extract OAuth client-id resolution from CSS middleware - #241

Merged
aspiers merged 2 commits into
mainfrom
split148/oauth-request-context
Aug 6, 2026
Merged

refactor(pds-core): extract OAuth client-id resolution from CSS middleware#241
aspiers merged 2 commits into
mainfrom
split148/oauth-request-context

Conversation

@aspiers

@aspiers aspiers commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Split 1 of 4 from #148, which bundled four independent concerns behind ~1900 lines of enrichment tests. This is the shared dependency the others build on.

What it does

OAuth authorize pages carry either an explicit client_id query parameter or only a PAR request_uri that has to be resolved through the provider's request manager. That resolution lived inline in the CSS injection middleware. Chooser enrichment (split 4) needs exactly the same step, so this hoists it into packages/pds-core/src/lib/oauth-request-context.ts rather than duplicating it at the second call site.

Resolver errors stay with the caller, so each middleware keeps its own logging and fallback behaviour.

Behaviour change

One, deliberate: the CSS middleware's failed-resolution log moves from warn to error, and LoggerLike gains an error method. A client_id that cannot be resolved means the page renders unbranded, which is worth an error-level line.

Otherwise this is a pure refactor — same resolution order (explicit client_id first, then PAR lookup), same fallbacks.

No changeset: internal refactor with no observable behaviour change for end users, client app developers, or operators.

Verification

typecheck, lint, format clean; 74 test files / 1129 tests pass.

Note on #80

This touches the same log statement that #80 redacts requestUri from. Whichever lands first, the other is a one-line rebase.

Series

  1. refactor(pds-core): extract OAuth client-id resolution from CSS middleware #241 ← this PR — extract OAuth client-id resolution
  2. fix(auth): gate email sign-in until its handlers are installed #242 — gate email sign-in until handlers are installed
  3. feat(auth): sign epds_handle_mode through the callback hop #243 — sign epds_handle_mode through the callback hop
  4. fix(pds-core): identify generated-handle accounts by email #244 — identify generated-handle accounts by email

The four branches together are byte-identical to #148's head, verified by merging them and diffing against 7fe24bb (the only difference is the original single changeset, split into three).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved OAuth client identification for direct requests and PAR flows.
    • Failed request-URI resolution no longer interrupts request processing.
    • Error logging now avoids exposing sensitive request-URI values and records only necessary metadata.
  • Reliability
    • Added coverage for client-ID resolution, fallback behavior, invalid requests, and error handling.

Copilot AI lite review requested due to automatic review settings August 5, 2026 17:08
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
epds-demo Ready Ready Preview Aug 6, 2026 9:17am

Request Review

@changeset-bot

changeset-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 707355b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@railway-app
railway-app Bot temporarily deployed to ePDS / ePDS-pr-241 August 5, 2026 17:09 Destroyed
@railway-app

railway-app Bot commented Aug 5, 2026

Copy link
Copy Markdown

🚅 Deployed to the ePDS-pr-241 environment in ePDS

Service Status Web Updated (UTC)
@certified-app/pds-core ✅ Success (View Logs) Web Aug 6, 2026 at 9:17 am
@certified-app/demo untrusted ✅ Success (View Logs) Web Aug 5, 2026 at 5:11 pm
@certified-app/auth-service ✅ Success (View Logs) Web Aug 5, 2026 at 5:11 pm
@certified-app/demo ✅ Success (View Logs) Web Aug 5, 2026 at 5:11 pm

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 43b96617-4c88-4de5-b19c-252b7c11584c

📥 Commits

Reviewing files that changed from the base of the PR and between 2b10346 and 707355b.

📒 Files selected for processing (4)
  • packages/pds-core/src/__tests__/client-css-injection.test.ts
  • packages/pds-core/src/__tests__/oauth-request-context.test.ts
  • packages/pds-core/src/lib/client-css-injection.ts
  • packages/pds-core/src/lib/oauth-request-context.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/pds-core/src/tests/oauth-request-context.test.ts
  • packages/pds-core/src/lib/oauth-request-context.ts
  • packages/pds-core/src/lib/client-css-injection.ts

📝 Walkthrough

Walkthrough

This change adds shared OAuth client ID resolution for direct client_id and PAR request_uri values. CSS injection middleware uses the resolver, logs failures without the URI value, and continues processing. Tests cover resolution behavior and logging.

Changes

OAuth client resolution

Layer / File(s) Summary
OAuth query resolution contract and tests
packages/pds-core/src/lib/oauth-request-context.ts, packages/pds-core/src/__tests__/oauth-request-context.test.ts
Adds OAuth query and request URI resolver types. Resolves direct client_id values before request_uri values. Tests cover invalid input, missing resolvers, unresolved URIs, and propagated errors.
CSS injection middleware integration
packages/pds-core/src/lib/client-css-injection.ts, packages/pds-core/src/__tests__/client-css-injection.test.ts
Uses the shared resolver, requires LoggerLike.error, logs only request URI presence metadata on resolution failure, and continues middleware processing.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant CSSInjectionMiddleware
  participant resolveOAuthClientIdFromQuery
  participant ResolveClientIdFromRequestUri
  participant Logger
  CSSInjectionMiddleware->>resolveOAuthClientIdFromQuery: Resolve client ID from query
  resolveOAuthClientIdFromQuery->>ResolveClientIdFromRequestUri: Resolve request_uri when needed
  ResolveClientIdFromRequestUri-->>resolveOAuthClientIdFromRequestUri: Return client ID or error
  resolveOAuthClientIdFromQuery-->>CSSInjectionMiddleware: Return resolved ID or error
  CSSInjectionMiddleware->>Logger: Log request URI presence metadata
  CSSInjectionMiddleware->>CSSInjectionMiddleware: Continue processing
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes extracting OAuth client-ID resolution from the CSS middleware.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch split148/oauth-request-context

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coveralls-official

coveralls-official Bot commented Aug 5, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 31088414989

Coverage increased (+0.3%) to 58.36%

Details

  • Coverage increased (+0.3%) from the base build.
  • Patch coverage: 8 of 8 lines across 2 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 3111
Covered Lines: 1800
Line Coverage: 57.86%
Relevant Branches: 1937
Covered Branches: 1146
Branch Coverage: 59.16%
Branches in Coverage %: Yes
Coverage Strength: 9.8 hits per line

💛 - Coveralls

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/pds-core/src/lib/client-css-injection.ts`:
- Around line 170-174: The error path in resolveClientIdFromRequestUri currently
logs the sensitive raw query.request_uri; replace that field in the logger.error
call with non-sensitive context such as hasRequestUri. Add or retain a
regression test for this branch asserting the logged error does not contain a
raw requestUri value.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e1e40245-95e7-4135-9fd8-97b657f84f9d

📥 Commits

Reviewing files that changed from the base of the PR and between 9781ef3 and 9ac34d4.

📒 Files selected for processing (4)
  • packages/pds-core/src/__tests__/client-css-injection.test.ts
  • packages/pds-core/src/__tests__/oauth-request-context.test.ts
  • packages/pds-core/src/lib/client-css-injection.ts
  • packages/pds-core/src/lib/oauth-request-context.ts

Comment thread packages/pds-core/src/lib/client-css-injection.ts

Copilot AI left a comment

Copy link
Copy Markdown

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 refactors pds-core OAuth response-enrichment utilities by extracting “OAuth client_id resolution from authorize request query/PAR request_uri” into a shared helper, so multiple middlewares can reuse the same resolution logic without duplication.

Changes:

  • Introduces resolveOAuthClientIdFromQuery() in a new oauth-request-context helper module.
  • Updates the client CSS injection middleware to use the shared resolver and adjusts logging (including adding logger.error to the middleware’s logger contract).
  • Adds unit test coverage for the new resolver helper.

Reviewed changes

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

File Description
packages/pds-core/src/lib/oauth-request-context.ts New shared helper to resolve OAuth client_id from either explicit query param or PAR request_uri.
packages/pds-core/src/lib/client-css-injection.ts Refactors inline resolution into the shared helper; adds LoggerLike.error and changes failure logging path.
packages/pds-core/src/tests/oauth-request-context.test.ts New unit tests covering resolution order, fallbacks, and error propagation.
packages/pds-core/src/tests/client-css-injection.test.ts Updates logger mock shape to include error.

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

Comment thread packages/pds-core/src/lib/client-css-injection.ts
aspiers added a commit that referenced this pull request Aug 5, 2026
request_uri is a short-lived bearer reference to the PAR entry, so a
log line carrying its value is replayable by anyone who can read the
logs. Log whether it was present instead.

Raised independently by CodeRabbit and Copilot on #241. The value was
already being logged before this series; hoisting the resolution out
of the request_uri guard promoted the line from warn to error, which
made it more visible without making it safe. #80 fixes the same leak
on the pre-refactor code.

typeof rather than a hardcoded true: the log now sits outside the
`if (requestUri)` guard, so presence is no longer implied by reaching
it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@railway-app
railway-app Bot temporarily deployed to ePDS / ePDS-pr-241 August 5, 2026 17:25 Destroyed
@aspiers

aspiers commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in ee1ec80. Both @coderabbitai and @copilot-pull-request-reviewer flagged this independently, and it's valid — the value was reaching the logs.

-        { err, requestUri: query.request_uri },
+        { err, hasRequestUri: typeof query.request_uri === 'string' },

typeof rather than the hardcoded true that #80 uses: this refactor hoisted the resolution out of the if (requestUri) guard, so reaching the catch block no longer implies a request_uri was present. Logging true unconditionally here would be wrong for client_id flows that fail for other reasons.

Worth being clear that I introduced the more visible half of this: the value was already being logged before this series, but promoting the line from warn to error made it more likely to be retained and shipped to log aggregation. The leak predates the split; the promotion didn't help.

Added a regression test that asserts the log context contains hasRequestUri: true and that the serialized context does not contain the URI value. Verified it fails against the unredacted version (1 failed / 21 passed) and passes with the fix.

#80 fixes the same leak on the pre-refactor code. Whichever lands first, the other is a small rebase.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@aspiers Confirmed. The fix removes the request_uri value from the log context and preserves useful diagnostic state with hasRequestUri.

Using typeof query.request_uri === 'string' is correct because this catch path can occur without a PAR request_uri. The regression test covers both the retained boolean and the absence of the sensitive URI value.

🐇 ✅


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

You are interacting with an AI system.

aspiers and others added 2 commits August 6, 2026 10:12
…eware

OAuth authorize pages carry either an explicit client_id query
parameter or only a PAR request_uri that has to be resolved through
the provider's request manager. That resolution lived inline in the
CSS injection middleware, but chooser enrichment needs exactly the
same step, so hoist it into a shared module rather than duplicating
it at the second call site.

Resolver errors stay with the caller so each middleware keeps its own
logging and fallback behaviour. The CSS middleware's failure log moves
from warn to error, since a client_id that cannot be resolved means
the page renders unbranded.

Split out of #148, which bundled this refactor with the enrichment
work that motivated it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
request_uri is a short-lived bearer reference to the PAR entry, so a
log line carrying its value is replayable by anyone who can read the
logs. Log whether it was present instead.

Raised independently by CodeRabbit and Copilot on #241. The value was
already being logged before this series; hoisting the resolution out
of the request_uri guard promoted the line from warn to error, which
made it more visible without making it safe. #80 fixes the same leak
on the pre-refactor code.

typeof rather than a hardcoded true: the log now sits outside the
`if (requestUri)` guard, so presence is no longer implied by reaching
it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@aspiers
aspiers force-pushed the split148/oauth-request-context branch from ee1ec80 to 707355b Compare August 6, 2026 09:16
@railway-app
railway-app Bot temporarily deployed to ePDS / ePDS-pr-241 August 6, 2026 09:16 Destroyed
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@aspiers

aspiers commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main after #80 merged. That conflict was expected — both PRs changed the same log statement.

Resolved in favour of this PR's refactored form, which preserves #80's intent:

logger.error(
  { err, hasRequestUri: typeof query.request_uri === 'string' },
  'CSS middleware: failed to resolve client_id from request_uri',
)

#80 landed hasRequestUri: true inside the if (requestUri) guard, where presence is guaranteed. This PR hoists the resolution into resolveOAuthClientIdFromQuery, so the catch block is now reachable for client_id flows that fail for other reasons — a hardcoded true would be wrong there. The typeof form is the same redaction under the wider scope.

The warnerror promotion is unchanged from before the rebase.

Verified the full stack (#241#243#244, plus #242) still reproduces #148 exactly: merging all four branches and diffing against #148's head merged into current main yields only the two redaction fixes and their tests. Everything else is identical.

All four rebased branches pass typecheck, lint, format and the full vitest suite locally.

@sonarqubecloud

sonarqubecloud Bot commented Aug 6, 2026

Copy link
Copy Markdown

@aspiers
aspiers merged commit 36eab67 into main Aug 6, 2026
24 checks passed
@aspiers
aspiers deleted the split148/oauth-request-context branch August 6, 2026 09:56
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.

2 participants