Implement SSO on a Hybrid App with Mendix and SAML

Last modified: November 28, 2023

1 Introduction

This how-to will describe the challenges involved in implementing SSO (single sign-on) in hybrid mobile apps, and teach you how this can be solved in Mendix app.

2 Prerequisites

Before starting this how-to, make sure you have completed the following prerequisites:

3 Context

3.1 Hybrid Apps, Cordova, and PhoneGap Build

Hybrid Mendix apps can be viewed in mobile web browsers. However, some features of mobile devices cannot be accessed through HTML and JavaScript. Also, if you want to publish your app in the Apple App Store or Google Play Store, you have to wrap your app in a native shell. Mendix uses Cordova to do this. Cordova creates a native wrapper around a web application and provides access to native functionality through a JavaScript API. These apps are called hybrid apps, because they are a hybrid of a web and a native app. To create binaries of your app, Mendix leverages PhoneGap Build so that you do not need to install software (Android SDK, XCode) for this.

3.2 How Authentication Against an IdP Works

When authenticating against an identity provider (IdP), the following steps are taken:

  1. The client (user agent) requests a page/resource from Mendix.
  2. Mendix redirects the authentication request to the IdP by redirecting the client user agent there.
  3. The IdP contacts the client and presents a login page.
  4. The client authenticates against the IdP, then the IdP generates a SAML token and sends it back to the client, where it will be stored as a cookie.
  5. The SAML token is sent to the Mendix Server by redirecting the client user agent back to the Mendix app.
  6. After authentication, Mendix redirects the client to the page requested initially.
  7. The client now requests the page requested initially.
  8. Now that a security context exists, Mendix responds with the requested resource (page).

For more information on the authentication process, see Wikipedia’s SAML 2.0 Web Browser SSO Profile.

4 The Problems

There are two main problems when trying to implement SSO on a hybrid app.

4.1 The First Problem

The first problem is that the JavaScript needed to start up the app mobile functionality is stored inside the Mendix hybrid app. The application is loaded from the locally stored index.html file.

This is a problem because of all the browser redirects happening when doing the authentication against the IdP (as described in the section How Authentication Against an IdP Works above).

When a Mendix hybrid app is started on the mobile device, the localhost index.html page is loaded in order to load all the necessary JavaScript to run the app. However, to be able to authenticate the user, the user is redirected to the IdP, and then the IdP needs to redirect the user back to the app. The problem is that there is no way for the IdP to redirect to a localhost page, so there is no way to start the app while still including the right Cordova JavaScript.

4.2 The Second Problem

The second problem is that Cordova does not store cookies permanently. And since Cordova does not store (authentication) cookies, when an app is closed, the IdP cannot recognize a returning user, so it will always ask the user for authentication.

5 The Solution

Mendix has created a standard approach to support SSO via the SAML module in a Mendix hybrid app. This approach contains reusable JavaScript code which can be added to the PhoneGap Build package that is used to build the app binaries. It also requires a simple configuration change on the SAML module. These components can be used by Mendix developers to make mobile apps compatible with SAML. However, care must always be taken to ensure the solution fits the requirements for specific apps.

5.1 The JavaScript

The JavaScript code below will address the two problems described above.

To address the first problem, when the mobile app is starting to load, the JavaScript below will be executed. It opens a new window using Cordova’s InAppBrowser, and all the redirects for the authentication are done there. When all the redirects are completed and the requested resource is sent from the Mendix Server back to the app, the authentication process is complete. The new window can then be closed, and the loading of the localhost index.html page can proceed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
MxApp.onConfigReady(function(config) {
    var samlLogin = function() {
        var samlWindow = cordova.InAppBrowser.open(window.mx.remoteUrl + "SSO/", "_blank", "location=no,toolbar=no");

        var exitFn = function() {
            navigator.app.exitApp();
        };

        samlWindow.addEventListener("exit", exitFn);

        var loop = setInterval(function() {
            samlWindow.executeScript({
                code: "window.location.href;"
            }, function(href) {
                if (href[0].toLowerCase().indexOf(window.mx.remoteUrl.toLowerCase()) == 0 && href[0].indexOf("SSO") == -1) {
                    samlWindow.executeScript({
                        code: "document.cookie;"
                    }, function(values) {
                        samlWindow.removeEventListener("exit", exitFn);

                        var authPromise = new Promise(function(resolve, reject) {
                            var token = new RegExp('AUTH_TOKEN=([^;]+)', 'g').exec(values[0]);
                            if (token && token.length > 1) {
                                mx.session.tokenStore.set(token[1]).then(resolve);
                            } else {
                                resolve();
                            }
                        });

                        var closeWindow = function() {
                            samlWindow.close();

                            if (window.mx.afterLoginAction) {
                                window.mx.afterLoginAction();
                            }
                        };

                        authPromise.then(closeWindow);
                    });
                };
            });
        }, 1000);
    }

    config.ui.customLoginFn = samlLogin;
});

