Configuring a single-page application (SPA) to work with App ID.

New to IBM Cloud App ID? Welcome!

With App ID, you can easily add authentication, authorization, and user profile services to web apps, mobile apps, and APIs with minimal to zero code changes, without redeploying your app. By using App ID, you no longer have to worry about setting up infrastructure, ensuring geo-availability, or trying to understand complex compliance regulations when it comes to managing user identity. 

With the SDKs, you can get a sign-in flow going in minutes with Facebook, SAML 2.0, and more. You can also choose to use App ID’s scalable user registry (called Cloud Directory) to let your users manage their own account. Additionally, the App ID user profiles feature can be used to store information about your users—such as their preferences—to make their experience of your app personalized and, most importantly, secure.

In this blog, we’re going to walk you through configuring a single-page application (SPA) to work with App ID. With the client-side JavaScript SDK, you can easily secure your Angular, React, or other frontend framework. If your application has a backend that you manage or needs to be refreshed to load content, try the web app flow instead.

Before getting started, we should note that the App ID JavaScript SDK is one of very few on the market that uses the Authorization Code with Proof Key for Code Exchange (PKCE) flow instead of the implicit flow to secure your SPAs. Although it is currently the industry standard, the OAuth working group no longer recommends using the implicit flow due to several security concerns. For more information about why we chose PKCE over implicit, see the docs.

Understanding the flow

The figure below shows how to securely authenticate and authorize single-page application (SPA) users with the Authorization Code + PKCE flow.

  1. A user attempts to log in to your single-page application.
  2. The App ID SDK creates a code verifier for the authorization request, which is the plain text version of the code challenge. 
  3. Along with the authorization request, the client sends the code challenge and the challenge method that is used to encode the challenge.
  4. The authentication flow is started by App ID in a new window.
  5. The user chooses an identity provider to authenticate with and completes the sign-in process.
  6. The App ID SDK on the application receives the grant code.
  7. The SDK then makes an XHR request to the App ID token endpoint along with the grant code and the code verifier.
  8.  App ID returns access and identity tokens.

We’re going to walk you through the steps that you can take to use the App ID JavaScript SDK to secure a single-page application. The sample app that we’re using is based on React, which is a JavaScript library that you can utilize to build user interfaces by using components to efficiently update and render a UI.

Prerequisites

Before you get started with your React SPA, be sure that you have the following prerequisites:

