Add a Trusted Device with IBM MobileFirst Foundation 8.0

Introduction

Many of the apps you use every day, like your favorite chat and email apps, are available to you in multiple channels - like web and mobile. And you probably appreciate it if you can transition seamlessly between the two, even when it comes to authentication. Entering your credentials over and over on each device can be frustrating. What if your browser could somehow know that you already authenticated in your mobile app?

Let’s take a look at some scenarios where this could be really useful:

  • Imagine you are using your favorite fitness app, and you are already logged in on your mobile device. You have used it to record all your training plans, and physiological data. After work you hit the gym and hop on a treadmill. The treadmill screen shows you a QRCode, you scan it with your app, and the treadmill automatically sets the workout program to match your personal preferences. You start working out, and that training info is transferred to your fitness record in your app.

  • After the gym, you go to the supermarket to buy some groceries. You go up to the checkout counter to pay, and scan a QR code on the machine with your supermarket app, which logs you in with your member discount. And you can even complete your payment from your app.

  • The next morning, you stop by the bank to deposit a check. But oh no, you forgot your debit card. No worries. You stand in front of the automatic teller, scan the QR code, and now you can deposit a check into your account.

This kind of functionality can add some pretty great value to your apps.

This blog will show you how simple it is to implement a feature which will let a user add a trusted device, like in the scenarios above, using IBM MobileFirst Foundation 8.0.

Live Demo


Note: Before diving into the technical details, it is recommended to have some knowledge about the following topics:

Running the sample

To run this sample application, see the sample’s README.md.

Architecture

Add a trusted device

General Sample flow

  1. User logs into the mobile app.
  2. The web browser, on another device (e.g: tablet, desktop, kiosk), opens a socket using socket.io in front of the NodeJS server. This socket will be used to notify the browser later on.
  3. In the web browser, the user opens a web page which tries to call the /user REST endpoint on the QRCodeWebLogin Resource Adapter. The /user endpoint is the protected resource that returns the user data.
  4. The /user request arrives to the NodeJS server which forwards it to the MobileFirst server, using Express middleware.
  5. The /user endpoint is protected with a scope mapped to the qrcode Security Check.
  6. The Security Check validation finds that there isn’t any registered /user in the MobileFirst Server registration service associated with the security context of the web client yet.
  7. A UUID is generated on the server and stored in the Registration Service.
  8. QRCode is generated by the Security Check and returned to the web client as challenge.
  9. User scans the QRCode from the his mobile app where he is already logged-in.
  10. As a result of the scan, the QRCode UUID is sent to /approveWebUser which is protected with a scope mapped to the UserLogin SecurityCheck.
  11. As a result the approveWebUser function on the QRCodeWebLogin resource adapter looks for a client with same UUID attribute.
  12. When the adapter finds this client security context, an AuthenticatedUser object is created for the client in the Registration Service.
  13. The QRCodeWebLogin resource adapter then sends the request to the /refresh/:uuid endpoint on the NodeJS server.
  14. The NodeJS server emits an event on the socket which belongs to the client, identity by the UUID.
  15. The web client is notified and sends an empty challenge answer.
  16. A token is returned to the web client and it can invoke the /user request successfully.

Note: In the sample there is no mapped scope just for simplicity, while in real world it is recommended to map each security-check to a scope in the application security tab in the MobileFirst Operations Console. Scope mapping allows for better control on resource protection. Read more about scope mapping.

So where does the “magic” happen in the code?

Approve a device (web client) by finding the client UUID (custom attribute) in the Registration Service

####QRCodeResource.java

public Boolean approveWebUser(@QueryParam("uuid") String uuid) {
     ClientSearchCriteria clientSearchCriteria = new ClientSearchCriteria().byAttribute(QRCodeWebLoginSecurityCheck.QR_CODE_UUID, uuid);
     List<ClientData> clientsData = securityContext.findClientRegistrationData(clientSearchCriteria);
     if (clientsData.size() == 1) {
         clientsData.get(0).getPublicAttributes().put(QRCodeWebLoginSecurityCheck.WEB_USER_REGISTRATION_KEY, this.securityContext.getAuthenticatedUser());
         securityContext.storeClientRegistrationData(clientsData.get(0));
         return sendRefreshEvent(uuid);
     }
     return false;
}

Working with socket.io in the sample to notifying the web client

I implemented the push to the web client with socket.io, since I find it vert simple to use. Of course there are other push techniques like Push and Comet which can be helpful too.

Note: In case you need to work in cluster environment read the following.

Opening a socket on the web client, get notified and submit the challenge answer

####index.js

var socket = io();

socket.on(challenge.qrUUID, function (data) {
    if (data.refresh) {
        QRCodeChallengeHandler.submitChallengeAnswer({});
    }
});

Listening to connection and notifying the web client

####app.js

io.on('connection', function (socket) {
  console.log('a user connected');
});

app.get('/refresh/:uuid', function (req, res) {
  var uuid = req.params.uuid;
  console.log('Get refresh event from uuid ' + uuid);
  io.sockets.emit(uuid, { 'refresh': true });
  res.statusCode = 200;
  return res.send('Sent refresh event to client id ' + uuid);
});

Food for Thought:

By extension, you can also use MobileFirst Foundation to implement scenarios that allow a user to gain access to a device or a physical space by scanning a QR code from their mobile app. For instance, unlocking a hotel room or a city bike, or gaining access to a business lounge. There is one more added step to add to the implementation described in the blog above to validate the user’s identity and whether they are allowed access.

Inclusive terminology note: The Mobile First Platform team is making changes to support the IBM® initiative to replace racially biased and other discriminatory language in our code and content with more inclusive language. While IBM values the use of inclusive language, terms that are outside of IBM's direct influence are sometimes required for the sake of maintaining user understanding. As other industry leaders join IBM in embracing the use of inclusive language, IBM will continue to update the documentation to reflect those changes.
Last modified on October 10, 2016