Skip to content

feat(oidc-client): add-par-support#631

Open
ryanbas21 wants to merge 2 commits into
mainfrom
par
Open

feat(oidc-client): add-par-support#631
ryanbas21 wants to merge 2 commits into
mainfrom
par

Conversation

@ryanbas21
Copy link
Copy Markdown
Collaborator

@ryanbas21 ryanbas21 commented May 11, 2026

Add support for par in oidc client.

JIRA Ticket

https://pingidentity.atlassian.net/browse/SDKS-4236

Description

Adds support for PAR for redirect based flows in oidc-client

Summary by CodeRabbit

  • New Features

    • OIDC client adds PAR support (opt-in flag, typed PAR response) and a server-driven opt-in when required.
  • User Interface

    • Demo page and navigation link for PAR flows with interactive login and token actions.
  • Tests

    • New unit and e2e tests for PAR background, redirect and error scenarios.
  • Chores

    • Test mock server and build config updated to simulate and include PAR endpoints.

Review Change Stack

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 11, 2026

🦋 Changeset detected

Latest commit: e012bed

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@forgerock/sdk-request-middleware Minor
@forgerock/sdk-oidc Minor
@forgerock/davinci-client Minor
@forgerock/oidc-client Minor
am-mock-api Patch
@forgerock/journey-client Minor
@forgerock/device-client Minor
@forgerock/protect Minor
@forgerock/sdk-types Minor
@forgerock/sdk-utilities Minor
@forgerock/iframe-manager Minor
@forgerock/sdk-logger Minor
@forgerock/storage Minor

Not sure what this means? Click here to learn what changesets are.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Warning

Rate limit exceeded

@ryanbas21 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 51 minutes before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 01cc3512-72d4-4514-8e02-218ef33dc70e

📥 Commits

Reviewing files that changed from the base of the PR and between a3bcb7a and e012bed.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (33)
  • .changeset/some-shirts-joke.md
  • e2e/am-mock-api/src/app/constants.js
  • e2e/am-mock-api/src/app/responses.js
  • e2e/am-mock-api/src/app/routes.auth.js
  • e2e/oidc-app/src/index.html
  • e2e/oidc-app/src/par/index.html
  • e2e/oidc-app/src/par/main.ts
  • e2e/oidc-app/src/utils/oidc-app.ts
  • e2e/oidc-app/vite.config.ts
  • e2e/oidc-suites/src/login.spec.ts
  • e2e/oidc-suites/src/par.spec.ts
  • packages/davinci-client/api-report/davinci-client.api.md
  • packages/davinci-client/api-report/davinci-client.types.api.md
  • packages/oidc-client/api-report/oidc-client.api.md
  • packages/oidc-client/api-report/oidc-client.types.api.md
  • packages/oidc-client/package.json
  • packages/oidc-client/src/lib/authorize.request.micros.test.ts
  • packages/oidc-client/src/lib/authorize.request.micros.ts
  • packages/oidc-client/src/lib/authorize.request.ts
  • packages/oidc-client/src/lib/authorize.request.utils.test.ts
  • packages/oidc-client/src/lib/authorize.request.utils.ts
  • packages/oidc-client/src/lib/client.store.test.ts
  • packages/oidc-client/src/lib/client.store.ts
  • packages/oidc-client/src/lib/config.types.ts
  • packages/oidc-client/src/lib/oidc.api.ts
  • packages/oidc-client/src/lib/par.types.ts
  • packages/oidc-client/src/types.ts
  • packages/oidc-client/tsconfig.lib.json
  • packages/sdk-effects/oidc/src/index.ts
  • packages/sdk-effects/oidc/src/lib/authorize.effects.ts
  • packages/sdk-effects/oidc/src/lib/authorize.test.ts
  • packages/sdk-effects/oidc/src/lib/authorize.utils.ts
  • packages/sdk-effects/sdk-request-middleware/src/lib/request-mware.derived.ts
📝 Walkthrough

Walkthrough

Adds end-to-end PAR (Pushed Authorization Request) support: centralizes authorize-parameter building, adds effects/micros for PAR/dispatch, integrates PAR into authorize flow, updates SDK entry exports, and adds unit and E2E tests and fixtures.

Changes

Pushed Authorization Request (PAR) Support

