Skip to content

Conversation

cerebrl
Copy link
Collaborator

@cerebrl cerebrl commented Jul 17, 2025

JIRA Ticket

SDKS-4050

Description

This implements the token exchange capability to the OIDC Client.

Yes, changeset included

Copy link

nx-cloud bot commented Jul 17, 2025

View your CI Pipeline Execution ↗ for commit beb349a

Command Status Duration Result
nx run-many -t build ✅ Succeeded 35s View ↗
nx affected -t build typecheck lint test e2e-ci ✅ Succeeded 1m View ↗
nx-cloud record -- nx format:check ✅ Succeeded 1s View ↗

☁️ Nx Cloud last updated this comment at 2025-07-27 19:15:49 UTC

Copy link

changeset-bot bot commented Jul 18, 2025

🦋 Changeset detected

Latest commit: beb349a

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

This PR includes changesets to release 9 packages
Name Type
@forgerock/iframe-manager Minor
@forgerock/storage Minor
@forgerock/sdk-oidc Minor
@forgerock/davinci-client Minor
@forgerock/oidc-client Minor
@forgerock/sdk-types Minor
@forgerock/sdk-utilities Minor
@forgerock/sdk-logger Minor
@forgerock/sdk-request-middleware 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

@cerebrl cerebrl changed the base branch from main to justin_oidc-mods July 18, 2025 19:40
Comment on lines 3 to 17
export interface TokenExchangeResponse {
access_token: string;
id_token?: string;
refresh_token?: string;
expires_in?: number;
scope?: string;
token_type?: string;
}

export interface TokenRequestOptions {
code: string;
config: OidcConfig;
endpoint: string;
verifier?: string;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should these interfaces be in exchange.types.ts?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, you're right. I'll do that now.

Comment on lines +37 to +40
if ('status' in error) {
message = 'error' in error ? error.error : JSON.stringify(error.data);
} else if ('message' in error) {
message = error.message;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

We do something similar in device client to narrow the RTK error type. Eventually we should probably create some sort of error utility that handles this that can be used by any package.

storeType: CustomStorageObject | 'localStorage' | 'sessionStorage';
type: 'custom' | 'localStorage' | 'sessionStorage';
prefix?: string;
name: string;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just curious if there was a challenge you came across that resulted in the addition of the name property on storage. Does it really need to be required?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No challenge per se, but the arguments seemed a bit odd when split out like they were. I just moved the additional parameters into this single config object so that now there's only one parameter. There requirements of each remain the same.

@cerebrl cerebrl force-pushed the justin_oidc-mods branch from f35d74a to 3cf2822 Compare July 23, 2025 19:11
@cerebrl cerebrl force-pushed the justin_oidc-mods branch from 3cf2822 to 249d35d Compare July 23, 2025 22:08
@cerebrl cerebrl force-pushed the token-exchange branch 3 times, most recently from 46a9e28 to c8fa674 Compare July 23, 2025 22:51
@cerebrl cerebrl force-pushed the justin_oidc-mods branch from 249d35d to e615b24 Compare July 23, 2025 22:59
return buildAuthorizeOptionsµ(wellknown, config, options).pipe(
Micro.flatMap(([url, config, options]) => createAuthorizeUrlµ(url, config, options)),
Micro.tap((url) => log.debug('Authorize URL created', url)),
Micro.tapError((url) => Micro.sync(() => log.error('Error creating authorize URL', url))),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is sync really necessary here to log an error? We don't use sync in the line above when we tap and log.debug

Copy link
Collaborator

Choose a reason for hiding this comment

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

No need to change it but just wanted to comment

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, this is an unfortunate requirement of tapError. It's different than tap, which is admittedly odd. Here's the API docs, but it's not super clear.

}) {
const log = loggerFn({ level: logger?.level || 'error', custom: logger?.custom });
const storageClient = createStorage({
storeType: 'localStorage',
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should be type instead of storeType

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure if you are agreeing or disagreeing with me here :) I think we are in agreement that storeType got changed to type in the StorageConfig interface. I'm saying line 44 should be changed to type: 'localStorage' to align with the new interface.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Lol, sorry. I misread your comment. I will definitely change this.


export interface StorageConfig {
storeType: CustomStorageObject | 'localStorage' | 'sessionStorage';
type: 'custom' | 'localStorage' | 'sessionStorage';
Copy link
Collaborator

Choose a reason for hiding this comment

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

We don't actually do anything with this custom store type in createStorage. It may be better to change the checks for custom storage to be something like:

if (storeType === 'custom') {
   if (!custom) {
      throw new Error(store type is custom but no custom storage was provided)
      }
      ...
}

That way if the store type is 'custom' but no custom storage was provided then we warn instead of potentially defaulting to storing in local storage which may not be what the customer intended.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hmm, this is a good point. Let me rework the types and logic here.

const result = await Micro.runPromiseExit(
await authorizeµ(wellknown, config, log, options),
Copy link
Collaborator

Choose a reason for hiding this comment

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

authorizeµ already does a runPromiseExit when it returns. Do we need to runPromiseExit again here when it's called?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

authorizeµ no longer returns the result of .runPromiseExit. We are now doing it in this top level function. This goes with the idea of running "side effects at the edge", which we can discuss at a later time.

@@ -0,0 +1,3 @@
export interface TokenExchangeOptions {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Missing copyright. But also, can we just move this into exhange.types.ts. It seems to be used in both exchange.utils.ts and client.store.ts

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Ah, this is actually not needed. I'll push an update that just removes this completely.

@cerebrl cerebrl changed the title Token exchange feat(oidc-client): implement token exchange Jul 24, 2025
@cerebrl cerebrl force-pushed the justin_oidc-mods branch from e615b24 to 375d0ca Compare July 24, 2025 20:50
Base automatically changed from justin_oidc-mods to main July 24, 2025 21:00
ryanbas21 and others added 3 commits July 24, 2025 17:46
introduce the oidc-client with the authorize api. authoirize handles the
calling of authorize routes based on the well-known config.

when a p1 env is detected, it will use a post request
otherwise, a background request is done via a hidden iframe
@cerebrl cerebrl force-pushed the token-exchange branch 2 times, most recently from 6ac1d25 to ff690cd Compare July 24, 2025 23:19
@cerebrl cerebrl force-pushed the token-exchange branch 2 times, most recently from ad6b0d1 to 80d8678 Compare July 24, 2025 23:25
@codecov-commenter
Copy link

codecov-commenter commented Jul 24, 2025

Codecov Report

❌ Patch coverage is 0% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.44%. Comparing base (26c6983) to head (beb349a).

Files with missing lines Patch % Lines
packages/davinci-client/src/lib/client.store.ts 0.00% 4 Missing ⚠️

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

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #348   +/-   ##
=======================================
  Coverage   60.44%   60.44%           
=======================================
  Files          33       33           
  Lines        2045     2045           
  Branches      292      292           
=======================================
  Hits         1236     1236           
  Misses        809      809           
Files with missing lines Coverage Δ
packages/davinci-client/src/lib/client.store.ts 0.37% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

github-actions bot commented Jul 24, 2025

Deployed 6e23c2f to https://ForgeRock.github.io/ping-javascript-sdk/pr-348/6e23c2fe491db3fd3fd018616121c29775465106 branch gh-pages in ForgeRock/ping-javascript-sdk

Copy link
Contributor

github-actions bot commented Jul 24, 2025

📦 Bundle Size Analysis

📦 Bundle Size Analysis

🚨 Significant Changes

🔺 @forgerock/storage - 1.4 KB (+0.1 KB, +7.5%)
🔺 @forgerock/oidc-client - 12.2 KB (+11.0 KB, +921.9%)

📊 Minor Changes

📈 @forgerock/davinci-client - 34.3 KB (+0.0 KB)
📈 @forgerock/sdk-oidc - 3.5 KB (+0.1 KB)
📉 @forgerock/iframe-manager - 2.4 KB (-0.0 KB)

➖ No Changes

@pingidentity/protect - 108.4 KB
@forgerock/device-client - 9.2 KB
@forgerock/sdk-types - 5.6 KB
@forgerock/sdk-utilities - 4.0 KB
@forgerock/sdk-request-middleware - 4.2 KB
@forgerock/sdk-logger - 1.6 KB


11 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

@cerebrl cerebrl merged commit e192523 into main Jul 28, 2025
4 checks passed
@ryanbas21 ryanbas21 mentioned this pull request Jul 24, 2025
cerebrl added a commit that referenced this pull request Jul 29, 2025
feat(oidc-client): implement token exchange
cerebrl added a commit that referenced this pull request Jul 30, 2025
feat(oidc-client): implement token exchange
cerebrl added a commit that referenced this pull request Jul 30, 2025
feat(oidc-client): implement token exchange
cerebrl added a commit that referenced this pull request Jul 30, 2025
feat(oidc-client): implement token exchange
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.

4 participants