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
55,945 changes: 36,225 additions & 19,720 deletions javascript/package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions javascript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,22 @@
"./central-login-oidc-client/",
"./embedded-login/",
"./reactjs-todo/",
"./react-journey/",
"./reactjs-todo-davinci/",
"./todo-api/"
],
"scripts": {
"todo-api": "npm start --workspace todo-api",
"angular-todo": "npm start --workspace angular-todo",
"reactjs-todo": "npm start --workspace reactjs-todo",
"react-journey": "npm start --workspace react-journey",
"reactjs-todo-dv": "npm start --workspace reactjs-todo-davinci",
"start:central-login-oidc": "npm start --workspace central-login-oidc",
"start:central-login-oidc-client": "npm start --workspace central-login-oidc-client",
"start:embedded-login": "npm start --workspace embedded-login",
"start:angular-todo": "npm-run-all --parallel todo-api angular-todo",
"start:reactjs-todo": "npm-run-all --parallel todo-api reactjs-todo",
"start:react-journey": "npm-run-all --parallel todo-api react-journey",
"start:reactjs-todo-dv": "npm-run-all --parallel todo-api reactjs-todo-dv",
"lint": "npm run lint --workspaces --if-present",
"prepare": "husky install",
Expand Down
20 changes: 20 additions & 0 deletions javascript/react-journey/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# APP_URL - not using this for preview-environment instead, we can use window.location.origin
SERVER_URL=
WELLKNOWN_URL=
SCOPE=
API_URL=
DEBUGGER_OFF=true
DEVELOPMENT=
JOURNEY_LOGIN=
JOURNEY_REGISTER=
PORT=8443
REALM_PATH=
WEB_OAUTH_CLIENT=
CENTRALIZED_LOGIN=false

# INIT_PROTECT - a boolean which if true will initialize protect at app bootstrap time,
# otherwise relies on the PingOneProtectInitialize callback for initialization
INIT_PROTECT=

# PINGONE_ENV_ID - required if INIT_PROTECT is true
PINGONE_ENV_ID=
39 changes: 39 additions & 0 deletions javascript/react-journey/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module.exports = {
env: {
browser: true,
es2021: true,
},
ignorePatterns: [
'**/node_modules/**',
'**/dist/**',
'public',
'playwright-report',
'test-results',
],
extends: ['standard', 'plugin:react/recommended', 'prettier'],
overrides: [
{
env: {
node: true,
},
files: ['.eslintrc.{js,cjs}'],
parserOptions: {
sourceType: 'script',
},
},
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['react'],
settings: {
react: {
version: 'detect',
},
},
rules: {
'react/prop-types': 'off',
'no-debugger': 'off',
},
};
6 changes: 6 additions & 0 deletions javascript/react-journey/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules/
build/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
139 changes: 139 additions & 0 deletions javascript/react-journey/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# React JS Journey Sample App

## Disclaimers

This sample code is provided "as is" and is not a supported product of Ping. It's purpose is solely to demonstrate how the Ping JavaScript SDK can be implemented within a React application. Also, this is not a demonstration of React itself or instructional for _how_ to build a React app. There are many aspects to routing, state management, tooling and other aspects to building a React app that are outside of the scope of this project. For information about creating a React app, [visit React's official documentation](https://reactjs.org/docs/create-a-new-react-app.html).

## Requirements

1. An instance of Ping's Access Manager (AM), either within a Ping's Advanced Identity Cloud tenant, your own private installation or locally installed on your computer
2. Node >= 18.12.0 (recommended: install via [official package installer](https://nodejs.org/en/))
3. Knowledge of using the Terminal/Command Line
4. Ability to generate security certs (recommended: mkcert ([installation instructions here](https://github.com/FiloSottile/mkcert#installation)))
5. This project "cloned" to your computer

## Setup

Once you have the 5 requirements above met, we can build the project.

### Setup Your AM Instance

#### Configure CORS

1. Allowed origins: `https://localhost:8443`
2. Allowed methods: `GET` `POST`
3. Allowed headers: `Content-Type` `X-Requested-With` `X-Requested-Platform` `Accept-API-Version` `Authorization`
4. Allow credentials: enable

#### Create Your OAuth Clients

1. Create a public (SPA) OAuth client for the web app: no secret, scopes of `openid profile email`, implicit consent enabled, and no "token authentication endpoint method".
2. Create a confidential (Node.js) OAuth client for the API server: with a secret, default scope of `am-introspect-all-tokens`, and `client_secret_basic` as the "token authentication endpoint method".

#### Create your Authentication Journeys/Trees

1. Login
2. Register

**Note**: The sample app currently supports the following callbacks only:

- NameCallback
- PasswordCallback
- ChoiceCallback
- ValidatedCreateUsernameCallback
- ValidatedCreatePasswordCallback
- StringAttributeInputCallback
- BooleanAttributeInputCallback
- KbaCreateCallback
- TermsAndConditionsCallback
- TextOutputCallback
- ConfirmationCallback
- SelectIdPCallback
- RedirectCallback
- PingOneProtectInitializeCallback
- PingOneProtectEvaluationCallback

WebAuthn type steps for registration and authentication are also supported


### Configure Your `.env` File

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

Example with annotations:

```text
WELLKNOWN_URL=<<<Wellknown URL to your AM instance>>>
APP_URL=https://localhost:8443 # in develop we do not use this variable for dynamic deployment reasons
API_URL=http://localhost:9443
DEBUGGER_OFF=false
JOURNEY_LOGIN=Login
JOURNEY_REGISTER=Registration
REALM_PATH=<<<Realm path of AM>>>
WEB_OAUTH_CLIENT=<<<Your Web OAuth client name/ID>>>
SCOPE='openid profile email'
```

### Installing Dependencies and Run Build

**Run from `/javascript` root**: Since this sample app uses npm's workspaces, we recommend running the npm commands from the root of the `/javascript` folder.

```sh
# Install all dependencies (no need to pass the -w option)
npm install
```

### Run the Servers

Now, run the below command to start the processes needed for building the application and running the servers for both client and API server:

```sh
# In one terminal window, run the following command from the root of the /javascript folder
npm run start:react-journey
```

Now, you should be able to visit `https://localhost:8443`, which is your web app or client (the Relying Party in OAuth terms). This client will make requests to your AM instance, (the Authorization Server in OAuth terms), which will be running on whatever domain you set, and `http://localhost:9443` as the REST API for your todos (the Resource Server).

### Accept Cert Exceptions

You will likely have to accept the security certificate exceptions for both your React app and the Node.js server. To accept the cert form the Node.js server, you can visit `http://localhost:9443/healthcheck` in your browser. Once you receive "OK", your Node.js server is running on the correct domain and port, and the cert is accepted.

## Learn About Integration Touchpoints

This project has a debugging statements that can be activated which causes the app to pause execution at each SDK integration point. It will have a comment above the `debugger` statement explaining the purpose of the integration.

If you'd like to use this feature as a learning tool, open the developer tools of your browser and rerun the app locally. It will automatically pause at these points of integration.

For local development, if you want to turn these debuggers off, you can set the environment variable of `DEBUGGER_OFF` to true.

## Modifying This Project

### React Client

To modify the client portion of this project, you'll need to be familiar with the following React patterns:

1. [Functional components and composition](https://reactjs.org/docs/components-and-props.html)
2. [Hooks (including custom hooks)](https://reactjs.org/docs/hooks-intro.html)
3. [Context API](https://reactjs.org/docs/hooks-reference.html#usecontext)
4. [React Router](https://reactrouter.com/)

You'll also want a [basic understanding of Webpack](https://webpack.js.org/concepts/) and the following:

1. [Babel transformation for React](https://webpack.js.org/loaders/babel-loader/#root)
2. [Plugins for Sass-to-CSS processing](https://webpack.js.org/loaders/sass-loader/#root)

#### Styling and CSS

We heavily leveraged [Twitter Bootstrap](https://getbootstrap.com/) and [it's utility classes](https://getbootstrap.com/docs/5.0/utilities/api/), but you will see classes with the prefix `cstm_`. These are custom classes, hence the `cstm` shorthand, and they are explicitly used to denote an additional style application on top of Bootstrap's styling.

### REST API Server

To modify the API server, you'll need a [basic understanding of Node](https://nodejs.org/en/about/) as well as the following things:

1. [Express](https://expressjs.com/)
2. [PouchDB](https://pouchdb.com/)
3. [Superagent](https://www.npmjs.com/package/superagent)

## TypeScript?

The Ping JavaScript SDK is developed with TypeScript, so type definitions are available. This sample application does not utilize TypeScript, but if you'd like to see a version of this written in TypeScript, let us know.
3 changes: 3 additions & 0 deletions javascript/react-journey/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
presets: ['@babel/preset-react'],
};
3 changes: 3 additions & 0 deletions javascript/react-journey/client/components/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Components

These are React based units of code that could potentially be used anywhere, to an extent. They are the units that compose a view. These could be actual React components or custom React hooks.
33 changes: 33 additions & 0 deletions javascript/react-journey/client/components/icons/account-icon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* ping-sample-web-react-journey
*
* account-icon.js
*
* Copyright (c) 2026 Ping Identity Ping Identity Corporation. All rights reserved.
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/

import React from 'react';

/**
* @function AccountIcon - React component for the user icon representing the account
* @param {Object} props - React props object
* @param {string} props.classes - A string of classnames to be set on component
* @param {string} props.size - A string representing the intended size of the rendering
* @returns {Object} - React JSX Object
*/
export default function AccountIcon({ classes = '', size = '24px' }) {
return (
<svg
className={classes}
height={size}
width={size}
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M0 0h24v24H0z" fill="none" />
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z" />
</svg>
);
}
33 changes: 33 additions & 0 deletions javascript/react-journey/client/components/icons/action-icon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* ping-sample-web-react-journey
*
* action-icon.js
*
* Copyright (c) 2026 Ping Identity Ping Identity Corporation. All rights reserved.
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/

import React from 'react';

/**
* @function ActionIcon - React component that displays the action, "three dots" icon representing the a menu
* @param {Object} props - React props object
* @param {string} props.classes - A string of classnames to be set on component
* @param {string} props.size - A string representing the intended size of the rendering
* @returns {Object} - React JSX Object
*/
export default function ActionIcon({ classes = '', size = '24px' }) {
return (
<svg
className={classes}
height={size}
width={size}
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M0 0h24v24H0z" fill="none" />
<path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
</svg>
);
}
33 changes: 33 additions & 0 deletions javascript/react-journey/client/components/icons/alert-icon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* ping-sample-web-react-journey
*
* alert-icon.js
*
* Copyright (c) 2026 Ping Identity Ping Identity Corporation. All rights reserved.
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/

import React from 'react';

/**
* @function AlertIcon - React component that displays the alert icon representing the a warning
* @param {Object} props - React props object
* @param {string} props.classes - A string of classnames to be set on component
* @param {string} props.size - A string representing the intended size of the rendering
* @returns {Object} - React JSX Object
*/
export default function AlertIcon({ classes = '', size = '24px' }) {
return (
<svg
className={classes}
height={size}
width={size}
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M0 0h24v24H0z" fill="none" />
<path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" />
</svg>
);
}
40 changes: 40 additions & 0 deletions javascript/react-journey/client/components/icons/apple-icon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* ping-sample-web-react-journey
*
* apple-icon.js
*
* Copyright (c) 2026 Ping Identity Ping Identity Corporation. All rights reserved.
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/

import React from 'react';

/**
* @function AppleIcon - React component for the user icon representing the apple icon
* @param {Object} props - React props object
* @param {string} props.classes - A string of classnames to be set on component
* @param {string} props.size - A string representing the intended size of the rendering
* @returns {Object} - React JSX Object
*/
export default function AppleIcon({ classes = '', size = '24px' }) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
className={classes}
height={size}
width={size}
viewBox="0 0 256 256"
>
<g fill="#070000" strokeMiterlimit="10" style={{ mixBlendMode: 'normal' }}>
<path d="M0 256V0h256v256z"></path>
</g>
<path
fill="#fff"
strokeMiterlimit="10"
d="M32.5 44c-1.778 0-3.001-.577-4.08-1.086C27.38 42.424 26.481 42 25 42c-1.481 0-2.38.424-3.42.914C20.501 43.423 19.278 44 17.5 44 13.174 44 6 34.071 6 23.5 6 16.49 10.832 11 17 11c2.027 0 3.259.581 4.346 1.093C22.378 12.58 23.27 13 25 13s2.622-.42 3.654-.907C29.741 11.581 30.973 11 33 11c2.664 0 5.033.982 7.042 2.921a1.5 1.5 0 01-.288 2.376C37.438 17.644 36 20.499 36 23.75c0 3.661 2.004 6.809 4.986 7.831.391.134.709.423.879.799.171.375.18.805.023 1.188C39.461 39.515 35.424 44 32.5 44zm-7-34a1.499 1.499 0 01-1.494-1.637c.012-.123.303-3.045 2.593-5.382C28.753.781 30.85.127 31.081.059a1.5 1.5 0 011.904 1.652c-.034.241-.389 2.436-2.232 4.899-1.973 2.636-4.791 3.322-4.91 3.35-.114.027-.229.04-.343.04z"
transform="scale(5.33333)"
></path>
</svg>
);
}
Loading
Loading