As a cloud developer, securing a single-page application (SPA) can be an intricate process with many different security protocols to consider. 

With IBM Cloud App ID in your toolbox, however, you can easily secure your Angular single-page application by using the App ID JavaScript SDK to add authentication and authorization.

With just a few lines of code, you can easily add a level of security to your SPA by requiring that users sign in to gain access to protected resources. The App ID SDK gives you the ability to do the following:

  • Enforce social or enterprise sign-in (such as Facebook, Google, and SAML 2.0 Federation) as identity provider options to your apps by using APIs, SDKs, prebuilt UIs, or your own branded UIs through verification of authentication tokens. 
  • Personalize your app experiences by storing user data, such as preferences and information that is returned by public social profiles.
  • Manage a user registry that you can easily scale as your user base grows.
  • Enforce policy-driven security for your apps by integrating with IBM Cloud Kubernetes Service at the cluster level.

Securing Angular SPAs

In this blog post, I’m going to walk you through configuring an Angular single-page application (SPA) to work with App ID by using the JavaScript SDK. 

Working with another frontend framework? No problem, follow along for the concepts but use your code. However, if your app has a backend that you manage or needs to be refreshed to load content, try working with the web app flow instead.

Understanding the flow

Before we get started, it is important to get the context of what we are about to do. The figure below shows how to securely authenticate and authorize single-page application users with the Authorization Code with Proof Key for Code Exchange (PKCE):

Figure 1: The authorization flow of single-page applications.

  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.

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.

Prerequisites

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

Note: You can skip the steps below by checking out the repository of our Angular sample SPA which you can clone and have running quickly to see how App ID can easily secure your application.

The steps below will take about 12 minutes to complete.

Prepare your workspace

  1. In your terminal, install the Angular CLI:
    npm install -g @angular/cli
    Scroll to view full table
  2. Create a workspace and initial application:
    ng new angular-sample-spa
    Scroll to view full table

    There will be follow-up questions after running the command above, go ahead and select your preferences as shown below:

    • Would you like to add Angular routing? y
    • Which stylesheet format would you like to use? CSS
  3. Navigate to the workspace folder:
    cd angular-sample-spa
    Scroll to view full table
  4. Install the IBM Cloud AppID SDK dependency using npm:
    npm install ibmcloud-appid-js
    Scroll to view full table

