Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions javascript/reactjs-todo-davinci/.env.example
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
WELLKNOWN_URL=
WEB_OAUTH_CLIENT=
API_URL=http://localhost:9443
DEBUGGER_OFF=true
DEVELOPMENT=true
PORT=8443
SCOPE="openid profile email phone name revoke"

# INIT_PROTECT (optional) - bootstrap | flow
# 'bootstrap' will initialize protect at app bootstrap time
# 'flow' relies on the PingOne Protect collector for initialization
INIT_PROTECT=
# PINGONE_ENV_ID - required when ProtectCollector is present
PINGONE_ENV_ID=

# SDK configuration (clientId, discoveryEndpoint, scopes, redirectUri) is no
# longer sourced from environment variables. Copy config.example.json to
# config.json and fill in your values.
1 change: 1 addition & 0 deletions javascript/reactjs-todo-davinci/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules/
config.json
/test-results/
/playwright-report/
/blob-report/
Expand Down
28 changes: 22 additions & 6 deletions javascript/reactjs-todo-davinci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,36 @@ Once you have the requirements above met, we can build the project.

1. DaVinci Policies: Select your DaVinci application

### Configure Your `.env` File
### Configure SDK Credentials

Copy `config.example.json` to `config.json` at the app root and fill in your values:

```sh
cp config.example.json config.json
```

`config.json` (gitignored):

```json
{
"oidc": {
"clientId": "<your-oauth-client-id>",
"discoveryEndpoint": "https://<your-domain>/.well-known/openid-configuration",
"scopes": ["openid", "profile", "email"],
"redirectUri": "https://localhost:8443/callback.html"
}
Comment on lines +65 to +70

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix redirect URI protocol mismatch in setup instructions.

Line 69 shows https://localhost:8443/callback.html, but the same README config/setup path uses http://localhost:8443/callback.html (Line 41). Align these to one value to avoid misconfiguration during onboarding.

🤖 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 `@javascript/reactjs-todo-davinci/README.md` around lines 65 - 70, The
README.md file contains an inconsistency in the redirect URI configuration
examples, showing https://localhost:8443/callback.html in one location and
http://localhost:8443/callback.html in another. Update the redirect URI in the
OIDC configuration example to use the same protocol (http or https) consistently
throughout the entire README file to prevent configuration errors during user
onboarding.

}
```

Change the name of `.env.example` to `.env` and replace the dummy values (e.g. `$CLIENT_ID`) with your values.
### Configure Your `.env` File

Example with annotations:
Change the name of `.env.example` to `.env` and set the remaining runtime values:

```text
WELLKNOWN_URL=<<PingOne wellknown url>>
WEB_OAUTH_CLIENT=<<PingOne application client id>>
API_URL=http://localhost:9443
DEBUGGER_OFF=true
DEVELOPMENT=true
PORT=8443
SCOPE="openid profile email phone name revoke"
```

### Installing Dependencies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

import { davinci } from '@forgerock/davinci-client';
import { makeDavinciConfig } from '@forgerock/sdk-utilities';
import { CONFIG } from '../../../constants.js';

/**
Expand All @@ -17,7 +18,7 @@ import { CONFIG } from '../../../constants.js';
*/
export default async function createClient() {
try {
const davinciClient = await davinci({ config: CONFIG });
const davinciClient = await davinci({ config: makeDavinciConfig(CONFIG) });
return davinciClient;
} catch (error) {
console.error('Error creating DaVinci client');
Expand Down
40 changes: 19 additions & 21 deletions javascript/reactjs-todo-davinci/client/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,30 @@
* of the MIT license. See the LICENSE file for details.
*/

/** ***************************************************************************
* SDK INTEGRATION POINT
* Summary: Configure the DaVinci client
* ----------------------------------------------------------------------------
* Details: CONFIG uses the unified SDK configuration schema. Pass it to
* `makeDavinciConfig(CONFIG)` from `@forgerock/sdk-utilities` before calling
* the factory — e.g. `davinci({ config: makeDavinciConfig(CONFIG) })`.
*
* Local dev: copy config.example.json → config.json and fill in your values.
* E2e / CI: set SDK_CONFIG to a JSON string (e.g. from config.test.json).
*************************************************************************** */
import sdkConfigJson from '../config.json';
export const API_URL = process.env.API_URL;
// Yes, the debugger boolean is intentionally reversed
export const DEBUGGER = process.env.DEBUGGER_OFF === 'false';
export const WEB_OAUTH_CLIENT = process.env.WEB_OAUTH_CLIENT;
export const SCOPE = process.env.SCOPE;
export const WELLKNOWN_URL = process.env.WELLKNOWN_URL;
export const INIT_PROTECT = process.env.INIT_PROTECT;
export const PINGONE_ENV_ID = process.env.PINGONE_ENV_ID;
/** ***************************************************************************
* SDK INTEGRATION POINT
* Summary: Configure the OIDC client
* ----------------------------------------------------------------------------
* Details: The config object below is passed to the `oidc()` initializer in
* `oidc.context.js` to configure the OIDC client:
* - clientId: the OAuth 2.0 client ID registered in PingOne
* - redirectUri: the URI of this app to which the OAuth 2.0 flow redirects
* after authentication (points to callback.html for the redirect handler)
* - scope: the OAuth 2.0 scopes requested from PingOne
* - serverConfig.wellknown: the OpenID Connect discovery URL for your
* PingOne environment, used to resolve authorization/token endpoints
*************************************************************************** */

const rawConfig = process.env.SDK_CONFIG ? JSON.parse(process.env.SDK_CONFIG) : sdkConfigJson;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard SDK_CONFIG parsing to prevent startup-time crashes.

Line 29 parses process.env.SDK_CONFIG without error handling; malformed JSON will throw during module load and hard-fail app initialization.

Proposed fix
-import sdkConfigJson from '../config.json';
+import sdkConfigJson from '../config.json';
@@
-const rawConfig = process.env.SDK_CONFIG ? JSON.parse(process.env.SDK_CONFIG) : sdkConfigJson;
+const rawConfig = (() => {
+  if (!process.env.SDK_CONFIG) return sdkConfigJson;
+  try {
+    return JSON.parse(process.env.SDK_CONFIG);
+  } catch (error) {
+    throw new Error(`Invalid SDK_CONFIG JSON: ${error.message}`);
+  }
+})();
🤖 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 `@javascript/reactjs-todo-davinci/client/constants.js` at line 29, The
rawConfig constant assignment does not handle errors when parsing
process.env.SDK_CONFIG, which will cause the entire module to fail loading if
the JSON is malformed. Wrap the JSON.parse call in a try-catch block, and if
parsing throws an error, fall back to using sdkConfigJson as the default value.
This ensures the application can still initialize even when SDK_CONFIG contains
invalid JSON.


export const CONFIG = {
clientId: WEB_OAUTH_CLIENT,
redirectUri: `${window.location.origin}/callback.html`,
scope: SCOPE,
serverConfig: {
wellknown: WELLKNOWN_URL,
...rawConfig,
oidc: {
...rawConfig.oidc,
redirectUri: `${window.location.origin}/callback.html`,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import { useState, createContext, useEffect } from 'react';
import { oidc } from '@forgerock/oidc-client';
import { makeOidcConfig } from '@forgerock/sdk-utilities';
import { DEBUGGER } from '../constants';

const email = window.sessionStorage.getItem('sdk_email');
Expand All @@ -19,7 +20,7 @@ const username = window.sessionStorage.getItem('sdk_username');
* @function useInitOidcState - A custom hook to get initial OIDC state for managing user authentication
* @returns {Array} - OIDC client, state values and state methods
*/
export function useInitOidcState(config) {
export function useInitOidcState(json) {
/**
* Create state properties for "global" OIDC state.
* The destructing of the hook's array results in index 0 having the state values,
Expand All @@ -44,7 +45,7 @@ export function useInitOidcState(config) {
* but it can be done outside of the React component for better performance.
************************************************************************* */
if (DEBUGGER) debugger;
let client = await oidc({ config });
let client = await oidc({ config: makeOidcConfig(json) });
if ('error' in client) {
console.error(`Error initializing OIDC client: ${client.error}`);
client = null;
Expand Down
7 changes: 7 additions & 0 deletions javascript/reactjs-todo-davinci/config.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"oidc": {
"clientId": "<your-oauth-client-id>",
"discoveryEndpoint": "https://<your-domain>/.well-known/openid-configuration",
"scopes": ["openid", "profile", "email"]
}
}
8 changes: 8 additions & 0 deletions javascript/reactjs-todo-davinci/config.test.fido.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"oidc": {
"clientId": "20dd0ed0-bb9b-4c8f-9a60-9ebeb4b348e0",
"discoveryEndpoint": "https://auth.pingone.ca/02fb4743-189a-4bc7-9d6c-a919edfe6447/as/.well-known/openid-configuration",
"scopes": ["openid", "profile", "email", "phone", "name", "revoke"],
"redirectUri": "http://localhost:5829/callback.html"
}
}
8 changes: 8 additions & 0 deletions javascript/reactjs-todo-davinci/config.test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"oidc": {
"clientId": "724ec718-c41c-4d51-98b0-84a583f450f9",
"discoveryEndpoint": "https://auth.pingone.ca/02fb4743-189a-4bc7-9d6c-a919edfe6447/as/.well-known/openid-configuration",
"scopes": ["openid", "profile", "email", "phone", "name", "revoke"],
"redirectUri": "http://localhost:8443/callback.html"
}
}
1 change: 1 addition & 0 deletions javascript/reactjs-todo-davinci/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"dependencies": {
"@forgerock/davinci-client": "latest",
"@forgerock/oidc-client": "latest",
"@forgerock/sdk-utilities": "latest",
"@forgerock/protect": "latest",
"cookie-parser": "^1.4.5",
"cors": "^2.8.5",
Expand Down
12 changes: 4 additions & 8 deletions javascript/reactjs-todo-davinci/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { defineConfig, devices } from '@playwright/test';
import testConfig from './config.test.json';
import testFidoConfig from './config.test.fido.json';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove or use testFidoConfig to fix the lint error.

testFidoConfig is currently unused because the only reference is inside commented code, which triggers no-unused-vars.

💡 Suggested fix
 import { defineConfig, devices } from '`@playwright/test`';
 import testConfig from './config.test.json';
-import testFidoConfig from './config.test.fido.json';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import testFidoConfig from './config.test.fido.json';
import { defineConfig, devices } from '`@playwright/test`';
import testConfig from './config.test.json';
🧰 Tools
🪛 ESLint

[error] 3-3: 'testFidoConfig' is defined but never used.

(no-unused-vars)

🤖 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 `@javascript/reactjs-todo-davinci/playwright.config.ts` at line 3, The import
statement for testFidoConfig is triggering a no-unused-vars lint error because
the variable is only referenced in commented code and not actively used. Either
remove the import statement for testFidoConfig entirely if it is not needed, or
uncomment and properly integrate the code that uses testFidoConfig so the
variable is actively referenced in the configuration.

Source: Linters/SAST tools


const url = process.env.PLAYWRIGHT_TEST_BASE_URL || 'http://localhost:8443';

Expand Down Expand Up @@ -27,11 +29,8 @@ export default defineConfig({
DEBUGGER_OFF: 'true',
DEVELOPMENT: 'false',
PORT: '8443',
WEB_OAUTH_CLIENT: '724ec718-c41c-4d51-98b0-84a583f450f9',
SCOPE: 'openid profile email phone name revoke',
WELLKNOWN_URL:
'https://auth.pingone.ca/02fb4743-189a-4bc7-9d6c-a919edfe6447/as/.well-known/openid-configuration',
PINGONE_ENV_ID: '02fb4743-189a-4bc7-9d6c-a919edfe6447',
SDK_CONFIG: JSON.stringify(testConfig),
},
ignoreHTTPSErrors: true,
},
Expand Down Expand Up @@ -61,10 +60,7 @@ export default defineConfig({
// DEBUGGER_OFF: 'true',
// DEVELOPMENT: 'false',
// PORT: '5829',
// WEB_OAUTH_CLIENT: '20dd0ed0-bb9b-4c8f-9a60-9ebeb4b348e0',
// SCOPE: 'openid profile email phone name revoke',
// WELLKNOWN_URL:
// 'https://auth.pingone.ca/02fb4743-189a-4bc7-9d6c-a919edfe6447/as/.well-known/openid-configuration',
// SDK_CONFIG: JSON.stringify(testFidoConfig),
// },
// ignoreHTTPSErrors: true,
// },
Expand Down
14 changes: 8 additions & 6 deletions javascript/reactjs-todo-davinci/webpack.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const dotenv = require('dotenv');
const fs = require('fs');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');
Expand All @@ -12,10 +13,8 @@ module.exports = () => {
const API_URL = process.env.API_URL || localEnv.API_URL;
const DEBUGGER_OFF = process.env.DEBUGGER_OFF || localEnv.DEBUGGER_OFF;
const DEVELOPMENT = process.env.DEVELOPMENT || localEnv.DEVELOPMENT;
const WEB_OAUTH_CLIENT = process.env.WEB_OAUTH_CLIENT || localEnv.WEB_OAUTH_CLIENT;
const SCOPE = process.env.SCOPE || localEnv.SCOPE;
const WELLKNOWN_URL = process.env.WELLKNOWN_URL || localEnv.WELLKNOWN_URL;
const INIT_PROTECT = process.env.INIT_PROTECT || localEnv.INIT_PROTECT;
const SDK_CONFIG = process.env.SDK_CONFIG || null;
const PINGONE_ENV_ID = process.env.PINGONE_ENV_ID || localEnv.PINGONE_ENV_ID;

return {
Expand Down Expand Up @@ -101,15 +100,18 @@ module.exports = () => {
},
plugins: [
new MiniCssExtractPlugin(),
new webpack.NormalModuleReplacementPlugin(/config\.json$/, (resource) => {
if (!fs.existsSync(path.resolve(__dirname, 'config.json'))) {
resource.request = resource.request.replace('config.json', 'config.example.json');
}
}),
new webpack.DefinePlugin({
// Inject all the environment variable into the Webpack build
'process.env.API_URL': JSON.stringify(API_URL),
'process.env.DEBUGGER_OFF': JSON.stringify(DEBUGGER_OFF),
'process.env.WEB_OAUTH_CLIENT': JSON.stringify(WEB_OAUTH_CLIENT),
'process.env.SCOPE': JSON.stringify(SCOPE),
'process.env.WELLKNOWN_URL': JSON.stringify(WELLKNOWN_URL),
'process.env.INIT_PROTECT': JSON.stringify(INIT_PROTECT),
'process.env.PINGONE_ENV_ID': JSON.stringify(PINGONE_ENV_ID),
'process.env.SDK_CONFIG': JSON.stringify(SDK_CONFIG),
}),
],
};
Expand Down
11 changes: 6 additions & 5 deletions javascript/reactjs-todo-journey/.env.example
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
VITE_WELLKNOWN_URL=
VITE_WEB_OAUTH_CLIENT=
VITE_API_URL=http://localhost:9443
VITE_PORT=8443
VITE_DEBUGGER_OFF=true
VITE_DEVELOPMENT=true
VITE_SCOPE='openid profile email'
VITE_JOURNEY_LOGIN=Login
VITE_JOURNEY_REGISTER=Registration

# VITE_INIT_PROTECT (optional) - bootstrap | journey
# 'bootstrap' will initialize protect at app bootstrap time
# 'journey' relies on the PingOneProtectEvaluationCallback for initialization
VITE_INIT_PROTECT=
VITE_INIT_PROTECT=

# VITE_PINGONE_ENV_ID - required if VITE_INIT_PROTECT is set
VITE_PINGONE_ENV_ID=
VITE_PINGONE_ENV_ID=

# SDK configuration (clientId, discoveryEndpoint, scopes, redirectUri) is no
# longer sourced from environment variables. Copy config.example.json to
# config.json and fill in your values.
1 change: 1 addition & 0 deletions javascript/reactjs-todo-journey/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules/
config.json
build/
/test-results/
/playwright-report/
Expand Down
29 changes: 22 additions & 7 deletions javascript/reactjs-todo-journey/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,38 @@ Once you have the 5 requirements above met, we can build the project.
WebAuthn type steps for registration and authentication are also supported


### Configure Your `.env` File
### Configure SDK Credentials

Copy `config.example.json` to `config.json` at the app root and fill in your values:

```sh
cp config.example.json config.json
```

`config.json` (gitignored):

```json
{
"oidc": {
"clientId": "<your-oauth-client-id>",
"discoveryEndpoint": "https://<your-domain>/.well-known/openid-configuration",
"scopes": ["openid", "profile", "email"],
"redirectUri": "https://localhost:8443/callback.html"
}
}
```

Change the name of `.env.example` to `.env` and fill the environment variables with your values.
### Configure Your `.env` File

Example with annotations:
Change the name of `.env.example` to `.env` and set the remaining runtime values:

```text
VITE_WELLKNOWN_URL=<<<Wellknown URL to your AM instance>>>
VITE_WEB_OAUTH_CLIENT=<<<Your Web OAuth client name/ID>>>
VITE_API_URL=http://localhost:9443
VITE_PORT=8443
VITE_DEBUGGER_OFF=true
VITE_DEVELOPMENT=true
VITE_SCOPE='openid profile email'
VITE_JOURNEY_LOGIN=Login
VITE_JOURNEY_REGISTER=Registration
VITE_REALM_PATH=<<<Realm path of AM>>>
```

### Installing Dependencies and Run Build
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CONFIG, DEBUGGER } from '../../constants.js';
import { htmlDecode } from '../../utilities/decode.js';
import { OidcContext } from '../../context/oidc.context.js';
import { callbackType, journey } from '@forgerock/journey-client';
import { makeJourneyConfig } from '@forgerock/sdk-utilities';

/**
* @function isGenericError - Helper function to determine if a step is a GenericError
Expand Down Expand Up @@ -69,7 +70,7 @@ export default function useJourney({ formMetadata, resumeUrl }) {
********************************************************************* */
if (DEBUGGER) debugger;
try {
const client = await journey({ config: CONFIG });
const client = await journey({ config: makeJourneyConfig(CONFIG) });
setJourneyClient(client);

if (resumeUrl) {
Expand Down Expand Up @@ -253,7 +254,11 @@ export default function useJourney({ formMetadata, resumeUrl }) {
const previousCallbacks = prev?.callbacks;
const previousPayload = prev?.payload;

if (stepCount.current === 1 && newStep.type === 'Step' && newStep.getStage() === previousStage) {
if (
stepCount.current === 1 &&
newStep.type === 'Step' &&
newStep.getStage() === previousStage
) {
newStep.callbacks = previousCallbacks;
newStep.payload = {
...previousPayload,
Expand Down Expand Up @@ -286,12 +291,7 @@ export default function useJourney({ formMetadata, resumeUrl }) {
if (submissionStep && journeyClient) {
setStep(submissionStep);
}
}, [
formMetadata.tree,
submissionStep,
journeyClient,
authorize,
]);
}, [formMetadata.tree, submissionStep, journeyClient, authorize]);

/**
* @function redirect - Redirects the user to the specified URL in the step
Expand Down
Loading
Loading