Creating your app

  1. Set up a frontend build pipelines using create-react-app. Then, move into the project directory:
    npx create-react-app my-app
    cd my-app
  2. Install the IBM Cloud App ID SDK:
    npm install ibmcloud-appid-js
  3. In your code editor in the src directory of the application, open the App.js file. Import App ID by adding the following code:
    import AppID from 'ibmcloud-appid-js';
  4. In the main App() function, declare a new App ID instance with useMemo, which recomputes a memorized value when a dependency changes:
    const appID = React.useMemo(() => {
        return new AppID()
      }, []);
  5. Initialize App ID and add error handling. Add your client ID and discovery endpoint, which can be found in the Applications tab of the App ID dashboard:
    const [errorState, setErrorState] = React.useState(false);
    const [errorMessage, setErrorMessage] = React.useState('');
    (async () => {
        try {
          await appID.init({
            clientId: '<SPA_CLIENT_ID>',
            discoveryEndpoint: '<WELL_KNOWN_ENDPOINT>'
          });
        } catch (e) {
          setErrorState(true);
          setErrorMessage(e.message);
        }
      })();
  6. Create a login action that will execute when the login button is clicked. After a successful authentication, the welcomeDisplayState will be set to true and the userName will be set to the name returned in the App ID token:
    const [welcomeDisplayState, setWelcomeDisplayState] = React.useState(false);
    const [loginButtonDisplayState, setLoginButtonDisplayState] = React.useState(true);
    const [userName, setUserName] = React.useState('');
    
    
    const loginAction = async () => {
      try {
        const tokens = await appID.signin();
        setErrorState(false);
        setLoginButtonDisplayState(false);
        setWelcomeDisplayState(true);
        setUserName(tokens.idTokenPayload.name);
      } catch (e) {
        setErrorState(true);
        setErrorMessage(e.message);
      }
    };
  7. Add a welcome div, the login button that calls the login action, and an error div:
    {welcomeDisplayState && <div> Welcome {userName}! You are now authenticated.</div>}
    {loginButtonDisplayState && 
       <button style={{fontSize: '24px', backgroundColor: 'skyblue', border: 'none', cursor: 'pointer'}} id='login' onClick={loginAction}>Login</button>}
    {errorState && <div style={{color: 'red'}}>{errorMessage}</div>}
  8. Save all of the files. Your entire App.js file should look like this:
    import React from 'react';
    import logo from './logo.svg';
    import './App.css';
    import AppID from 'ibmcloud-appid-js';
    function App() {
      const appID = React.useMemo(() => {
        return new AppID()
      }, []);
      const [errorState, setErrorState] = React.useState(false);
      const [errorMessage, setErrorMessage] = React.useState('');
      (async () => {
        try {
          await appID.init({
            clientId: '<SPA_CLIENT_ID>',
            discoveryEndpoint: '<WELL_KNOWN_ENDPOINT>'
          });
        } catch (e) {
          setErrorState(true);
          setErrorMessage(e.message);
        }
      })();
      const [welcomeDisplayState, setWelcomeDisplayState] = React.useState(false);
      const [loginButtonDisplayState, setLoginButtonDisplayState] = React.useState(true);
      const [userName, setUserName] = React.useState('');
      const loginAction = async () => {
        try {
          const tokens = await appID.signin();
          setErrorState(false);
          setLoginButtonDisplayState(false);
          setWelcomeDisplayState(true);
          setUserName(tokens.idTokenPayload.name);
        } catch (e) {
          setErrorState(true);
          setErrorMessage(e.message);
        }
      };
      return (
        <div className='App'>
        <header className='App-header'>
          <img src={logo} className='App-logo' alt='logo' />
            {welcomeDisplayState && <div> Welcome {userName}! You are now authenticated.</div>}
            {loginButtonDisplayState && <button style={{fontSize: '24px', backgroundColor: 'skyblue', 
              border: 'none', cursor: 'pointer'}} id='login' onClick={loginAction}>Login</button>}
            {errorState && <div style={{color: 'red'}}>{errorMessage}</div>}
        </header>
        </div>
      );
    }
    export default App;
  9. Open your terminal. Run the following command to access your app from http://localhost:3000:
    npm start
  10. Make sure you register your redirect_uri (in this case http://localhost:3000/*) with App ID to ensure that only authorized clients are allowed to participate in the authorization workflow. This can be done on the App ID dashboard under the Manage Authentication tab in the Authentication Settings. See the docs for more details.

Well done! You successfully integrated IBM Cloud App ID’s SDK for SPA into a React application.

Note: You can view the code repository for our React sample app here.

Tips and things to note

  • You can use the App ID client SDK to automatically obtain a new pair of tokens without requiring that the user explicitly sign in. For more information, see Silent login.
  • To learn more about security vulnerabilities with the implicit grant type and authorization code flow, visit OAuth 2.0 Security Best Current Practice.
  • For more information about how PKCE and the authorization code flow work together, see the spec.

Questions and feedback

  • If you have technical questions about App ID, post your question on Stack Overflow and tag your question with ibm-appid.
  • For questions about the service and getting started instructions, use the IBM Developer Answers forum. Include the appid.
  • Open a support ticket in the IBM Cloud menu.
  • Reach out directly to the development team on Slack!

To get started with App ID, check it out in the IBM Cloud Catalog.

Was this article helpful?
YesNo

More from Cloud

Enhance your data security posture with a no-code approach to application-level encryption

4 min read - Data is the lifeblood of every organization. As your organization’s data footprint expands across the clouds and between your own business lines to drive value, it is essential to secure data at all stages of the cloud adoption and throughout the data lifecycle. While there are different mechanisms available to encrypt data throughout its lifecycle (in transit, at rest and in use), application-level encryption (ALE) provides an additional layer of protection by encrypting data at its source. ALE can enhance…

Attention new clients: exciting financial incentives for VMware Cloud Foundation on IBM Cloud

4 min read - New client specials: Get up to 50% off when you commit to a 1- or 3-year term contract on new VCF-as-a-Service offerings, plus an additional value of up to USD 200K in credits through 30 June 2025 when you migrate your VMware workloads to IBM Cloud®.1 Low starting prices: On-demand VCF-as-a-Service deployments begin under USD 200 per month.2 The IBM Cloud benefit: See the potential for a 201%3 return on investment (ROI) over 3 years with reduced downtime, cost and…

The history of the central processing unit (CPU)

10 min read - The central processing unit (CPU) is the computer’s brain. It handles the assignment and processing of tasks, in addition to functions that make a computer run. There’s no way to overstate the importance of the CPU to computing. Virtually all computer systems contain, at the least, some type of basic CPU. Regardless of whether they’re used in personal computers (PCs), laptops, tablets, smartphones or even in supercomputers whose output is so strong it must be measured in floating-point operations per…

IBM Newsletters

Get our newsletters and topic updates that deliver the latest thought leadership and insights on emerging trends.
Subscribe now More newsletters