Uses sample app found here: https://github.com/pingidentity/pingone-customers-sample-custom-signon.git
This is a small React sample that shows how to use of OAuth2 authentication inside your react applications.
It handles OAuth 2.0 implicit flow by default, where the access token is returned immediately without an extra authorization code exchange step.
But you can check the other flows here as well. In particular, the authorization grants like authorization_code or client_credentials, where your application will call the /{environmentId}/as/token endpoint to acquire the access token.
It has a simple component that generates the necessary link to send your users to the correct location, and perform the authorization process once the user is back on the application. If successful, the "Show user information" link will be present on the page that will trigger to retrieve the OAuth 2.0 protected resource (from UserInfo Endpoint) about the authenticated end user.
You will need the following things:
- PingOne for Customers Account - If you don’t have an existing one, you can drop the it after register.
- A PingOne application, configured for Single-Page App (SPA) or Native mode. Also make sure that it is enabled plus redirect, sign off URL's and access grants by scopes are properly set.
- Specify custom login page URL for the application in SIGNON URL textbox of P14C admin console.
-
Clone source code
git clone git@github.com:pingidentity/pingone-customers-sample-custom-signon.git . -
Update config.js with your application's data extracted from P14C admin console:
environment_id: Required. Your application's Environment ID. You can find this value at your Application's Settings under Configuration tab from the admin console( extractxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxstring that specifies the environment 128-bit universally unique identifier (UUID) right fromhttps://auth.pingone .com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/as/authorizeAUTHORIZATION URL ). Or from the Settings main menu (ENVIRONMENT ID variable)client_id: Required. Your application's client UUID. You can also find this value at Application's Settings right under the Application name.clientSecret: A string that specifies the the application’s client secret. This property is required if your application is not a public client. Plus make sure to set it if the following the application’stokenEndpointAuthMethodproperty is set toCLIENT_SECRET_POST.responseType: A string that specifies the code or token type returned by an authorization request. Options aretoken,id_token, andcode. The value MUST be thecodefor requesting an authorization code flow,id_token tokenfor the implicit flow, orcode id_tokenfor hybrid flow (a scenario when you can have a long lived session in your application and get tokens back immediately from the authorization endpoint). For more variants please check Definitions of Multiple-Valued Response Type Combinations topic.grantType: A string that specifies the grant type of the token request. Options areauthorization_code,implicit(is set by default), andclient_credentials. Forauthorization_codeorclient_credentialsgrant types please follow this rules:responseType=codeandclientSecretis necessary.redirectUri: Required. The URL to which the PingOne will redirect the user's browser after authorization has been granted by the user. REDIRECT URLS values corresponds to this data. The Access and ID Token will be available in the hash fragment of this URL. For simplicity this sample has it hardcoded ashttp://localhost:3000/callback, where/callbackis handled by callback react componentlogoutRedirectUri: The URL to which the browser is redirected after a logout has been performed. SIGNOFF URLS values corresponds to this data.scope: A string that specifies permissions that determine the resources that the application can access. This parameter is not required, but it is needed to specify accessible resources.tokenEndpointAuthMethod: A string that specifies the client authentication methods supported by the token endpoint. This is a required property. Options arenone,client_secret_basic, andclient_secret_post.
-
Build a project by
npm installoryarn install -
Start an application by
npm startoryarn start
The following table shows the relationships between the application type attribute and the default grantTypes, response_type, and tokenEndpointAuthMethod attributes.
| Application type | Grant type | Response type | Token endpoint authentication method |
|---|---|---|---|
| Non-interactive | client_credentials | token | client_secret_basic |
| Native | authorization_code, implicit | token, id_token, code | none |
| Web | authorization_code | code | client_secret_basic |
| Single-page | implicit | token, id_token | none |
| Endpoint | Description |
|---|---|
POST /{environmentId}/as/authorize prompt=login parameter is used by default |
Authorization request with a code or implicit grant type. |
POST /{environmentId}/as/token |
Obtain an access token in authorization grant case |
GET /{environmentID}/as/signoff?id_token_hint={idToken} if post_logout_redirect_uri parameter is provided and it does not match one of the postLogoutRedirectUri values of your application in the specified environment - it would be handled as an unpredictable error. |
Obtain an access token in authorization grant case |
Note: For any application type (except non-interactive), you can specify either none, client_secret_basic, or client_secret_post as the tokenEndpointAuthMethod attribute value. Non-interactive applications use the client_credentials grant type, which does not support a tokenEndpointAuthMethod value of none.
This project was bootstrapped with Create React App. This means you don’t need to install or configure tools like Webpack or Babel, since they are preconfigured and hidden so that you can focus on the code.
- In case you want to experience more OIDC and other PingOne for Customers Management APIs without enforcing CORS, you can open another instance of chrome with disabled security (without closing other running chrome instances): on Mac terminal:
open -n -a "Google Chrome" --args --user-data-dir=/tmp/temp_chrome_user_data_dir http://localhost:3000/ --disable-web-securityOtherwise you will see such error like "No 'Access-Control-Allow-Origin' header is present on the requested resource" on some actions.
componentDidMountis only called once in the lifecycle of any component, re-render will not reinitialize the component.componentDidUpdatewill be called where you can manage your logic.- Sample doesn't use a sophisticated persistent layer for OAuth2 tokens, thereby a browser
session storagewas used as a cache (so you don't loose them once the browser tab is closed or refreshed).
sessionStorage is similar to localStorage; the only difference is while data stored inlocalStoragehas no expiration time, data stored insessionStoragegets cleared when the page session ends. A page session lasts for as long as the browser is open and survives over page reloads and restores. If you are implementingauthorization_codeorclient_credentialsgrant types or looking for more advanced local storage solutions, you can checkout store.js, cross-storage or similar solutions. - For the development server port 8080 is used, that is specified in package.json
“start”script as follows:"start": “PORT=8080 react-scripts start", - If you are using Redux and want to keep tokens after browser tab refresh, than you can persist redux state to the local storage by using a simple redux subscriber to store auth tokens in the browser localStorage. Would be nice to check the Access Token Handling (Automatic Refresh) with React + Redux article as well.
In the project directory, you can run:
Runs the app in the development mode.
Open http://localhost:8080 to view it in the browser. If you see CORS related issues like "Origin is not allowed by Access-Control-Allow-Origin", please open another instance of your browser with disabled security.
If you are using Chrome on Mac OS, then start it as:
open -n -a "Google Chrome" --args --user-data-dir=/tmp/temp_chrome_user_data_dir http://localhost:8080/ --disable-web-securityThe page will reload if you make edits.
You will also see any lint errors in the console.
Launches the test runner in the interactive watch mode.
See the section about running tests for more information.
Builds the app for production to the build folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.
Your app is ready to be deployed!
See the section about deployment for more information.
Note: this is a one-way operation. Once you eject, you can’t go back!
If you aren’t satisfied with the build tool and configuration choices, you can eject at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except eject will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
You don’t have to ever use eject. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
You can learn more in the Create React App documentation.
To learn React, check out the React documentation.
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify