Securing single page apps with App ID service

5 min read

By: Twana Daniel

Securing single page apps with App ID service

 

Investment Insights for Asset Managers is a modern portfolio manager that provides real-time insights into how news around the world can impact a given stock portfolio type. We’ve covered the detail of this application in previous posts. If you haven’t seen any of the previous posts then you should start with the introduction blog post.

The Investment Insights for Asset Managers offers a dashboard type user interface to allow users to analyze a set of stock portfolios based on the risk factor calculated. The application uses a combination of services like Watson Discovery News, Investment Portfolio, Predictive Market Scenarios and Simulated Instrument Analytics. All of the services configured using Node.js for the backend and AngularJS for the front end.

The backend Node.js app is responsible for handling the API’s, these API’s then been used by the client AngularJS app. The application works as expected but with one problem, the backend API’s are publicly available and can be used by anyone as there is user authentication added.

This is a perfect place to setup an authentication method to the application so only allow authenticated users to access the data and to secure the API’s endpoints.

Now that we have a clear understanding of why an authentication method is needed let’s explore the options available for integrating such service to add user authentication and secure the API’s.

Authentication Method

When comes to adding login authentications developers often ask what authentication service to use and why even use one in the first place?

In this blog post, we will cover what authentication service we used for the Investment Insights for Asset Managers application, and we explain why selected that an Authentication service.

First let’s look at the why, why use an authentication service. While developing the application, we needed a quick and easy way to get this done. We didn’t want to spend time on creating a custom login page, then storing and hashing user logins and handling all the middleware stuff. Why do all that when an authentication service can be used to deliver just that and more.

Luckily there is a service called App ID on IBM cloud catalog that can deliver everything we need with great integrations for Node.js applications.

Why we selected App ID?

  • App ID offers an easy integration for Node.js apps and most other runtimes or even mobile apps.

  • It offers user login interface that can be easily customised.

  • It offers out of the box social media integration allowing users to login via FaceBook or Google.

  • Easy to setup, you can configure the service in less than 5 minutes and then integrate it into your app.

  • It offers a collection code samples that be reused right away.

More on App ID can be found in the previous introduction blog post.

App ID

Here is a quick 2 minutes video demonstrating how to setup App ID for the web or mobile apps. Also, a more detailed stepping guide can be found on the IBM docs page.

App ID provides a Node.js SDK that can be found here and a full list of SDK’s for other runtimes can be found here. We will be using the Node.js SDK given that our application is done in Node.js.

The Node.js SDK offers two options in which we can use to secure the backend API’s:

  • APIStrategy to protect APIs

  • WebAppStrategy to protect web application and APIs

Code samples for each option can be found under the samples folder.

The SDK provides Passport.js strategies for protecting the APIs and Web applications. This helps to integrate App ID into your application. A passport authenticate method is added under all API’s and a method is set for each function. Let’s explore the main App ID source file that handles all the authentications in the backend.

The code sample below is located in /routes/auth.js where can be found here, the auth.js file handles all the authentication functionality from the server end. Let’s step through the code.

1. Loading the required dependencies. Note passport.js is needed as App ID SDK uses passport.js

const express = require('express');
const passport = require('passport');
const WebAppStrategy = require('bluemix-appid').WebAppStrategy;

2. Loading the helmet to help with securing express and connect-flash to store messages in the session.

const helmet = require('helmet');
const flash = require('connect-flash');
var router = express.Router();

3. /auth/login is the explicit login endpoint. Will always redirect browser to login widget due to {forceLogin: true}. If user is authenticated successfully then redirect to the dashboard page located on: /#!/dashboard

router.get('/auth/login', passport.authenticate(WebAppStrategy.STRATEGY_NAME, {
successRedirect: '/#!/dashboard',
forceLogin: true
}));

4. /auth/loginanon to handle anonymous login endpoint.

router.get('/auth/loginanon', passport.authenticate(WebAppStrategy.STRATEGY_NAME, {
successRedirect: '/#!/dashboard',
allowAnonymousLogin: true,
allowCreateNewAnonymousUser: true
}));

5. /auth/callback is to handle the callback to finish the authorization process. This will retrieve access and identity tokens from App ID service and redirect to either (in below order).

router.get('/auth/callback', passport.authenticate(WebAppStrategy.STRATEGY_NAME));

6. /auth/logged is called by the Web UI to check if the current session is authenticated and to retrieve the user profile once logged.

router.get('/auth/logged', (req, res) => {
res.send({
logged: req.isAuthenticated(),
profile: req.user
});
});

7. Logout endpoint. Clears authentication information from session

router.get('/auth/logout', (req, res) => {
WebAppStrategy.logout(req);
res.redirect('/');
});

8. Configure passportjs with user serialization/deserialization. This is required for authenticated session persistence accross HTTP requests. See passportjs docs for additional information http://passportjs.org/docs

module.exports = (app, appIDCredentials) => {
passport.serializeUser((user, cb) => {
cb(null, user);
});
passport.deserializeUser((obj, cb) => {
cb(null, obj);
});
// Configure express application to use passportjs
app.use(passport.initialize());
app.use(passport.session());

9. Used for AppID – Helmet helps to secure Express apps by setting various HTTP headers and Configure passportjs to use AppID WebAppStrategy

app.use(helmet());
app.use(flash());
passport.use(new WebAppStrategy(appIDCredentials));

Checkout the auth.js file for full source code example.

Next, after setting up the base authentication inside the auth.js file we must use it within the app. Inside the main server.js file we are making a use the authentication functions.

We set all the API urls with a path of ‘/api/v1’ then simply added a check to see if the user is authenticated or not, if the user is authenticated then we grant access, if not then we prompt a 401 error meaning the user is unauthorised. The code below shows how this is done:

function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
res.sendStatus(401);
}
}
app.use('/api/v1/', checkAuthenticated);

The code snippet above can be found here: https://github.com/IBM-Bluemix/investment-insights-for-asset-managers/blob/master/server.js

Next, we need to add a check on the client side to verify with the server if the user is authenticated or not.

The Client

As noted earlier, we are using AngularJS on the client side. We have a login service where it checks if the user is logged in or not. This is done by calling the backend API on ‘/auth/logged’ to see if the user is logged in with a valid cookie. If the user is not authenticated then they will be directed to the App ID login page. The code that handles the client side can be found inside the login.service.js file.

Testing

It’s time to test the application to see if the web application and API’s are secure. To do that we are going carry two type of testing.

Web application testing

Let’s start by trying to access the dashboard without being authenticated. To test this, try and access the portfolio page without being authenticated.

Note that you are getting redirected to the home page.

This proves that our site is secure from the web application end. Now let’s test the API’s.

API testing

To test the API’s we are going to use cURL to see if we can access one of the API’s.

  • Open your command line window and run the next command to call the portfolios api

  • curl -v https://investment-insights-am.mybluemix.net/api/v1/portfolios

The output should be unauthorized: 

< HTTP/1.1 401 Unauthorized
< X-Backside-Transport: FAIL FAIL

This proves that our API’s are secure and the only way to access the API’s is if we have a valid cookie that in which to be passed when making the API call when doing cURL. If you want to learn more on how to generate a cookie and pass into the cURL, then check out this post covering all the API’s in more depth.

 

Watch out for more blog articles talking about future services that will be added to the Investment Insights for Asset Managers application. Happy Coding!

Be the first to hear about news, product updates, and innovation from IBM Cloud