Layer / File(s) Summary
Entrypoints and E2E pages
packages/sdk-effects/oidc/src/index.ts, e2e/oidc-suites/src/par.spec.ts, e2e/oidc-app/src/par/*
Exports authorize utils from sdk-effects entry; adds E2E PAR spec and page scaffolding and network interception helpers.
SDK effects integration
packages/sdk-effects/oidc/src/lib/authorize.effects.ts
createAuthorizeUrl now delegates parameter construction to buildAuthorizeParams.
Request middleware types
packages/sdk-effects/sdk-request-middleware/src/lib/request-mware.derived.ts
Adds par actionType so middleware endpoint types include PAR.
Client store tests & MSW PAR mocks
packages/oidc-client/src/lib/client.store.test.ts
Adds MSW /as/par mock returning request_uri, expands tests to validate slim URL shape, PAR error handling, factory/config behavior, and background/redirect flows.
Authorize utils & flow tests
packages/oidc-client/src/lib/authorize.request.utils.test.ts, other authorize tests
Adds/expands unit and integration tests for parAuthorizeµ, guards, validateParResponse, buildParAuthorizeUrl, buildAuthorizeOptions, and authorizeµ routing between PAR and non-PAR flows.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant OidcLib
  participant RTK_Par
  participant AuthServer

  Client->>OidcLib: authorize.url (useParFlow = true)
  OidcLib->>OidcLib: build auth params + PKCE (buildAuthorizeParams / generatePkceChallenge)
  OidcLib->>RTK_Par: POST { endpoint, body: URLSearchParams } (dispatchParRequest)
  RTK_Par->>AuthServer: HTTP POST /par
  AuthServer-->>RTK_Par: { request_uri, expires_in }
  RTK_Par-->>OidcLib: PushAuthorizationResponse
  OidcLib-->>Client: slim authorize URL (client_id + request_uri)
  Client->>AuthServer: Redirect with slim URL
  AuthServer-->>Client: Redirect with code & state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • cerebrl

Poem

🐰 I nudged a tiny PAR through night,

Sent a URI, tucked it tight,
A slim redirect, tidy and neat,
Tokens dance when code and state meet,
Hooray — a hop that made auth neat.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat(oidc-client): add-par-support' clearly describes the main change: adding PAR (Pushed Authorization Request) support to the oidc-client package, which aligns with the actual changeset modifications.
Description check ✅ Passed The PR description includes the JIRA ticket reference (SDKS-4236) and provides a clear explanation of the changes: adding PAR support for redirect-based flows in oidc-client, meeting the template requirements.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch par

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 and usage tips.

@nx-cloud
Copy link
Copy Markdown
Contributor

nx-cloud Bot commented May 11, 2026

View your CI Pipeline Execution ↗ for commit 08f8d74

Command Status Duration Result
nx run-many -t build --no-agents ✅ Succeeded <1s View ↗
nx affected -t build lint test typecheck e2e-ci ✅ Succeeded 55s View ↗

☁️ Nx Cloud last updated this comment at 2026-05-20 19:40:39 UTC

@ryanbas21 ryanbas21 force-pushed the par branch 2 times, most recently from 1ee2b2c to 5526f30 Compare May 12, 2026 19:09
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 13, 2026

Open in StackBlitz

@forgerock/davinci-client

pnpm add https://pkg.pr.new/@forgerock/davinci-client@631

@forgerock/device-client

pnpm add https://pkg.pr.new/@forgerock/device-client@631

@forgerock/journey-client

pnpm add https://pkg.pr.new/@forgerock/journey-client@631

@forgerock/oidc-client

pnpm add https://pkg.pr.new/@forgerock/oidc-client@631

@forgerock/protect

pnpm add https://pkg.pr.new/@forgerock/protect@631

@forgerock/sdk-types

pnpm add https://pkg.pr.new/@forgerock/sdk-types@631

@forgerock/sdk-utilities

pnpm add https://pkg.pr.new/@forgerock/sdk-utilities@631

@forgerock/iframe-manager

pnpm add https://pkg.pr.new/@forgerock/iframe-manager@631

@forgerock/sdk-logger

pnpm add https://pkg.pr.new/@forgerock/sdk-logger@631

@forgerock/sdk-oidc

pnpm add https://pkg.pr.new/@forgerock/sdk-oidc@631

@forgerock/sdk-request-middleware

pnpm add https://pkg.pr.new/@forgerock/sdk-request-middleware@631

@forgerock/storage

pnpm add https://pkg.pr.new/@forgerock/storage@631

commit: e012bed

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 13, 2026

Codecov Report

❌ Patch coverage is 87.79599% with 67 lines in your changes missing coverage. Please review.
✅ Project coverage is 19.84%. Comparing base (eafe277) to head (e012bed).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
packages/oidc-client/src/lib/client.store.ts 53.03% 31 Missing ⚠️
...es/oidc-client/src/lib/authorize.request.micros.ts 89.36% 25 Missing ⚠️
packages/oidc-client/src/lib/authorize.request.ts 92.55% 7 Missing ⚠️
packages/oidc-client/src/lib/oidc.api.ts 95.23% 3 Missing ⚠️
packages/sdk-effects/oidc/src/index.ts 0.00% 1 Missing ⚠️

❌ Your project status has failed because the head coverage (19.84%) is below the target coverage (40.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #631      +/-   ##
==========================================
+ Coverage   18.07%   19.84%   +1.77%     
==========================================
  Files         155      158       +3     
  Lines       24398    24788     +390     
  Branches     1203     1331     +128     
==========================================
+ Hits         4410     4920     +510     
+ Misses      19988    19868     -120     
Files with missing lines Coverage Δ
...ges/oidc-client/src/lib/authorize.request.utils.ts 100.00% <100.00%> (+56.66%) ⬆️
packages/oidc-client/src/lib/config.types.ts 100.00% <ø> (ø)
packages/oidc-client/src/lib/par.types.ts 100.00% <100.00%> (ø)
packages/oidc-client/src/types.ts 14.28% <ø> (ø)
...ages/sdk-effects/oidc/src/lib/authorize.effects.ts 100.00% <100.00%> (ø)
...ckages/sdk-effects/oidc/src/lib/authorize.utils.ts 100.00% <100.00%> (ø)
...equest-middleware/src/lib/request-mware.derived.ts 100.00% <100.00%> (ø)
packages/sdk-effects/oidc/src/index.ts 20.00% <0.00%> (-5.00%) ⬇️
packages/oidc-client/src/lib/oidc.api.ts 65.51% <95.23%> (+18.31%) ⬆️
packages/oidc-client/src/lib/authorize.request.ts 93.33% <92.55%> (+60.00%) ⬆️
... and 2 more

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 13, 2026

Deployed 673dc21 to https://ForgeRock.github.io/ping-javascript-sdk/pr-631/673dc21a2cb934f8955a39f975afb93a94249602 branch gh-pages in ForgeRock/ping-javascript-sdk

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 13, 2026

📦 Bundle Size Analysis

📦 Bundle Size Analysis

🚨 Significant Changes

🔺 @forgerock/sdk-oidc - 5.7 KB (+0.9 KB, +18.9%)
🔻 @forgerock/device-client - 0.0 KB (-10.0 KB, -100.0%)
🔺 @forgerock/oidc-client - 30.3 KB (+5.1 KB, +20.4%)
🔻 @forgerock/journey-client - 0.0 KB (-91.9 KB, -100.0%)

📊 Minor Changes

📈 @forgerock/sdk-request-middleware - 4.6 KB (+0.0 KB)

➖ No Changes

@forgerock/storage - 1.5 KB
@forgerock/iframe-manager - 2.4 KB
@forgerock/sdk-logger - 1.6 KB
@forgerock/sdk-types - 7.9 KB
@forgerock/davinci-client - 54.1 KB
@forgerock/protect - 144.6 KB
@forgerock/device-client - 10.0 KB
@forgerock/sdk-utilities - 11.2 KB
@forgerock/journey-client - 91.9 KB


14 packages analyzed • Baseline from latest main build

Legend

🆕 New package
🔺 Size increased
🔻 Size decreased
➖ No change

ℹ️ How bundle sizes are calculated
  • Current Size: Total gzipped size of all files in the package's dist directory
  • Baseline: Comparison against the latest build from the main branch
  • Files included: All build outputs except source maps and TypeScript build cache
  • Exclusions: .map, .tsbuildinfo, and .d.ts.map files

🔄 Updated automatically on each push to this PR

nx-cloud[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@nx-cloud nx-cloud Bot left a comment

Choose a reason for hiding this comment

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

Important

At least one additional CI pipeline execution has run since the conclusion below was written and it may no longer be applicable.

Nx Cloud is proposing a fix for your failed CI:

We updated the PAR background login test to match the two-step flow introduced alongside it in this PR: the journey form must be submitted first to establish an AM session and enable the Login (Background) button before background auth can succeed. The original test skipped that step, causing Playwright to time out waiting for the disabled button to become actionable, and incorrectly expected a redirect to the AM login page which does not occur in the prompt=none silent-auth happy path.

Warning

We could not verify this fix.

Suggested Fix changes
diff --git a/e2e/oidc-suites/src/par.spec.ts b/e2e/oidc-suites/src/par.spec.ts
index d680f95..08afd89 100644
--- a/e2e/oidc-suites/src/par.spec.ts
+++ b/e2e/oidc-suites/src/par.spec.ts
@@ -12,7 +12,7 @@ import { asyncEvents } from './utils/async-events.js';
 
 test.describe('PAR (Pushed Authorization Request) login tests', () => {
   test('background login with PAR enabled (ParClient) obtains access token', async ({ page }) => {
-    const { clickWithRedirect, navigate } = asyncEvents(page);
+    const { navigate } = asyncEvents(page);
 
     const parRequests: string[] = [];
 
@@ -24,14 +24,14 @@ test.describe('PAR (Pushed Authorization Request) login tests', () => {
 
     await navigate('/par/');
 
-    await clickWithRedirect('Login (Background)', '**/am/XUI/**');
-
+    // Step 1: Establish AM session via journey login to enable the background button
     await page.getByLabel('User Name').fill(pingAmUsername);
-    await page.getByRole('textbox', { name: 'Password' }).fill(pingAmPassword);
-    await clickWithRedirect('Next', 'http://localhost:8443/par/**');
+    await page.getByLabel('Password').fill(pingAmPassword);
+    await page.getByRole('button', { name: 'Login (Journey)' }).click();
+    await expect(page.locator('#journey-status')).toContainText('Session established');
 
-    expect(page.url()).toContain('code');
-    expect(page.url()).toContain('state');
+    // Step 2: Background PAR auth with prompt=none succeeds silently using existing session
+    await page.getByRole('button', { name: 'Login (Background)' }).click();
 
     await expect(page.locator('#accessToken-0')).not.toBeEmpty();
 

Apply fix via Nx Cloud  Reject fix via Nx Cloud


Or Apply changes locally with:

npx nx-cloud apply-locally JZaG-dtfX

Apply fix locally with your editor ↗   View interactive diff ↗



🎓 Learn more about Self-Healing CI on nx.dev

@ryanbas21 ryanbas21 marked this pull request as ready for review May 13, 2026 19:51
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (4)
e2e/oidc-app/src/par/main.ts (2)

59-61: ⚡ Quick win

Error detection may not catch all failure cases.

The success check if (!submitJson.tokenId && !submitJson.successUrl) only throws when both fields are absent. However, AM may return error responses with different structures (e.g., { code: 401, message: 'Authentication Failed' }).

🛡️ More robust error detection
-if (!submitJson.tokenId && !submitJson.successUrl) {
-  throw new Error(submitJson.message || 'Login failed');
-}
+if (submitJson.code && submitJson.code >= 400) {
+  throw new Error(submitJson.message || `Login failed with code ${submitJson.code}`);
+}
+if (!submitJson.tokenId && !submitJson.successUrl) {
+  throw new Error(submitJson.message || 'Login failed');
+}
🤖 Prompt for 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.

In `@e2e/oidc-app/src/par/main.ts` around lines 59 - 61, The current check in
main.ts using submitJson (if (!submitJson.tokenId && !submitJson.successUrl))
misses alternate error shapes; update the validation around submitJson (the PAR
response handling) to treat any response that lacks tokenId and lacks successUrl
as an error and also detect common error shapes like presence of a numeric code
or a message string (e.g., submitJson.code, submitJson.message) — throw an Error
that includes submitJson.message when present otherwise include a safe
serialization of submitJson (JSON.stringify(submitJson)) so callers get
meaningful diagnostics; ensure this change is applied where submitJson is
handled in the PAR response block.

45-48: ⚡ Quick win

Consider defensive callback validation.

The code mutates initJson.callbacks without first checking whether the array exists or contains the expected callback types. If the journey response structure changes or the Login journey is misconfigured, this could throw a runtime error.

🛡️ Add defensive checks
 // Fill NameCallback + PasswordCallback
-for (const cb of initJson.callbacks ?? []) {
+const callbacks = initJson.callbacks ?? [];
+const nameCallback = callbacks.find((cb) => cb.type === 'NameCallback');
+const passwordCallback = callbacks.find((cb) => cb.type === 'PasswordCallback');
+
+if (!nameCallback || !passwordCallback) {
+  throw new Error('Expected NameCallback and PasswordCallback not found in journey');
+}
+
+nameCallback.input[0].value = username;
+passwordCallback.input[0].value = password;
+
+for (const cb of callbacks) {
   if (cb.type === 'NameCallback') cb.input[0].value = username;
   if (cb.type === 'PasswordCallback') cb.input[0].value = password;
 }

Alternatively, simpler version that just validates presence:

+if (!initJson.callbacks || initJson.callbacks.length === 0) {
+  throw new Error('No callbacks returned from journey');
+}
+
 for (const cb of initJson.callbacks ?? []) {
   if (cb.type === 'NameCallback') cb.input[0].value = username;
   if (cb.type === 'PasswordCallback') cb.input[0].value = password;
 }
🤖 Prompt for 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.

In `@e2e/oidc-app/src/par/main.ts` around lines 45 - 48, The loop over
initJson.callbacks in main.ts blindly mutates callback objects and can throw if
callbacks is missing or items lack expected shape; update the code that iterates
initJson.callbacks to first verify initJson.callbacks is an array and for each
cb confirm cb.type is defined and cb.input is an array with at least one element
before setting cb.input[0].value, and skip or log a warning for entries that
don’t match expected "NameCallback" / "PasswordCallback" shapes so the login
flow fails gracefully instead of raising a runtime error.
e2e/oidc-suites/src/par.spec.ts (1)

13-13: ⚡ Quick win

Add type annotation for the page parameter.

The page parameter should have an explicit type annotation for consistency with TypeScript best practices.

📝 Proposed fix to add type annotation
+import type { Page } from '@playwright/test';
+
-async function loginJourney(page, username: string, password: string) {
+async function loginJourney(page: Page, username: string, password: string) {
🤖 Prompt for 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.

In `@e2e/oidc-suites/src/par.spec.ts` at line 13, The function loginJourney is
missing a TypeScript type for the page parameter; add an explicit Playwright
Page type by updating the signature to accept page: Page and ensure you import
Page from your Playwright test package (e.g. import { Page } from
'@playwright/test' or 'playwright' if not already imported), then update the
function declaration loginJourney(page: Page, username: string, password:
string) accordingly.
packages/oidc-client/src/lib/authorize.request.utils.test.ts (1)

109-224: ⚡ Quick win

Add one PAR regression case for request-level overrides.

All of the new PAR cases use the base config, so they won't catch a mismatch when a call overrides scope, redirectUri, or responseType. One assertion against the dispatched PAR body for an overridden value would lock that contract down.

🤖 Prompt for 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.

In `@packages/oidc-client/src/lib/authorize.request.utils.test.ts` around lines
109 - 224, Add a PAR regression test that verifies request-level overrides are
propagated into the PAR POST body: create a test that calls parAuthorizeµ with
par: true and passes overrides (e.g., scope: 'openid profile', redirectUri:
'https://app/callback', responseType: 'code') and stub sessionStorage as other
tests do; spy on sdkOidc.buildAuthorizeParams or inspect the first argument
passed to mockStore.dispatch to assert the PAR body includes those overridden
fields (scope, redirect_uri, response_type) instead of the values from the base
config, and keep existing assertions about the returned slim URL.
🤖 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 `@e2e/oidc-suites/src/par.spec.ts`:
- Line 64: The selector string passed to clickWithRedirect is missing a closing
parenthesis causing an incomplete button text match; update the call to
clickWithRedirect (in par.spec.ts) to use the full button label "Login
(Redirect)" so it matches the actual button text (consistent with the usage on
line 16) and ensures the selector finds the correct element.
- Line 37: The button selector uses an unterminated regex (/Login \(Background/)
which is inconsistent with the full button text used elsewhere (e.g., 'Login
(Journey)'); update the selector in the call to page.getByRole('button', { name:
... }) to match the complete label — either supply the exact string "Login
(Background)" or a properly escaped/closed regex like /Login \(Background\)/ so
it only targets the intended button.

In `@packages/oidc-client/src/lib/authorize.request.ts`:
- Around line 83-87: The current log.debug call is emitting the raw
authorization payload (data / data.authorizeResponse) which may contain
sensitive fields like code and state; update the logging inside the authorize
response handling (where variables data and data.authorizeResponse are used) to
remove any payload contents and instead log only metadata (e.g., "Received
success response" plus non-sensitive context such as endpoint path, request id,
or status) and do the same for the second occurrence later in the file (the
block around the other log.debug at lines ~139-143) so no authorization payload
fields are ever logged.

In `@packages/oidc-client/src/lib/authorize.request.utils.ts`:
- Around line 157-170: The toAuthorizationError helper currently only checks for
the presence of error and then casts the object to AuthorizationError, which can
yield missing error_description or type; update toAuthorizationError to validate
that data is a non-null object and that the properties error (string),
error_description (string), and type (string) all exist and have correct types
before casting to AuthorizationError (use the Record<string, unknown> shape
check already present as basis); if any of those fields are missing or wrong
type, return the canonical fallback AuthorizationError with error:
'Unknown_Error', error_description: 'Unexpected error response shape', and type:
'unknown_error' so downstream code never sees partial/undefined fields.
- Around line 200-225: generate a single normalized request-level overrides
object (e.g., requestOverrides) that merges config defaults (clientId,
redirectUri, scope, responseType) with the per-call options, then pass that same
requestOverrides into generateAndStoreAuthUrlValues(...) and into
buildAuthorizeParams(...) instead of re-reading config values; specifically,
stop re-setting redirectUri/ scope/responseType from config when building the
PAR body (in the block using authUrlOptions, createChallenge, and
buildAuthorizeParams) and use requestOverrides for those fields so the stored
authUrlValues and the pushed PAR body cannot diverge.

In `@packages/oidc-client/src/lib/client.store.test.ts`:
- Around line 289-603: Tests are missing coverage for error branches in
dispatchAuthorizeµ; add unit tests in client.store.test.ts that trigger and
assert each error-path: (1) simulate the PAR endpoint returning a
CONFIGURATION_ERROR-shaped response and assert dispatchAuthorizeµ returns/passes
through a configuration_error result, (2) simulate non-configuration failure
shapes so createAuthorizeErrorµ is used (e.g., server returns a 400 with
standard OAuth error JSON) and assert the resulting error type
(network_error/argument_error as appropriate), and (3) feed malformed/unexpected
RTK error shapes from the PAR endpoint and assert the fallback error handling
path is exercised; use the existing test helpers (server.use/http.post/http.get
and OIDC client via oidc({ config: ..., storage: ... })) and target
dispatchAuthorizeµ/createAuthorizeErrorµ behavior by calling authorize.url() or
authorize.background() and asserting the returned error objects' types and
payloads.

In `@packages/oidc-client/src/lib/oidc.api.ts`:
- Around line 152-163: The current check "if (!response.data || !('request_uri'
in response.data))" can throw when response.data is a non-object (e.g.,
string/number); update the guard to ensure response.data is an object (e.g.,
typeof response.data === 'object' && response.data !== null) before testing for
the 'request_uri' property so malformed PAR responses return the existing
PAR_ERROR object; locate and change the conditional around
response.data/request_uri in the function that handles the PAR response
(references: response.data and 'request_uri') to perform this type/object check
and keep the same error return path when the guard fails.

---

Nitpick comments:
In `@e2e/oidc-app/src/par/main.ts`:
- Around line 59-61: The current check in main.ts using submitJson (if
(!submitJson.tokenId && !submitJson.successUrl)) misses alternate error shapes;
update the validation around submitJson (the PAR response handling) to treat any
response that lacks tokenId and lacks successUrl as an error and also detect
common error shapes like presence of a numeric code or a message string (e.g.,
submitJson.code, submitJson.message) — throw an Error that includes
submitJson.message when present otherwise include a safe serialization of
submitJson (JSON.stringify(submitJson)) so callers get meaningful diagnostics;
ensure this change is applied where submitJson is handled in the PAR response
block.
- Around line 45-48: The loop over initJson.callbacks in main.ts blindly mutates
callback objects and can throw if callbacks is missing or items lack expected
shape; update the code that iterates initJson.callbacks to first verify
initJson.callbacks is an array and for each cb confirm cb.type is defined and
cb.input is an array with at least one element before setting cb.input[0].value,
and skip or log a warning for entries that don’t match expected "NameCallback" /
"PasswordCallback" shapes so the login flow fails gracefully instead of raising
a runtime error.

In `@e2e/oidc-suites/src/par.spec.ts`:
- Line 13: The function loginJourney is missing a TypeScript type for the page
parameter; add an explicit Playwright Page type by updating the signature to
accept page: Page and ensure you import Page from your Playwright test package
(e.g. import { Page } from '@playwright/test' or 'playwright' if not already
imported), then update the function declaration loginJourney(page: Page,
username: string, password: string) accordingly.

In `@packages/oidc-client/src/lib/authorize.request.utils.test.ts`:
- Around line 109-224: Add a PAR regression test that verifies request-level
overrides are propagated into the PAR POST body: create a test that calls
parAuthorizeµ with par: true and passes overrides (e.g., scope: 'openid
profile', redirectUri: 'https://app/callback', responseType: 'code') and stub
sessionStorage as other tests do; spy on sdkOidc.buildAuthorizeParams or inspect
the first argument passed to mockStore.dispatch to assert the PAR body includes
those overridden fields (scope, redirect_uri, response_type) instead of the
values from the base config, and keep existing assertions about the returned
slim URL.
🪄 Autofix (Beta)

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

Run ID: 382a985d-e9cd-4735-b948-7172731959aa

📥 Commits

Reviewing files that changed from the base of the PR and between 207e275 and e7383f6.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (26)
  • .changeset/some-shirts-joke.md
  • e2e/am-mock-api/src/app/constants.js
  • e2e/am-mock-api/src/app/responses.js
  • e2e/am-mock-api/src/app/routes.auth.js
  • e2e/oidc-app/src/index.html
  • e2e/oidc-app/src/par/index.html
  • e2e/oidc-app/src/par/main.ts
  • e2e/oidc-app/src/utils/oidc-app.ts
  • e2e/oidc-app/vite.config.ts
  • e2e/oidc-suites/src/par.spec.ts
  • packages/oidc-client/api-report/oidc-client.api.md
  • packages/oidc-client/api-report/oidc-client.types.api.md
  • packages/oidc-client/package.json
  • packages/oidc-client/src/lib/authorize.request.ts
  • packages/oidc-client/src/lib/authorize.request.utils.test.ts
  • packages/oidc-client/src/lib/authorize.request.utils.ts
  • packages/oidc-client/src/lib/client.store.test.ts
  • packages/oidc-client/src/lib/client.store.ts
  • packages/oidc-client/src/lib/config.types.ts
  • packages/oidc-client/src/lib/oidc.api.ts
  • packages/oidc-client/src/lib/par.types.ts
  • packages/oidc-client/src/types.ts
  • packages/oidc-client/tsconfig.lib.json
  • packages/sdk-effects/oidc/src/lib/authorize.effects.ts
  • packages/sdk-effects/oidc/src/lib/authorize.test.ts
  • packages/sdk-effects/sdk-request-middleware/src/lib/request-mware.derived.ts

Comment thread e2e/oidc-suites/src/par.spec.ts Outdated
Comment thread e2e/oidc-suites/src/par.spec.ts Outdated
Comment thread packages/oidc-client/src/lib/authorize.request.ts Outdated
Comment thread packages/oidc-client/src/lib/authorize.request.utils.ts
Comment thread packages/oidc-client/src/lib/authorize.request.utils.ts Outdated
Comment thread packages/oidc-client/src/lib/client.store.test.ts
Comment thread packages/oidc-client/src/lib/oidc.api.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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/oidc-client/src/lib/authorize.request.utils.test.ts`:
- Around line 56-59: The afterEach hook currently calls vi.resetAllMocks(),
which only resets mocks but does not restore spied original implementations
(e.g., the spy created with vi.spyOn(sdkOidc, 'buildAuthorizeParams')); replace
vi.resetAllMocks() with vi.restoreAllMocks() in the afterEach block so all spies
and mocked implementations are restored to their originals while keeping
vi.unstubAllGlobals() as-is.
🪄 Autofix (Beta)

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

Run ID: 7be9d2af-1669-4699-91c5-aa8c866fc957

📥 Commits

Reviewing files that changed from the base of the PR and between e7383f6 and 2b25bc8.

📒 Files selected for processing (7)
  • e2e/oidc-suites/src/login.spec.ts
  • packages/davinci-client/api-report/davinci-client.api.md
  • packages/davinci-client/api-report/davinci-client.types.api.md
  • packages/oidc-client/src/lib/authorize.request.ts
  • packages/oidc-client/src/lib/authorize.request.utils.test.ts
  • packages/oidc-client/src/lib/authorize.request.utils.ts
  • packages/oidc-client/src/lib/client.store.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/oidc-client/src/lib/authorize.request.ts
  • packages/oidc-client/src/lib/client.store.ts

Comment thread packages/oidc-client/src/lib/authorize.request.utils.test.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
packages/oidc-client/src/lib/authorize.request.ts (1)

50-60: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Logging the raw authorize success payload still leaks code/state.

result here is the resolved AuthorizationSuccess returned from dispatchAuthorizeFetch (data.authorizeResponse) or dispatchAuthorizeIframe (data) — both carry the authorization code, state, and related artifacts. The earlier reviewed call sites were refactored into this helper, but the same payload-in-debug-log pattern was reintroduced on both branches. Log metadata only.

🛡️ Proposed fix
   if (options.responseMode === 'pi.flow') {
     const { responseMode: _, ...redirectOptions } = options;
     return dispatchAuthorizeFetch(store, url, wellknown, redirectOptions).pipe(
-      Micro.tap((result) => log.debug('Received success response', result)),
+      Micro.tap(() => log.debug('Received success response from authorize endpoint (pi.flow)')),
     );
   }

   return dispatchAuthorizeIframe(store, url, wellknown, options).pipe(
-    Micro.tap((result) => log.debug('Received success response', result)),
+    Micro.tap(() => log.debug('Received success response from authorize endpoint (iframe)')),
   );
🤖 Prompt for 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.

In `@packages/oidc-client/src/lib/authorize.request.ts` around lines 50 - 60, The
debug taps currently log the full AuthorizationSuccess payload (which contains
sensitive fields like code and state) in the Micro.tap callbacks; change those
log.debug calls inside the branch that calls dispatchAuthorizeFetch(...) and the
branch that calls dispatchAuthorizeIframe(...) to log only non-sensitive
metadata (e.g., event type, method used, timestamps, or success status) rather
than the raw result object — update the Micro.tap((result) =>
log.debug('Received success response', result)) invocations to pass a metadata
object or formatted message that excludes result.code/result.state while
preserving context for debugging.
🧹 Nitpick comments (1)
packages/oidc-client/src/lib/authorize.request.micros.test.ts (1)

337-339: 💤 Low value

Consider simplifying the mock return type cast.

The double cast as unknown as ReturnType<typeof mockStore.dispatch> works but is complex. Consider defining an explicit type for the mock return value to improve clarity, though the current approach is acceptable for test code.

♻️ Optional refactoring approach

Define a helper type for the dispatch result:

type MockDispatchResult<T> = Promise<{ data?: T; error?: unknown }>;

Then use it in the mock:

vi.mocked(mockStore.dispatch).mockResolvedValueOnce({
  data: { authorizeResponse },
} as MockDispatchResult<{ authorizeResponse: typeof authorizeResponse }>);

However, given that this is test code and the current pattern is common for mocking Redux Toolkit types, the existing approach is acceptable.

Also applies to: 355-357

🤖 Prompt for 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.

In `@packages/oidc-client/src/lib/authorize.request.micros.test.ts` around lines
337 - 339, Replace the double cast on the mock return value for
vi.mocked(mockStore.dispatch).mockResolvedValueOnce by introducing a small
explicit helper type (e.g., MockDispatchResult<T> = Promise<{ data?: T; error?:
unknown }>) and use it to type the resolved value for the authorizeResponse
mocks; update both occurrences that currently use "as unknown as
ReturnType<typeof mockStore.dispatch>" so the mock call reads like
mockResolvedValueOnce({...} as MockDispatchResult<{ authorizeResponse: typeof
authorizeResponse }>) referencing mockStore.dispatch and the authorizeResponse
variable.
🤖 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 `@e2e/oidc-app/src/par/index.html`:
- Around line 1-5: Add standard meta tags for character encoding and responsive
viewport inside the existing <head> element (before or after the <title>) in the
HTML file: include a meta charset="utf-8" and a meta name="viewport"
content="width=device-width, initial-scale=1". Update the head block that
currently contains the <title> to insert those two meta tags so the page uses
UTF-8 encoding and proper mobile scaling.

In `@packages/oidc-client/src/lib/authorize.request.ts`:
- Around line 78-84: The current Micro.fail call when parEndpoint is missing
uses a sentence for the error field; change it to a machine-readable
SCREAMING_SNAKE code (e.g., PAR_ENDPOINT_NOT_CONFIGURED) so it matches other PAR
errors; modify the Micro.fail invocation in authorize.request.ts where
parEndpoint is checked (the block that currently returns Micro.fail({ error:
'PAR endpoint not configured', ... })) to use the new constant-style error
string for error while keeping the existing error_description and type fields
unchanged.

In `@packages/oidc-client/src/lib/authorize.request.utils.ts`:
- Around line 200-217: The validateParResponse function currently maps any
result.error to toAuthorizationError passing undefined when
isFetchBaseQueryError(result.error) is false, which drops SerializedError
diagnostics; update validateParResponse to mirror
handleDispatchError/toDispatchError behavior: detect if result.error is a
FetchBaseQueryError and convert via toAuthorizationError, otherwise convert the
SerializedError (preserving code/message/name) using toDispatchError (or the
existing toDispatchError helper) before returning Micro.fail; keep the existing
PAR missing-field Micro.fail branch and return Micro.succeed(result.data)
unchanged.

---

Duplicate comments:
In `@packages/oidc-client/src/lib/authorize.request.ts`:
- Around line 50-60: The debug taps currently log the full AuthorizationSuccess
payload (which contains sensitive fields like code and state) in the Micro.tap
callbacks; change those log.debug calls inside the branch that calls
dispatchAuthorizeFetch(...) and the branch that calls
dispatchAuthorizeIframe(...) to log only non-sensitive metadata (e.g., event
type, method used, timestamps, or success status) rather than the raw result
object — update the Micro.tap((result) => log.debug('Received success response',
result)) invocations to pass a metadata object or formatted message that
excludes result.code/result.state while preserving context for debugging.

---

Nitpick comments:
In `@packages/oidc-client/src/lib/authorize.request.micros.test.ts`:
- Around line 337-339: Replace the double cast on the mock return value for
vi.mocked(mockStore.dispatch).mockResolvedValueOnce by introducing a small
explicit helper type (e.g., MockDispatchResult<T> = Promise<{ data?: T; error?:
unknown }>) and use it to type the resolved value for the authorizeResponse
mocks; update both occurrences that currently use "as unknown as
ReturnType<typeof mockStore.dispatch>" so the mock call reads like
mockResolvedValueOnce({...} as MockDispatchResult<{ authorizeResponse: typeof
authorizeResponse }>) referencing mockStore.dispatch and the authorizeResponse
variable.
🪄 Autofix (Beta)

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

Run ID: 578574e5-b6ca-43a5-847b-b6bdd13b3d05

📥 Commits

Reviewing files that changed from the base of the PR and between 2b25bc8 and e81b87e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (34)
  • .changeset/some-shirts-joke.md
  • e2e/am-mock-api/src/app/constants.js
  • e2e/am-mock-api/src/app/responses.js
  • e2e/am-mock-api/src/app/routes.auth.js
  • e2e/oidc-app/src/index.html
  • e2e/oidc-app/src/par/index.html
  • e2e/oidc-app/src/par/main.ts
  • e2e/oidc-app/src/utils/oidc-app.ts
  • e2e/oidc-app/vite.config.ts
  • e2e/oidc-suites/src/login.spec.ts
  • e2e/oidc-suites/src/par.spec.ts
  • packages/davinci-client/api-report/davinci-client.api.md
  • packages/davinci-client/api-report/davinci-client.types.api.md
  • packages/oidc-client/api-report/oidc-client.api.md
  • packages/oidc-client/api-report/oidc-client.types.api.md
  • packages/oidc-client/package.json
  • packages/oidc-client/src/lib/authorize.request.effects.ts
  • packages/oidc-client/src/lib/authorize.request.micros.test.ts
  • packages/oidc-client/src/lib/authorize.request.micros.ts
  • packages/oidc-client/src/lib/authorize.request.ts
  • packages/oidc-client/src/lib/authorize.request.utils.test.ts
  • packages/oidc-client/src/lib/authorize.request.utils.ts
  • packages/oidc-client/src/lib/client.store.test.ts
  • packages/oidc-client/src/lib/client.store.ts
  • packages/oidc-client/src/lib/config.types.ts
  • packages/oidc-client/src/lib/oidc.api.ts
  • packages/oidc-client/src/lib/par.types.ts
  • packages/oidc-client/src/types.ts
  • packages/oidc-client/tsconfig.lib.json
  • packages/sdk-effects/oidc/src/index.ts
  • packages/sdk-effects/oidc/src/lib/authorize.effects.ts
  • packages/sdk-effects/oidc/src/lib/authorize.test.ts
  • packages/sdk-effects/oidc/src/lib/authorize.utils.ts
  • packages/sdk-effects/sdk-request-middleware/src/lib/request-mware.derived.ts
✅ Files skipped from review due to trivial changes (6)
  • e2e/oidc-app/vite.config.ts
  • packages/oidc-client/src/types.ts
  • packages/oidc-client/src/lib/par.types.ts
  • e2e/oidc-app/src/index.html
  • .changeset/some-shirts-joke.md
  • e2e/oidc-suites/src/login.spec.ts
🚧 Files skipped from review as they are similar to previous changes (16)
  • packages/sdk-effects/sdk-request-middleware/src/lib/request-mware.derived.ts
  • packages/oidc-client/src/lib/config.types.ts
  • packages/oidc-client/tsconfig.lib.json
  • e2e/am-mock-api/src/app/responses.js
  • packages/oidc-client/api-report/oidc-client.types.api.md
  • packages/oidc-client/src/lib/oidc.api.ts
  • packages/sdk-effects/oidc/src/lib/authorize.test.ts
  • packages/oidc-client/src/lib/client.store.test.ts
  • e2e/am-mock-api/src/app/routes.auth.js
  • e2e/oidc-app/src/utils/oidc-app.ts
  • e2e/oidc-app/src/par/main.ts
  • packages/oidc-client/api-report/oidc-client.api.md
  • e2e/oidc-suites/src/par.spec.ts
  • packages/oidc-client/package.json
  • packages/oidc-client/src/lib/client.store.ts
  • packages/oidc-client/src/lib/authorize.request.utils.test.ts

Comment thread e2e/oidc-app/src/par/index.html
Comment thread packages/oidc-client/src/lib/authorize.request.ts
Comment thread packages/oidc-client/src/lib/authorize.request.utils.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
packages/oidc-client/src/lib/authorize.request.utils.test.ts (1)

67-70: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Restore spies instead of resetting them in test cleanup.

On Line 69, vi.resetAllMocks() does not restore original implementations for vi.spyOn(...), which can leak altered behavior across tests. Use vi.restoreAllMocks() in this hook.

Proposed fix
 afterEach(() => {
   vi.unstubAllGlobals();
-  vi.resetAllMocks();
+  vi.restoreAllMocks();
 });
🤖 Prompt for 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.

In `@packages/oidc-client/src/lib/authorize.request.utils.test.ts` around lines 67
- 70, The test cleanup currently calls vi.resetAllMocks() which does not restore
original implementations for spies created with vi.spyOn; in the afterEach hook
replace vi.resetAllMocks() with vi.restoreAllMocks() so that spies are properly
restored while keeping vi.unstubAllGlobals() intact; update the afterEach
closure (the one containing vi.unstubAllGlobals() and vi.resetAllMocks()) to
call vi.restoreAllMocks() instead of vi.resetAllMocks() to prevent spy leakage
across tests.
🧹 Nitpick comments (1)
e2e/oidc-suites/src/par.spec.ts (1)

63-66: ⚡ Quick win

Assert no-redirect behavior explicitly in the PAR 400 test.

The test name promises "without redirecting", but current checks only assert the error UI. Add a URL assertion to lock that contract.

Proposed test assertion update
     // The SDK should surface an error in the UI instead of redirecting away
+    await expect(page).not.toHaveURL(/\/am\/XUI\//);
+    await expect(page).toHaveURL(/\/par\/(?:\?.*)?$/);
     await expect(page.locator('.error')).toBeVisible({ timeout: 10000 });
     await expect(page.locator('.error')).toContainText('PAR_ERROR');
🤖 Prompt for 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.

In `@e2e/oidc-suites/src/par.spec.ts` around lines 63 - 66, The test currently
checks only the error UI (page.locator('.error')) but doesn't assert the
"no-redirect" promise; capture the page URL before the action that triggers PAR
and after the error appears and assert they are identical to ensure there was no
navigation. Specifically, in par.spec.ts around the PAR 400 test, record the URL
via page.url() (or use expect(page).toHaveURL(...) semantics) before invoking
the flow that produces the PAR error, then after the existing checks (await
expect(page.locator('.error')).toBeVisible... and toContainText('PAR_ERROR'))
add an assertion that the current URL equals the captured URL to lock the
no-redirect contract.
🤖 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.

Duplicate comments:
In `@packages/oidc-client/src/lib/authorize.request.utils.test.ts`:
- Around line 67-70: The test cleanup currently calls vi.resetAllMocks() which
does not restore original implementations for spies created with vi.spyOn; in
the afterEach hook replace vi.resetAllMocks() with vi.restoreAllMocks() so that
spies are properly restored while keeping vi.unstubAllGlobals() intact; update
the afterEach closure (the one containing vi.unstubAllGlobals() and
vi.resetAllMocks()) to call vi.restoreAllMocks() instead of vi.resetAllMocks()
to prevent spy leakage across tests.

---

Nitpick comments:
In `@e2e/oidc-suites/src/par.spec.ts`:
- Around line 63-66: The test currently checks only the error UI
(page.locator('.error')) but doesn't assert the "no-redirect" promise; capture
the page URL before the action that triggers PAR and after the error appears and
assert they are identical to ensure there was no navigation. Specifically, in
par.spec.ts around the PAR 400 test, record the URL via page.url() (or use
expect(page).toHaveURL(...) semantics) before invoking the flow that produces
the PAR error, then after the existing checks (await
expect(page.locator('.error')).toBeVisible... and toContainText('PAR_ERROR'))
add an assertion that the current URL equals the captured URL to lock the
no-redirect contract.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ad87a678-4a47-4351-bd39-8c7c811ce636

📥 Commits

Reviewing files that changed from the base of the PR and between e81b87e and a3bcb7a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (34)
  • .changeset/some-shirts-joke.md
  • e2e/am-mock-api/src/app/constants.js
  • e2e/am-mock-api/src/app/responses.js
  • e2e/am-mock-api/src/app/routes.auth.js
  • e2e/oidc-app/src/index.html
  • e2e/oidc-app/src/par/index.html
  • e2e/oidc-app/src/par/main.ts
  • e2e/oidc-app/src/utils/oidc-app.ts
  • e2e/oidc-app/vite.config.ts
  • e2e/oidc-suites/src/login.spec.ts
  • e2e/oidc-suites/src/par.spec.ts
  • packages/davinci-client/api-report/davinci-client.api.md
  • packages/davinci-client/api-report/davinci-client.types.api.md
  • packages/oidc-client/api-report/oidc-client.api.md
  • packages/oidc-client/api-report/oidc-client.types.api.md
  • packages/oidc-client/package.json
  • packages/oidc-client/src/lib/authorize.request.effects.ts
  • packages/oidc-client/src/lib/authorize.request.micros.test.ts
  • packages/oidc-client/src/lib/authorize.request.micros.ts
  • packages/oidc-client/src/lib/authorize.request.ts
  • packages/oidc-client/src/lib/authorize.request.utils.test.ts
  • packages/oidc-client/src/lib/authorize.request.utils.ts
  • packages/oidc-client/src/lib/client.store.test.ts
  • packages/oidc-client/src/lib/client.store.ts
  • packages/oidc-client/src/lib/config.types.ts
  • packages/oidc-client/src/lib/oidc.api.ts
  • packages/oidc-client/src/lib/par.types.ts
  • packages/oidc-client/src/types.ts
  • packages/oidc-client/tsconfig.lib.json
  • packages/sdk-effects/oidc/src/index.ts
  • packages/sdk-effects/oidc/src/lib/authorize.effects.ts
  • packages/sdk-effects/oidc/src/lib/authorize.test.ts
  • packages/sdk-effects/oidc/src/lib/authorize.utils.ts
  • packages/sdk-effects/sdk-request-middleware/src/lib/request-mware.derived.ts
✅ Files skipped from review due to trivial changes (5)
  • packages/oidc-client/tsconfig.lib.json
  • e2e/oidc-suites/src/login.spec.ts
  • packages/oidc-client/package.json
  • packages/oidc-client/api-report/oidc-client.api.md
  • .changeset/some-shirts-joke.md
🚧 Files skipped from review as they are similar to previous changes (21)
  • e2e/oidc-app/vite.config.ts
  • e2e/am-mock-api/src/app/responses.js
  • packages/oidc-client/src/types.ts
  • packages/oidc-client/src/lib/par.types.ts
  • packages/oidc-client/src/lib/config.types.ts
  • e2e/oidc-app/src/index.html
  • e2e/oidc-app/src/utils/oidc-app.ts
  • e2e/am-mock-api/src/app/routes.auth.js
  • packages/oidc-client/src/lib/oidc.api.ts
  • e2e/oidc-app/src/par/index.html
  • packages/sdk-effects/oidc/src/lib/authorize.test.ts
  • packages/sdk-effects/oidc/src/lib/authorize.utils.ts
  • e2e/am-mock-api/src/app/constants.js
  • packages/oidc-client/src/lib/authorize.request.ts
  • packages/oidc-client/src/lib/authorize.request.effects.ts
  • packages/oidc-client/api-report/oidc-client.types.api.md
  • packages/oidc-client/src/lib/authorize.request.micros.test.ts
  • e2e/oidc-app/src/par/main.ts
  • packages/oidc-client/src/lib/authorize.request.micros.ts
  • packages/oidc-client/src/lib/authorize.request.utils.ts
  • packages/oidc-client/src/lib/client.store.ts

Implements RFC 9126 PAR flow: client POSTs authorization parameters to
the server's pushed_authorization_request_endpoint, receives a
request_uri, and uses only that in the redirect — keeping sensitive
parameters out of browser history and server logs.

- New parAuthorizeµ pipeline: builds PAR body, dispatches POST,
  validates response, stores PKCE state, builds slim authorize URL
- authorizeµ selects PAR vs standard flow via config.par or
  wellknown.require_pushed_authorization_requests
- New par.types.ts, authorize.request.micros.ts,
  authorize.request.effects.ts layer split
- PAR endpoint added to oidc.api.ts (RTK Query mutation)
- e2e suite and app added (e2e/oidc-app/src/par/, oidc-suites/par.spec.ts)
Copy link
Copy Markdown
Collaborator

@cerebrl cerebrl left a comment

Choose a reason for hiding this comment

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

I'm still going through it, but I thought I'd provide what I have so far.


const response = await initQuery(request, 'par')
.applyMiddleware(requestMiddleware)
.applyQuery(async (req: FetchArgs) => await baseQuery(req));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we get a debug log printing out the raw response? I want to have one for the request just before we use initQuery, and one for the response right after, before we have any logic.

};
}

logger.debug('OIDC PAR API response', response);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ah, can we just move this up?

wellknown: WellknownResponse,
options?: OptionalAuthorizeOptions,
): Micro.Micro<ReturnType<typeof generateAndStoreAuthUrlValues>, AuthorizationError, never> =>
Micro.try({
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It took me an embarrassing long time to realize this Micro was being returned, so it was a bit confusing for me. I then noticed the missing braces. Anyway, maybe I'm a boomer, so take this with a grain of salt, but for larger function bodies, I really prefer the use of braces and a return statement.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

How do you feel about merging .micro.ts with .effect.ts? Let's just say get rid of the Effect Micro-Pattern, and replace it with "Micro" Micro-Pattern. Micros can be both effectful and non-effectful. So, for internal patterns, it would look like this:

  1. Store: factory function that returns public API
  2. API: network orchestration and request-response mgmt
  3. Reducers/Slices: state transformation/transition
  4. Micro: functions that return a Micro (optionally effectful; non-network effects)
  5. Utilities: pure, stateless functions
  6. Types: interfaces and types

The Effect Macro-Pattern will still be a thing, but let's swap out Micro for Effect at the Micro level since there's really not a difference, and we can expose Micro internally, just not externally.

Comment on lines +120 to +124
/**
* Background authorization flow. Uses PAR when the server mandates it
* (`require_pushed_authorization_requests`) or `config.par` is set; otherwise
* builds a full authorize URL and dispatches via iframe or pi.flow fetch.
*/
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why did we remove the detailed JSDoc comment? Are we no longer generating API docs from these comments?

} as const;
},
): Micro.Micro<never, AuthorizationError, never> =>
Micro.tryPromise({
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Okay, I see what you're saying in the other thread we have. So, my vision is that Micro, the pattern and library, can use Utilities, but Utilities can't use Micro.

With that said, let's remove the use of Micro, or move these functions to the micro.ts file.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Plus, if a function returns a Micro, it needs to communicate that with the use of the µ symbol.

challenge: string,
state: string,
prompt?: PromptValue,
): Micro.Micro<URLSearchParams, AuthorizationError, never> =>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's just create a clear delineation with a Utility from a Micro, so let's have the rule that if Micro is used, it's a Micro.

@ryanbas21 ryanbas21 force-pushed the par branch 2 times, most recently from f6de759 to 2f3564a Compare May 20, 2026 19:35
…ror handling

- Fix: spurious await on Micro value in client.store authorize path
- Fix: validateParResponse uses toDispatchError for SerializedError,
  preserving diagnostic info instead of silently dropping it
- Fix: optional chaining on wellknown?.require_pushed_authorization_requests
  in authorizeµ default param (prevents synchronous throw outside Micro)
- Fix: scope PAR dispatch tapError inside flatMap to prevent double-logging
  with misleading "Error dispatching PAR authorize request" message
- Fix: dispatchAuthorizeIframe validates code+state shape before succeeding
- Fix: add credentials: include to PAR endpoint FetchArgs for SSO support
- Fix: correct misleading log in authorizeIframe error path
- Feat: surface expires_in from PAR response; warn when TTL < 30s
- Test: add PAR 400 error e2e scenario to mock server and par.spec.ts
- Chore: remove console.log debug artifacts from client.store.test.ts

fix(oidc-app): add charset and viewport meta tags to PAR demo page
fix(oidc-suites): tighten PAR button selectors with anchored regex
fix(oidc-client): use PAR_NOT_CONFIGURED error code for missing PAR endpoint
fix(oidc-client): redact authorization payload from authorize success debug logs
docs(oidc-client): restore JSDoc on authorizeµ and parAuthorizeµ
fix(oidc-client): guard PAR response shape before reading request_uri
fix(oidc-client): bracket PAR queryFn with raw request and raw response debug logs
test(oidc-client): use vi.restoreAllMocks so spyOn originals are restored between tests
test(oidc-client): cover dispatchAuthorizeµ error branches via authorize.background()
refactor(oidc-client): merge effects.ts into micros.ts and µ-suffix all Micro exports

Consolidate authorize.request.effects.ts and existing micros into a single
file. Every function returning Micro is now µ-suffixed and uses braces +
explicit return for clarity.

refactor(oidc-client): move Micro helpers into micros.ts; utils.ts holds only pure utilities

Establish the convention: any function returning a Micro lives in
authorize.request.micros.ts and ends in µ. authorize.request.utils.ts now
contains only pure stateless utilities (type guards, error converters, URL
builders) with no dependency on the Effect library.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants