Contents


Scale single sign-on with App ID for your Node.js cloud apps

Use Redis to scale authentication for apps using the IBM App ID service

Comments

In this tutorial, you will learn about implementing scalable Node.js applications when you are using the App ID service. This IBM Cloud service allows you to add authentication to your mobile and web apps and protect your APIs and back-ends running on IBM Cloud. App ID provides authentication with email/password through a scalable user registry or you can add social login, so that users can sign in with their Facebook or Google credentials. With App ID, you can also host user profile info that you can use to build engaging experiences.

Successful cloud-scale application design requires planning for how to correctly achieve horizontal scaling in application components and services. For the tutorial, you create a Node.js getting started application in IBM Cloud that is modified for App ID. The application works well with a single instance. But you'll see that it demonstrates unreliable behavior when the app is scaled to two instances. Then, I explain what went wrong and take you through one implementation to fix it, with the help of the Redis Cloud service in IBM Cloud.

To achieve optimal scaling, each process should be designed to be stateless and always persist data to a backing service available to all processes.

What you'll need to complete this tutorial

  • An IBM Cloud account
  • A workstation with the following software installed:
    • Git (to clone the base app repository)
    • The IBM Cloud CLI version 0.6.5 or later.
    • A text editor for making minor updates to the provided source code

Run the appGet the code

When you run my demo app, sign in with the user name clouduser@example.com and the password IBMcloud123.

Step 1. Set up the initial application

Your first task is to create a simple Node.js application in IBM Cloud that uses the App ID service. You'll create a new app, add and configure an App ID service instance, and bind the service to the app.

  1. Log in to IBM Cloud, click Create Resource.
  2. Click Cloud Foundry Apps>SDK for Node.js.
  3. Specify a unique name for your app. For example, you could start the name with scaleApp ID followed by a hyphen and then, to make it unique, add your initials and the date, as in scaleApp ID-tor1803: Screenshot of app name example
    Screenshot of app name example
    Note: In the rest of this tutorial, replace <your app name> with the name you entered here.
  4. Click Create. You can continue with the following steps while the app is being created.
  5. Go to the IBM Cloud Catalog and click App ID in the Security services section: Screenshot of the app id tile in security catalog
    Screenshot of the app id tile in security catalog
  6. Keep all defaults and click Create. Wait for the service to be created and the dashboard for the service to start.
  7. On the left menu of the App ID dashboard, select Users to open the Cloud Directory.
  8. Click Add User.
  9. In the Add User dialog box, enter a user name and password of your choice, along with the other profile attributes. Click Save to add the user.Screenshot of cloud directory users
    Screenshot of cloud directory users
  10. Return to the Apps dashboard and click your application to open its overview page.
  11. In the application overview under Connections, click Create connection.
  12. Select the icon for the App ID service that you just created and click Connect:Screenshot of connecting user to service
    Screenshot of connecting user to service
  13. If prompted to restage the application, click Cancel.
  14. After you connect the service, you will see the App connections panel with the App ID service icon.

Your initial app setup is complete.

Step 2. Modify the application code and deploy

In this step, you clone a GitHub project that has the Getting Started Node.js App configured to use App ID. You'll make a minor modification to the manifest to deploy it over the Cloud Foundry application that you created in Step 1.

  1. Open a command prompt on your local workstation and run this command:

    git clone https://github.com/ibmecod/bluemix-scaleAppID.git <your app name>

  2. Update the manifest.yml file, replacing the app host and name properties:
    applications:
    - name: <your app name>
      host: <your app name>
      memory: 128M
  3. Change the command-line working directory to the project directory and log in to IBM Cloud with the IBM Cloud command-line tool:

    bx login -a https://api.ng.bluemix.net

  4. Update and deploy your app in IBM Cloud by running:

    bx app push

  5. Watch the staging messages from the bx app push command. After deployment, the app will start and you'll see a state of running for the app instance: Screenshot of the cf command output showing app start                             and instance details
    Screenshot of the cf command output showing app start and instance details

The app is now ready for testing.

Step 3. Scale the application in IBM Cloud

In this step, you test authentication for your app—first with a single app instance and then with an added second instance.

  1. In a new browser window or tab, open the URL for your application: https://<your app name>.mybluemix.net. Click the Log in button.
  2. You will see the default App ID login screen. You can change the authentication options that are available in the App ID login chooser and also customize the color and the displayed logo by using the App ID dashboard.
    Enter the user name and password that you added to the Cloud Directory when you are configuring the App ID service and click Log in. Screenshot of logging into app id service
    Screenshot of logging into app id service

    You get a greeting that combines the authenticated user name and the realm of the authentication — for example, "Hello, Cloud User!" — indicating that you authenticated successfully for this app instance.
  3. Return to the IBM Cloud Apps dashboard to scale the application. Open the app overview, click the + button on the Instances dial to increment the instance number 2, and click Save.
  4. IBM Cloud starts the second instance. After a moment the instance health will update with the new number of instances: Screenshot of the instance count showing two running and                             health of 100%
    Screenshot of the instance count showing two running and health of 100%
  5. Close the browser session that you used to test App ID and open a new browser window or tab. Browse to https://<your app name>.mybluemix.net and click the Log in button. Authenticate to the App ID login screen.
  6. Instead of the simple greeting, most likely you will see the login panel appear again. Or you might see the simple greeting, but if you click reload one or more times, you end up back on the login panel. If you experiment a little, you might also observe a successful login, where the app returns to the home page without any notification or acknowledgement of the successful login. In short, the application behavior has become unpredictable.