Create your application

  1. In your terminal, navigate to the app folder of your application and create two Angular components—welcome and home:
    cd src/app
    ng generate component welcome
    ng generate component home
    Scroll to view full table
  2. First, we will update the welcome component. In your code editor, go to the welcome folder, open welcome.component.html, and replace its contents with the code below:
    <div id="welcome" [ngClass]="style">
      <div class="welcome-display">
        <div>
          <img alt="App ID Logo" class="logo-icon" src="https://appid-management.eu-gb.bluemix.net/swagger-ui/images/app_id_icon.svg">
          <p>
            Welcome to the<br>
            IBM Cloud App ID SPA SDK<br>
            Sample App
          </p>
        </div>
        <button id="login" [ngClass]='buttonDisplay' (click)="onLoginClick()">Login</button>
        <div [ngClass]="errorStyle" id="error">{{errorMessage}}</div>
      </div>
    </div>
    Scroll to view full table
  3. Open the welcome.component.ts file and replace its contents with the code below. This file will contain the code necessary to add authentication and authorization to the application using the App ID SDK. Be sure to add your own SPA’s client ID and discovery endpoint:
    import { Component, Output, EventEmitter, OnInit } from '@angular/core';
    import AppID from 'ibmcloud-appid-js';
    @Component({
      selector: 'app-welcome',
      templateUrl: './welcome.component.html',
      styleUrls: ['./welcome.component.css']
    })
    export class WelcomeComponent implements OnInit {
      style = 'show';
      buttonDisplay = 'show';
      errorStyle = 'hide';
      errorMessage = '';
      appid = new AppID();
      @Output() changeState = new EventEmitter();
      async ngOnInit() {
        try {
          await this.appid.init({
            clientId: '<CLIENT_ID>',
            discoveryEndpoint: '<WELL_KNOWN_ENDPOINT>'
          });
        } catch (e) {
          this.errorMessage = e.message;
          this.errorStyle = 'show';
        }
      }
      async onLoginClick() {
        try {
          this.buttonDisplay = 'hide';
          const tokens = await this.appid.signin();
          const decodeIDTokens = tokens.idTokenPayload;
          const userName = 'Hi ' + decodeIDTokens.name + ', Congratulations!';
          this.style = 'hide';
          this.changeState.emit({userName});
        } catch (e) {
          this.errorMessage = e.message;
          this.errorStyle = 'show';
          this.buttonDisplay = 'show';
        }
      }
    }
    Scroll to view full table
  4. Now, we will update the home component. In the home folder, open the home.component.html file and replace its contents with the code below:
    <div [ngClass]="displayState">
      <div class="welcome-display">
        <img alt="App ID Logo" class="logo-icon" src="https://appid-management.eu-gb.bluemix.net/swagger-ui/images/app_id_icon.svg">
        <p>{{userName}}</p>
        <p>You've made your first authentication.</p>
      </div>
     </div>
    Scroll to view full table
  5. Go to the home.component.ts file in the home component, clear all the code present, and add the code below:
    import { Component, Input} from '@angular/core';
     
     
    @Component({
      selector: 'app-home',
      templateUrl: './home.component.html',
      styleUrls: ['./home.component.css']
    })
    export class HomeComponent {
      @Input() displayState: string;
      @Input() userName: string;
    }
    Scroll to view full table
  6. Navigate to the app folder and replace the contents of app.component.html with the following code:
    <app-welcome (changeState)="onChangeState($event)"></app-welcome>
    <app-home [displayState]="displayStateStatus" [userName]="userNameStatus"></app-home>
    Scroll to view full table
  7. Go to the app.component.ts file, clear all the code present, and add the code below:
    import { Component } from '@angular/core';
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      displayStateStatus = 'hide';
      userNameStatus = '';
      onChangeState(value) {
        this.displayStateStatus = 'show';
        this.userNameStatus = value.userName;
      }
    }
    Scroll to view full table
  8. Go to the src folder and add the following global styles to the styles.css file:
    body {margin: 0;padding: 0;max-width: 100%;overflow-x: hidden;}
    .hide {display: none;}
    .show {display: block;}
    .welcome-display {display: block;font-family: 'IBMPlexSans-Light', sans-serif;font-size: 1.5vw;text-align: center;margin: 10% auto 0;}
    .logo-icon {width: 70px;height: 70px;}
    #login {font-family: 'IBMPlexSans-Medium', sans-serif;font-size: 14px;color: #FFFFFF;text-align: center;background-color: #4178BE;border: none;cursor: pointer;width: 158px;height: 40px;margin: 20px auto 0;}
    #error {padding-top: 20px;font-size: 14px;color: red;}
    Scroll to view full table
  9. Save all the files and in your terminal, run the following command to view your app in the browser at  http://localhost:4200:
    ng serve
    Scroll to view full table
  10. Make sure you register your redirect_uri (in this case http://localhost:4200/*) 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 “Adding redirect URIs” for more details.

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

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 “Configuring 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 tag.
  • Check out the App ID tutorials on our YouTube channel.
  • 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.

More from Cloud

Clients can strengthen defenses for their data with IBM Storage Defender, now generally available

2 min read - We are excited to inform our clients and partners that IBM Storage Defender, part of our IBM Storage for Data Resilience portfolio, is now generally available. Enterprise clients worldwide continue to grapple with a threat landscape that is constantly evolving. Bad actors are moving faster than ever and are causing more lasting damage to data. According to an IBM report, cyberattacks like ransomware that used to take months to fully deploy can now take as little as four days. Cybercriminals…

2 min read

Integrating data center support: Lower costs and decrease downtime with your support strategy

3 min read - As organizations and their data centers embrace hybrid cloud deployments, they have a rapidly growing number of vendors and workloads in their IT environments. The proliferation of these vendors leads to numerous issues and challenges that overburden IT staff, impede clients’ core business innovations and development, and complicate the support and operation of these environments.  Couple that with the CIO’s priorities to improve IT environment availability, security and privacy posture, performance, and the TCO, and you now have a challenge…

3 min read

Using advanced scan settings in the IBM Cloud Security and Compliance Center

5 min read - Customers and users want the ability to schedule scans at the timing of their choice and receive alerts when issues arise, and we’re happy to make a few announcements in this area today: Scan frequency: Until recently, the IBM Cloud® Security and Compliance Center would scan resources every 24 hours, by default, on all of the attachments in an account. With this release, users can continue to run daily scans—which is the recommended option—but they also have the option for…

5 min read

Modernizing child support enforcement with IBM and AWS

7 min read - With 68% of child support enforcement (CSE) systems aging, most state agencies are currently modernizing them or preparing to modernize. More than 20% of families and children are supported by these systems, and with the current constituents of these systems becoming more consumer technology-centric, the use of antiquated technology systems is archaic and unsustainable. At this point, families expect state agencies to have a modern, efficient child support system. The following are some factors driving these states to pursue modernization:…

7 min read