To address the second problem, after a successful authentication against the IdP, Mendix stores a token in the device’s local storage. The system will use that token from that moment on to create a new session for the user. The session is created in Mendix only, so a new authentication against the IdP will not be performed again. This token is a TokenInformation (part of the System module) object, and it can be accessed/edited in microflows. By default, this local token will never expire, but this can be overridden by changing the com.mendix.webui.HybridAppLoginTimeOut Runtime customization setting. The downside of this approach is that access rights will not be updated upon login, since no interaction is done with the IdP. However, in most systems using SSO, user and role provisioning is handled separately from the authentication, so this might not be an issue.

5.2 The Hybrid App Package

To use the hybrid app package, follow these steps:

  1. Open your app in the Developer Portal. In the navigation pane, click Mobile App.

  2. Click Publish for Mobile App Stores:

  3. Select Do it yourself and then click Download Customizable Package:

    This package you just downloaded is a customizable hybrid app package for your specific Mendix app. You can make changes to it, build a new PhoneGap Build package, and then upload it to PhoneGap Build to create the binaries (for example, APK for Android and IPA for iOS). To better understand the structure of what you just downloaded, see the Folder Structure section in the Mendix PhoneGap Build App Template documentation.

  4. Unzip the hybrid app package.

  5. Edit the Entry.js file (under src\www\scripts). The file should look like this:

  6. Add the JavaScript code provided in 5.1 The JavaScript under MxApp.onConfigReady(function(config) {. Your Entry.js file should now look like this:

  7. Create the PhoneGap Build package by following the instructions in the Through Uploading to PhoneGap Build section of the Mendix PhoneGap Build App Template documentation. Be sure to read the Prerequisites and Build on PhoneGap sections of this documentation as well. This is an overview of the steps:

    1. Install the latest stable version of Node.js.
    2. In the hybrid app root folder, execute npm install.
    3. In the hybrid app root folder execute npm run package.
  8. Create an APK or iOS package from the PhoneGap Build package. You can upload the new PhoneGap Build package (in the dist folder) to PhoneGap to build the APK or iOS binary.

5.3 The SAML Module

If you have the com.mendix.webui.HybridAppLoginTimeOut custom runtime setting configured to customize the expiration of mobile authentication tokens, you will have to set the value of the SAML20.HybridAppLoginTimeOutInMinutes constant to match the value of the custom runtime setting. When you use the SAML module for SSO in your Mendix app, the authentication token is not created by the Mendix runtime, which uses the custom runtime setting. Instead, the authentication token is created by the Java code in the SAML module. This Java code does not have access to the custom runtime setting value, and thus requires the constant value to be set.

Be sure to take these actions based on your use case:

  • If you use the default login handler in your hybrid app, you must change the com.mendix.webui.HybridAppLoginTimeOut custom runtime setting to change the validity of the authentication token used by the hybrid mobile app
  • If you use the SAML module in your hybrid app, you must change the SAML20.HybridAppLoginTimeOutInMinutes constant to change the validity of the authentication token used by the hybrid mobile app
  • If you use both the default login handler and the SAML module in your hybrid app, you must change both

The last thing to do is to check the Enable mobile authentication token box in the Provisioning tab when configuring an identity provider in the Mendix SAML module. This will make sure the SAML module provides the correct login token to the JavaScript part.

6 Read More