Step 4. Understand the test results

The simple app had no authentication issues with a single instance, but two instances are a problem because this app doesn't follow the twelve-factor app methodology. Specifically, it violates factor 6: "Execute the app as one or more stateless processes."

This unintentional failure is a by-product of how Node.js apps in IBM Cloud use express-session middleware and Passport in implementing the session interface that was used with OpenID Connect. By default, the express-session service stores session data in-memory, so it's available to only one of the two instances. This problem actually affects any application that is trying to use HTTP sessions with express-session so the solution we describe here works for all of those other applications, too.

This diagram illustrates how data for a session is only available to Instance 0 in the app:

Diagram showing session ID 1 available only to app instance 0
Diagram showing session ID 1 available only to app instance 0

What's the solution? Factor 6 goes on to say, "Any data that needs to persist must be stored in a stateful backing service, typically a database." The express-session documentation on GitHub lists several compatible backing stores. You'll implement this persistence by using Redis, which provides an in-memory key-value cache. This change will move session data for express-session out of the instance memory and into a persistent store available to all instances:

Diagram showing that after implementing persistence with Redis
Diagram showing that after implementing persistence with Redis

Step 5. Add session persistence with Redis

The Redis Cloud service in IBM Cloud is hosted in the same cloud environment as your app, minimizing response time for accessing this backing service.

  1. In IBM Cloud, navigate to the catalog and choose Redis Cloud from the Data & Analytics category: Screenshot of the Redis Cloud tile in the Bluemix                             catalog's Data and Analytics category
    Screenshot of the Redis Cloud tile in the Bluemix catalog's Data and Analytics category
  2. Select the 30MB Free Plan from the Pricing Plans list.
  3. Click Create to add the service.
  4. Click Restage to complete adding the service to your app.
  5. Return to the Apps dashboard and click your application to open its overview page.
  6. In the application overview under Connections, click Create connection.
  7. Select the icon for the Redis service that you just created and click Connect.
  8. Click Restage to complete adding the service to your app.
  9. In your local copy of the application source code, update the dependencies section in package.json by adding a comma on line 25 and two more entries:
    "passport": "^0.4.0",
      "connect-redis" : "^3.3.0",
      "redis" : "^2.8.0"
    },
  10. In server.js, add redis and connect-redis to the require section, appending after line 6:
    const passport = require("passport");
    const redis = require('redis');
    const RedisStore = require('connect-redis')(session);
  11. After line 112 , add code to obtain the configuration details for the Redis Cloud service from the environment and connect to the service:
    // additions for App ID support
    // get configuration for redis backing service and connect to service
    var redisConfig = appEnv.getService(/Redis.*/)
    var redisPort = redisConfig.credentials.port;
    var redisHost = redisConfig.credentials.hostname;
    var redisPasswd = redisConfig.credentials.password;
     
    var redisclient = redis.createClient(redisPort, redisHost, {no_ready_check: true});
    redisclient.auth(redisPasswd, function (err) {
        if (err) {
          throw err;
        }
    });
     
    redisclient.on('connect', function() {
        console.log('Connected to Redis');
    });
  12. In the app.use (session (... statement around line 130, add an option to use Redis as the store for the session:
    app.use(session({
      store: new RedisStore({ client: redisclient }),
      secret: '123456',
      resave: true,
      saveUninitialized: true
    }));
    app.use(passport.initialize());
    app.use(passport.session());
  13. Save app.js and package.json if you haven't done so already.
  14. From the command line, update the app:

    bx app push

  15. After the app starts, use the Cloud Foundry logs command with the recent option:

    bx app logs <your app name> --recent

  16. Check for a message that the app connected to Redis on startup: Screenshot of log output from application showing                             Connected to Redis message
    Screenshot of log output from application showing Connected to Redis message
  17. The manifest.yml file does not specify a number of active instances, so the app restarted with two instances and the sample output is from instance 1.
  18. Go back to your app at https://<your app name>.mybluemix.net/ and repeat the login test from Step 3.

Success! Now the app works correctly with two (or more) instances.

Conclusion

In this tutorial, you created a simple app that uses the App ID service for IBM Cloud and then tested the app with one and two instances running. With two instances, the app was unreliable because the Node.js express-session middleware defaults to a local in-memory store.

You fixed the problem by adding a persistent store for express-session sessions by using the Redis Cloud service in IBM Cloud. Although it's a good fit for this tutorial, the Redis Cloud free plan has no liability/SLA. For production use, consider the Compose for Redis service or one the services from Redis Enterprise Cloud.


Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Security, Cloud computing, Web development
ArticleID=1017268
ArticleTitle=Scale single sign-on with App ID for your Node.js cloud apps
publish-date=03142018