Skip to Content
Technical Articles

Getting Started with Kapsel – Part 2 — Logon (SP13+)

Previous   Home   Next

Registering using the Logon Plugin
SAPUI5 and the Logon Plugin
Customizing the Logon Plugin’s UI
Timing and Performance
Registering using an X.509 Certificate on Android with SMP(SP15+)
Registering using an X.509 Certificate on Android with SAP Cloud Platform Mobile Services(SP15+)
Multiple Users


The Logon plugin manages the onboarding or registration process with a SAP Cloud Platform Mobile Services or SMP 3.0 server. When an application onboards to to a server, it receives a registration ID (also known as an application connection ID). In all subsequent requests to the server, the registration ID is sent via a cookie named X-SMP-APPCID that is set following a successful registration. This enables tracing functionality for each app instance.

The server integrates with common security providers such as HTTP/HTTPS Authentication, Directory Service (LDAP), SAML, or x.509 User Certificate. The Logon plugin provides a registration screen where the user can enter values needed to connect to the server. The server will validate the registration using one of the security providers and the connection details will be stored in the Logon plugin’s secure data vault. A basic authentication challenge can be handled automatically by the AuthProxy plugin using the stored registration credentials retrieved from the Logon plugin’s data vault.

The data vault used by the Logon plugin is separate from storage provided with the Encrypted Storage plugin and is used to store user names, passwords, keys and certificates while the Encrypted Storage plugin is better suited to storing application data.

For additional details on the Logon plugin, see C:\SAP\MobileSDK3\KapselSDK\docs\api\sap.Logon.html or Using the Logon Plugin.

For additional information on the underlying component that is exposed via the Logon plugin, the Developing with MAF Logon section explains how to use the MAF Logon in a native application.

Registering using the Logon Plugin

If you have not already done so, complete the previous section, Creating an Apache Cordova Project.

    • Add the Logon plugin and dialogs plugin.The following steps assume that a KAPSEL_HOME environment variable has been set to the location of the KapselSDK.
      Note the way to access an environment variable on windows is with a % sign while on a Mac it is a $.

      on Windows
      cordova plugin add kapsel-plugin-logon --searchpath %KAPSEL_HOME%/plugins
      on a Mac
      cordova plugin add kapsel-plugin-logon --searchpath $KAPSEL_HOME/plugins
      cordova plugin add cordova-plugin-dialogs

      An added plugin can be removed by calling

      cordova plugin remove plugin_id
    • A list of the plugins now included in the project can be seen by entering the below command.
      cordova plugins
      cordova-plugin-device 1.1.6 "Device"
      cordova-plugin-dialogs 1.3.3 "Notification"
      cordova-plugin-whitelist 1.3.2 "Whitelist"
      kapsel-plugin-authproxy 3.15.2 "AuthProxy"
      kapsel-plugin-corelibs 3.15.2 "CoreLibs"
      kapsel-plugin-i18n 3.15.2 "i18n"
      kapsel-plugin-inappbrowser 3.15.2 "InAppBrowser"
      kapsel-plugin-logon 3.15.2 "Logon"
      kapsel-plugin-ui5 3.15.2 "ui5"

      Notice that the plugins that the Logon plugin depends on are added if they are not present. This is defined in

    • This sample requires the application previously created in Configuring a Kapsel App in the Management Cockpit.
    • Replace www\index.html with the following contents.
      <!DOCTYPE html>
              <!--<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline' data: gap: 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">-->
              <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
              <script type="text/javascript" charset="utf-8" src="datajs-1.1.2.min.js"></script>
              <script type="text/javascript" charset="utf-8" src="serverContext.js"></script>
              <script type="text/javascript" charset="utf-8" src="cordova.js"></script>
                  var t0 = Number(location.href.split("startTime=")[1]); //Time passed in from main activity.
                  var t1 =;
                  var t2; //onLoad
                  var t3; //deviceready
                  var readStartTime;
                  var logonInitTime;
                  var unlockTime;
                  var resumeTime;
                  var applicationContext = null;
                  window.onerror = onError;
                  function onError(msg, url, line) {
                      var idx = url.lastIndexOf("/");
                      var file = "unknown";
                      if (idx > -1) {
                          file = url.substring(idx + 1);
                      alert("An error occurred in " + file + " (at line # " + line + "): " + msg);
                      return false; //suppressErrorAlert;
                  function init() {
                      updateStatus2("EventLogging: deviceready called");
                      t3 =;
                      console.log("EventLogging Perf: " + ((t3 - t1)/1000).toFixed(3) + " seconds from onLoad until deviceready");
                      if (sap.Logger) {
                          sap.Logger.setLogLevel(sap.Logger.DEBUG);  //enables the display of debug log messages from the Kapsel plugins.
                          sap.Logger.debug("EventLogging: Log level set to DEBUG");
                      if (navigator.notification) { // Override default HTML alert with native dialog. alert is not supported on Windows
                          window.alert = navigator.notification.alert;
                  function logonSuccessCallback(result) {
                      updateStatus2("logonSuccessCallback called");
                      var endTime =;
                      var endTime2 = new Date();
                      console.log("EventLogging Perf: " + ((endTime - logonInitTime)/1000).toFixed(3) + " seconds for logon.init to complete");
                      console.log("EventLogging Perf: " + ((endTime - t1)/1000).toFixed(3) + " seconds from onload till datavault is unlocked");
                      console.log("EventLogging Perf: " + ((endTime2 - t0)/1000).toFixed(3) + " seconds from main activity till datavault is unlocked.  Requires modifying");  //loadUrl(launchUrl + "?startTime=" + new java.util.Date().getTime());
                      console.log("EventLogging:  logonSuccessCallback " + JSON.stringify(result));
                      applicationContext = result;
                  //used when the logon plugin does not register with a server
                  function logon2SuccessCallback(result) {
                      console.log("EventLogging: logon2SuccessCallback " + JSON.stringify(result));
                      applicationContext = result;
                      applicationContext.applicationEndpointURL = "";
                  function logonErrorCallback(error) {   //this method is called if the user cancels the registration.
                      alert("An error occurred:  " + JSON.stringify(error));
                      if (device.platform == "Android") {  //Not supported on iOS
                  function read() {
                      updateStatus2("Read request started");
                      readStartTime =;
                      if (!applicationContext) {
                          alert("Register or unlock before proceeding");
                      sUrl = applicationContext.applicationEndpointURL + "/CarrierCollection?$format=json";  //JSON format is less verbose than atom/xml
                      var oHeaders = {};
                      //oHeaders['X-SMP-APPCID'] = applicationContext.applicationConnectionId;  //not needed as this will be sent by the logon plugin
                      var request = {
                          headers : oHeaders,
                          requestUri : sUrl,
                          method : "GET"
                      if (device.platform == "windows") { //provided by the authproxy and logon plugins on Android and iOS but not on Windows
                          request.user = applicationContext.registrationContext.user;
                          request.password = applicationContext.registrationContext.password;
            , readSuccessCallback, errorCallback);
                  function readSuccessCallback(data, response) {
                      var endTime =;
                      updateStatus2("Read " + data.results.length + " records in " + ((endTime - readStartTime)/1000).toFixed(3) + " seconds");
                      var carrierTable = document.getElementById("carrierTable");
                      for (var i = data.results.length -1; i >= 0; i--) {
                          var row = carrierTable.insertRow(1);
                          var cell1 = row.insertCell(0);
                          var cell2 = row.insertCell(1);
                          cell1.innerHTML = data.results[i].carrid;
                          cell2.innerHTML = data.results[i].CARRNAME;
                  function clearTable() {
                      var carrierTable = document.getElementById("carrierTable");
                      while(carrierTable.rows.length > 1) {
                  function errorCallback(e) {
                      alert("An error occurred: " + JSON.stringify(e));
                  function register() {
                      logonInitTime =;
                      updateStatus2("Calling Logon.init");
                      sap.Logon.init(logonSuccessCallback, logonErrorCallback, appId, context);
                      //sap.Logon.initPasscodeManager(logon2SuccessCallback, errorCallback, appId);  //initialize the datavault without registering with an SMP server
                  function unRegister() {
                      updateStatus2("Calling deleteRegistration");
                      sap.Logon.core.deleteRegistration(logonUnregisterSuccessCallback, errorCallback);
                      //sap.Logon.deletePasscodeManager(logonUnregisterSuccessCallback, errorCallback);  //Used when the datavault is initialized with initPasscodeManager
                  function logonUnregisterSuccessCallback(result) {
                      updateStatus2("Successfully Unregistered");
                      console.log("EventLogging: logonUnregisterSuccessCallback " + JSON.stringify(result));
                      applicationContext = null;
                  function lock() {
                      sap.Logon.lock(logonLockSuccessCallback, errorCallback);
                  function logonLockSuccessCallback(result) {
                      console.log("EventLogging: logonLockSuccessCallback " + JSON.stringify(result));
                  function unlock() {
                      unlockTime =;
                      sap.Logon.unlock(unlockSuccessCallback, errorCallback);
                  function unlockSuccessCallback(result) {
                      updateStatus2("unLockSuccessCallback called");
                      var endTime =;
                      console.log("EventLogging Perf: " + ((endTime - unlockTime)/1000).toFixed(3) + " seconds to unlock the datavault");
                  function managePasscode() {
                      sap.Logon.managePasscode(managePasscodeSuccessCallback, errorCallback);
                  function managePasscodeSuccessCallback() {
                      console.log("EventLogging: managePasscodeSuccess");
                  function showScreen(screenIDToShow) {
                      var screenToShow = document.getElementById(screenIDToShow);
             = "block";
                      var screens = document.getElementsByClassName('screenDiv');
                      for (var i = 0; i < screens.length; i++) {
                          if (screens[i].id != {
                              screens[i].style.display = "none";
                  function updateStatus2(msg) {
                      var d = new Date();
                      document.getElementById('statusID2').innerHTML = msg + " at " + addZero(d.getHours()) + ":" + addZero(d.getMinutes()) + ":" + addZero(d.getSeconds());
                      console.log("EventLogging: " + msg + " at " + addZero(d.getHours()) + ":" + addZero(d.getMinutes()) + ":" + addZero(d.getSeconds() + "." + addZero(d.getMilliseconds())));
                  function addZero(input) {
                      if (input < 10) {
                           return "0" + input;
                      return input;
                  function onLoad() {
                      console.log("EventLogging: onLoad");
                      t2 =;
                      var endTime = new Date();
                      console.log("EventLogging Perf: " + ((endTime - t0)/1000).toFixed(3) + " seconds between MainActivity and onLoad");
                  function onBeforeUnload() {
                      console.log("EventLogging: onBeforeUnLoad");
                  function onUnload() {
                      console.log("EventLogging: onUnload");
                  function onPause() {
                      console.log("EventLogging: onPause");
                  function onResume() {
                      resumeTime =;
                      console.log("EventLogging: onResume");
                  function onSapResumeSuccess() {
                      console.log("EventLogging: onSapResumeSuccess");
                      var endTime =;
                      console.log("EventLogging Perf: " +  ((endTime - resumeTime)/1000).toFixed(3)  + " seconds from onresume to onSapResumeSuccess");
                  function onSapLogonSuccess() {
                      console.log("EventLogging: onSapLogonSuccess");
                  function onSapResumeError(error) {
                      console.log("EventLogging: onSapResumeError " + JSON.stringify(error));
                  document.addEventListener("deviceready", init, false);
                  document.addEventListener("pause", onPause, false);
                  document.addEventListener("resume", onResume, false);
                  document.addEventListener("onSapResumeSuccess", onSapResumeSuccess, false);
                  document.addEventListener("onSapLogonSuccess", onSapLogonSuccess, false);
                  document.addEventListener("onSapResumeError", onSapResumeError, false);
          <body onload="onLoad()" onunload="onUnload()" onbeforeunload="onBeforeUnload()">
              <div class="screenDiv" id="LoadingDiv">
                  <h1>Loading ...</h1>
              <div class="screenDiv" id="LockedDiv" style="display: none">
                  <button id="unlock2" onclick="unlock()">Unlock</button>
              <div class="screenDiv" id="MainDiv" style="display: none">
                  <h1>Logon Sample</h1>
                  <button id="read" onclick="read()">Read</button>
                  <button id="unregister" onclick="unRegister()">Unregister</button>
                  <button id="lock" onclick="lock()">Lock</button>
                  <button id="unlock" onclick="unlock()">Unlock</button>
                  <button id="managePasscode" onclick="managePasscode()">Manage Passcode</button><br>
                  <span id="statusID2"></span>
                  <table id="carrierTable"><tr><th>Carrier ID</th><th>Carrier Name</th></tr></table>

      Create a file named serverContext.js in the www folder and copy the content from below.

      var appId = ""; // Change this to app id on server
      // Optional initial connection context
      var context = {
          //"serverHost": "", //Place your SMP 3.0 server name here
          "serverHost": "", //SAP Cloud Platform Mobile Services
          "https": true,  
          "serverPort": "443",  //443 for SAP Cloud Platform Mobile Services, may be different for an on premise SAP Mobile Platform server
          //"multiUser": true,
          //"useLocalStorage": false,
          "user": "i82XXXX",          //For demo purposes, specify the user name and password you wish to register with here to save typing on the device 
          "password": "XXXXX",        //Note, if you wish to use this user name and password to be passed to the backend OData producer, choose Basic as the SSO mechanism
                                      //The AuthProxy plugin with the Logon plugin can respond to 401 Authentication challenges if the same credentials used to register are also used to make OData requests
                                      //Once set the credentials can be changed by calling sap.Logon.changePassword()
          "passcode": "password",     //Hardcoding passwords and unlock passcodes are strictly for ease of use during development
                                      //Passcode can be changed by calling sap.Logon.managePasscode()
          "unlockPasscode": "password",
          "passcode_CONFIRM": "password",
          "oldPasscode" : "password",
          "communicatorId": "REST",
          //"auth": [ { "type": "" } ], //Indicates that a redirect to a SAML IDP should be used for registration
          //"refreshSAMLSessionOnResume": "skip",  // Useful for offline apps when you may not wish for a saml check to be performed when the app is resumed since you may be offline
          "custom": {
              "hiddenFields": ["farmId", "resourcePath", "securityConfig", "serverPort", "https"]

      Edit the serverHost, user, and password variables in serverContext.js.

      Note if you are using an Android emulator and your server is running on the same machine, can be used to reach the host machine from the emulator.

      Note, that the application ID is and is passed in as a parameter to the method sap.Logon.init(). The logonSuccessCallback method stores an object containing the logon parameters into the applicationContext variable.

      function logonSuccessCallback(result) {
          applicationContext = result;
    • Place a copy of datajs-1.1.2.min.js into the www folder. For additional details on datajs and OData see Appendix A: OData.
  • If you are deploying to iOS, ensure that Keychain Sharing is enabled.
  • If you are targeting Windows 10, add the following to your config.xml file.
    <preference name="windows-target-version" value="10.0" />
  • Prepare, build and deploy the app with the following commands.
    cordova run android
    cordova run windows -- --archs=x64 
    cordova run windows --device -- --archs=arm --phone
    cordova run ios
  • Alternatively, use Android Studio, Xcode or Visual Studio to deploy and run the project after first running the below command.
    cordova prepare
  • The registration screen allows a user to enter the connection information for their SAP Mobile Platform server. As of SP15, this screen will return the following error messages.
    • Not connected to network.
    • Please check your credentials.
    • Server certificate failed validation.
    • Server unreachable.
    • Secure channel error. (occurs if http is used on an https port or vice versa)

    In serverContext.js, the context object can be used to set default values such as port to be used.
    If you need to enter text on an Android device and wish to use your computers keyboard try the following.

    adb shell input text some_text_to_enter

    The hiddenFields which was added to the context object in SP 13 can be used to hide fields. Notice above that serverPort and whether to use HTTPS or not are not shown.

    var context = {
        "serverHost": "", //Place your SMP 3.0 server name here
        "https": "false",
        "serverPort": "8080",
        "custom": {
            "hiddenFields": ["farmId", "resourcePath", "securityConfig", "serverPort", "https"]

    For additional security, the application can have a passcode screen. The client password policy such as password length and retry limit can be centrally managed in the management cockpit. It is also possible to disable this feature via the custom property disablePasscode as shown in the customization section below.

    The Logon plugin’s data vault which stores the entered credentials needs to be unlocked when the application opens and is locked when it closes. The data vault will also lock if it the app is in the background for a certain length of time. This is configurable via the lock timeout setting.

    SAP Mobile Platform Cockpit

    SAP Cloud Platform Mobile Services Cockpit

    As of SP14, it is possible to use a fingerprint instead of a passcode to unlock the app. The following instructions demonstrate this on an Android 7.1 emulator. A few issues were found using an earlier emulator so it may be best to use the latest available emulator or a device. Note, a passcode is still required as a fallback in case the device is unable to successfully scan your fingerprint. For additional instructions see Understanding Fingerprint Authentication.
    Settings > Security> Fingerprint.

    The following command simulates a fingerprint touch.

    adb -e emu finger touch 1

    Alternatively, from the emulators extended controls menu select Fingerprint > Touch Sensor.


    Provide the previously entered fingerprint to unlock.

    adb -e emu finger touch 1

    It is possible to use the Logon plugin’s data vault without using its features for registering with an SMP server using the sap.Logon.initPasscodeManager method. See the index.html in the Encrypted Storage plugin for a complete example.

  • Try out the rest of the application. The following are a few more screenshots showing the lock screen and the results of performing a read.
  • Note, if the server host, port or application id changes; sap.Logon.core.reset() must be called followed by calling init sap.Logon.init().In SP10 of the SMP server a new setting was added called Automatic Removal which means that registrations that have not been used for a specified time will be deleted automatically.
  • If the registration fails one quick test to verify basic connectivity to the SMP 3.0 server from the device or emulator is to open the following URL from a browser on the device or emulator.
    http://SMP_Server_IP_Address:8080/sapui5/ or http://SMP_Server_IP_Address:8080 

    If the above URL opens correctly in a browser on the machine that the SMP server is running on but not from the browser on another machine or on a mobile device there is likely something such as a firewall preventing communication over port 8080.

  • When the app is opened, the deviceready event fires and the code in the init() method is called including a call to sap.Logon.init() which will open either the registration screen, the unlock screen, or if the no passcode option is enabled, the first screen of the app.
  • Note that this example contains some additional logging and timing of events using the term EventLogging. Event listeners for pause, resume, onload, onunload, onbeforeunload, onSapResumeSuccess, on SapLogonSuccess and onSapResumeError events have been added. See also Events.
  • Note that on iOS versions greater than 6, the status bar can overlay the contents of the WebView. The org.apache.cordova.statusbar plugin can be added to prevent this. See iOS 7 Status Bar Overlays the App.

SAPUI5 and the Logon Plugin

In SP14, a new plugin named kapsel-plugin-ui5 contains a minimal set of the SAPUI5 libraries that are used by the logon plugin.

A change was also made to use the belize theme where in previous versions of the SDK, the blue_crystal theme was used. This is specified in the following file:


The plugin will install UI5 to the resources folder at the root of the www folder if the following file is not found.


If you want to use your own copy of UI5, delete the resources folder in the www folder and add your own copy of UI5 there. Run cordova prepare to update the platforms with that copy.

If your application is always online and you wish to reduce the size of your app, you could change iab.html to load SAPUI5 from This may also improve the speed of building and deploying your app during development.


Note, this requires removing the logon plugin, then adding it back after making this change. Also delete the all the contents in the www\resources folder of your application and replace sap-ui-core.js with an empty file. The size of the app prior to making this change was about 12 MB vs 5 MB after.

Customizing the Logon Plugin’s UI

The text that is displayed as part of the Logon’s UI can be modified as the strings are loaded from the file


Make a change to the above file and then remove and add back the logon plugin as shown below.

cordova plugin remove kapsel-plugin-logon
cordova plugin add kapsel-plugin-logon --searchpath %KAPSEL_HOME%/plugins
cordova run android

See also the Localization section of this guide.

As of SP13, the custom field in the context object can be used to further customize the screens of the Logon plugin as shown in the following example context.

var context = {
    "serverHost": "", //Place your SMP 3.0 server name here
    "https": "false",
    "serverPort": "8080",
        "custom": {
            "hiddenFields": ["farmId", "resourcePath", "securityConfig", "serverPort", "https"],
            "backgroundImage": "../../../nightsky.jpg",
            "styleSheet": "../../../custom.css",
            "copyrightMsg": ["Copyright @2016 Mycompany Inc.", "All rights reserved."],
            "hideLogoCopyright" : false,
            "disablePasscode": true

Note, the above files such as nightsky.jpg should be placed in www folder and the ../ above is necessary as they are referenced from iab.html within the logon plugin.

The contents of the custom.css file follow.

/* company logo */
#panel_footer_hbox > .sapMFlexItem:not(#copyright) {
    /* uncomment to hide logo */
    /*display: none;*/

    /* uncomment to right align logo */
    /*position: absolute;
    right: 0px;*/

#logo {
    /* change size of logo */
    height: 40px !important;

/* copyright message */
    /* uncomment to hide copyright message */
    /*visibility: hidden;*/
    /* uncomment to right align text */
    /*text-align: right;*/

    /* uncomment to left align copyright message */
    /*left: 0px;*/


/* copyright message first line */
    /* change text color */
    color: white;
    /* change text size */
    font-size: 20px;
/* copyright message second line */
#copyright2 {
    /* change text color */
    color: yellow;

The background and logo images and custom.css files should be placed in the www folder.

Prepare, build and deploy the app with the following command.

cordova run android
cordova run windows -- --archs=x64  
cordova run ios

Notice that the background, and copyright logo and text have been customized. Also, note that the option to set a passcode screen is not shown after pressing the OK button due to the context option disablePasscode being set to true.

Timing and Performance

Note that this example contains some additional logging and timing of events using the term EventLogging. To enable the capturing of the time taken from the when the app is initially started till the datavault is unlocked, make the following modification.
On Android, modify the following file and change the below line to pass in to the index.html the time the app was started.

loadUrl(launchUrl + "?startTime=" + new java.util.Date().getTime());

With this change, the time taken from the MainActivity which should occur shortly after the user clicks on the app icon till the time the logonSucccessCallback is called can be calculated. In the below example, the time taken is about 2 1/2 seconds.

The time taken by the datavault to unlock can be reduced (using SP15 or greater is recommended for Android) by modifying the useLocalStorage setting in the serverContext.js file as shown below.

"useLocalStorage": true,

Notice above that the time taken from clicking on the app icon till the datavault unlocks has decreased from 2 1/2 seconds to 1.3 seconds.
For further details see Storing configuration data outside of the datavault.

Registering using an X.509 Certificate with SMP(SP16+)

In SP15, a built in certificate provider was added to the Logon plugin for Android(Logon Plugin Includes System Certificate Provider).
In SP16 a file and shared keychain certificate provider was added to the Logon plugin for iOS (Keychain Certificate Provider Plugin).

A certificate provider enables the logon plugin to perform a registration against a SMP or SCPMS server using a certificate to identify the user. The following instructions will demonstrate using it. Additional details are available at Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers.

  • Configure the app to use the Certificate Authentication provider.

    Set Validated Certificate Is Identity to ON and Certificate Attribute as Principal to be CN which is the Common Name field from the user’s certificate.
  • Configure the SMP server to trust certificates signed by the certificate authority that signed the user certificates by ensuring that the CA that signed the user certificates is listed in the Shared Keystore Entries.
  • Modify the serverContext.js file to use port 8082 and ensure the fully qualified machine name is used for the host.
  • Add the following code to the start of the JavaScript code in index.html just below the line var resumeTime = null;
    var operation = {};
    var appConfig = {};
    appConfig.appID = appId;
    appConfig.isForSMP = true;
    appConfig.certificate = "";
    //appConfig.certificate = "";  //iOS
    //appConfig.certificate = "";  //iOS
    var context2 = {};
    context2.smpConfig = context;
    context2.appConfig = appConfig;
    context2.operation = operation;
    var appDelegate = { 
        onRegistrationSuccess: logonSuccessCallback,
        onRegistrationError: logonErrorCallback,
  • Comment out the sap.Logon.init method and replace it with the following code.
    operation.logonView = sap.logon.LogonJsView;
    sap.Logon.startLogonInit(context2, appDelegate);
  • Run the app and notice that the user is prompted to select a certificate to be used for the registration.

  • One way to add the certificate to an iOS device or simulator is to rename the certificate to have an extension of fccert. On the device, if such a file is opened perhaps via a link from mobile Safari or from an email, it will open the Kapsel app that contains the plugin kapsel-plugin-keychaincertprovider and will add the certificate to the app’s keychain.
  • Note that on iOS the certificate gets added to the keychain of the app and will persist even if the app is uninstalled. To delete the certificate the following method can be called which will also delete the registration.

Registering using an X.509 Certificate on Android with SAP Cloud Platform Mobile Services(SP16+)

The steps are the same as above except the Management Cockpit of the SAP Cloud Platform Mobile Services has a different UI and an additional step to upload the CA is required.

  • Configure the app to use the Certificate Authentication provider.
  • Configure the server to trust certificates signed by the certificate authority that signed the user certificates.
    Download the Neo Environment SDK from SAP Cloud Platform Neo Environment SDK.
    For additional details see the following links.
    Configuring X.509 Certificate Authentication

        keytool -import -trustcacerts -alias sapsso -file c:\certs\SSO_CA.cer -keystore hcpms_trusted_ca.jks
        neo.bat upload-keystore --account i8XXXXtrial --application sapmobile:hcpms --user i82XXXX --location ./hcpms_trusted_ca.jks --host

    Note above that the application name should not be changed as this is the name of the SAP Cloud Platform Mobile Service.

  • Modify the serverContext.js file and change the serverHost to use the new domain for the application.

Multi User (SP14+)

Implemented on iOS and Windows only.
Android has multi user built-in to the Android OS via Settings -> Users.
To try it out, follow the instructions below.

  • Uncomment the line “multiUser”: true in the context object in serverContext.js
    Ensure that the disablePasscode option is either not present or set to false.
    Ensure that the option useLocalStorage is either not present or set to false.
  • Add the following code to the start of the JavaScript code in index.html just below the line var resumeTime = null;
    var appConfig = {};
    appConfig.appID = appId;
    appConfig.isForSMP = true;
    var operation = {};
    var context2 = {};
    context2.smpConfig = context;
    context2.appConfig = appConfig;
    context2.operation = operation;
    var appDelegate = {
        onRegistrationSuccess: logonSuccessCallback,
        onRegistrationError: logonErrorCallback,
  • Comment out the sap.Logon.init method and replace it with the following code:
    operation.logonView = sap.logon.LogonJsView;
    sap.Logon.startLogonInit(context2, appDelegate);
  • Add the following method:
    function signOutSuccessCallback() {
        unlock();  //shows the pick user screen
  • Add in a new button to enable the sign out.
    <button id="signOut" onclick="sap.logon.Core.deactivateCurrentUser(signOutSuccessCallback, errorCallback)">Sign Out</button>
  • Delete the app from the device or emulator before redeploying.

Previous   Home   Next

You must be Logged on to comment or reply to a post.
  • Hello Daniel,

    I got some problems when I create an ios project and add the logon plugin follow the Registering using the Logon Plugin.I run the project in xcode8,it throw an error Terminating app due to uncaught exception 'DataVaultException', reason: 'Does Not Exist’.Could you give me some suggestions to solve this problem?

    the cordova version is 6.1.1,kapsel version is 13.

    Thanks & regards

  • Hi Daniel,


    I'm following your documents on Kapsel Development, Thanks for sharing it, Very useful.


    Currently stuck with below issue.

    I've created a Kapsel SAPUI5 offline app using WebIDE and HAT connectors and It's working without any challenges, But now Login Screen is Standard with SAP Logo and text, I want to customize it and add Logo/Background Images and also hide few fields.

    Few questions here, Adding Context code as You mentioned in your Post under section Customizing the Logon Plugin’s UI is enough? And where exactly we need to add this code, It's in LogonController.js file? I tried adding it in Firevent Function of LogonController.js but it always gives blank screen.

    Thanks for your help.



    Abhishek Wajge



    • Searching through the generated hybrid project in c:\users\user_name\saphybrid\project_name\hybrid\www\mobile.json there appears to be a context object which I assume you could specify the customization options to.

      There also appears to be a Logon Options section in the Web IDE under the Project Settings, Hybrid App Configuration section where it looks like you could hide fields, hide the copyright and logo and add your own background.

      I imagine that the above section controls what appears in that file.


      Dan van Leeuwen




  • Hi Colleagues,

    I'm trying to register on the HCPMS server using the Logon plugin. There are two versions of my application: without crosswalk plugin and with the crosswalk.

    So the version without installed crosswalk works perfect, and I'm connected to the HCPMS, but the same code with crosswalk plugin trigger an error:


    Logon plugin version 3.15.0

    Android 4.4.2

    Cordova 6.5.0


    have somebody faced with the issue?


    Best Regards,


  • Hi Daniel,

    Thank you for the wonderful blog! In the overview, you had commented that the ability to customize the Logon plugin screens have been changed. We used the option provided in SP09 to skip the registration screens, and used the context parameters to set the necessary values. Is it still possible to achieve this in the latest versions?

    Also, what we are aiming is to bring our own manage passcode, or enter passcode screens instead of the standard Logon screens, such that we can pass, the new and old passcode as parameters to the sap.Logon.managePasscode call. Or if we can update the logonView.onShowScreen at runtime, after the Logon.init has already been called.

    The idea is to set the passcode, same as the user’s password, instead of skipping it, through which we can utilize the fingerprint authentication as well.

    Looking forward to hear from you.

    Vigil George

    • I believe the recommended approach is to use the provided Logon screens especially now that they are more easily customizable.

      Dan van Leeuwen

  • Hi, Great blog! Things are working great with Kapsel plugins for me.

    I am only struggling with Multi-User support on Android.

    What do you mean by "Android has multi user built in to the Android OS via Settings -> Users."?

    Which is the way to accomplish it?


    Thank you!


    • Thanks for the comment on the blog.

      Regarding multi-user on Android, instead of having the app support multiple users, the Android OS has multi user built into the OS.

      Hope that helps,

      Dan van Leeuwen


      • Thanks! That's a good option, but my Android version does not allow that feature by default.

        Also, In my case, I am developing an app which needs to display different information according to the user that is logged in. In other words, I need the app to get the user id/name so that the underlying oData is able to filter and deliver the correct data (and not all of it).

        Do you know another workaround or have some other suggestion as regards this requirement?


        Thank you again for your time!


        • You should be able to get the user name from the context.  I believe the Logon sample in this section accesses it via applicationContext.registrationContext.user.  If you are using another authentication method such as SAML or OAuth in which case the Kapsel app does not process the user name, there is an example that requests the user name from the settings plugin.  Search for sap.Settings.getConfigProperty in

          I would do some early prototyping.  One issue to consider is what happens if user1 has made changes but did not flush them before user2 starts using the app.  Does it matter if user2 sends user1s changes to the backend?  The autoFlush which attempts to flush any changes in the background might be helpful.  I believe it requires the latest PL for SP14.  It is documented at


          Dan van Leeuwen

          • Thanks! I managed to develop the requirement by getting the username the way you did and then passing it to the devapp to create a filter in the master controller. A bit messy that this logic resides in the application but a simple way to do it, though.


            Now struggling with the logout logic.

            Thank you so much Daniel for your dedicated answers. They were really helpful.



  • Hello,


    I see that It was possible to skip the login screen in Kapsel application ( but I'm on SP15 and I don't see how appy the same way.

    Could you explain how did that in SP15? Or how it's possible to hard-code user and password in the field?

    Thank's a lot for your help



    • The previous method may still work but it is not recommended as you have to change the Kapsel plugin JavaScript files which can be a pain as those changes have to be redone with each update.

      One new feature in SP 15 is the ability for the Logon plugin to remember the user's name and password for other forms of authentication such as SAML or OAuth or form based basic authentication.  This setting can be enabled with allowSavingFormCredentials.  There are more details including an example of it at


      The AuthProxy plugin with the Logon plugin will automatically send the previously saved user name and password when using basic authentication.  In this case the user will login once the first time they open the app and then will not see a login screen again while their user name and password are valid.  There are more details on this at


      Hope that helps,

      Dan van Leeuwen

  • Hello, great blog so far!

    I have a question regarding the password change process. We are not working with the mobile platform. Instead we connected the logon directly to a SAP Gateway. The login process itself works like expected and after this process, our SAP UI5 application will be loaded into the mainScreen. But our customers have to change their passwords every 60 days because of our policy. If they did not change it, they'll get a new initial password. The problem is, there is no password change screen or something similar like in the 'Launchpad' or in 'SAP GUI' that triggers the  customer to change the initial password.


    Did i missed something in general or is it not possible from within the logon plugin?

    Do you know how i can handle that?


    Thank you!

    Kind regards,


  • Hello,

    Thanks for the blog Daniel Van Leeuwen, it’s really useful! I have a case where we’d like to use the logon plugin against a Gateway. What are the options to do so? Is the multi user supported?  I did the basic authentification which consists in passing the user/pwd in the header.

    In general, any extra information on that topic would be highly appreciated.


    Aurélien Albert



    Thanks for your very helpful blog.  I'm trying to hide some fields on the logon screen.  I created a serverContext.js file and copied in the initial code used in your example above, and then placed the file in the app's WWW folder.  Then I modified the appId value to match my app's app ID.  I then did a prepare/build on the app and just tried it out to see if it changed the login screen any at all.  I expected it to at least hide some of the fields since your example code for this file specifies to hide fields such as the serverPort and https fields.  However it didn't have any affect at all - the app still used the same out-of-the-box login screen that it always uses.  Am I missing something?


    Thank you!

    Tim Sheppard

    • One thing that can sometimes trip people up is to remember to edit the files in the root www folder and then to run a cordova prepare or cordova run which will copy those changes to the platform specific www folder.  The only other thing that comes to mind is if you have a really old version of the SDK.  I am assuming you are on the current release with is 3.0 SP 15.  The version can be seen by examining one of the plugin.xml files such as C:\SAP\MobileSDK3\KapselSDK\plugins\logon\plugin.xml



        I verified that I'm editing the serverContext.js file in the root www folder and it is getting copied to the iOS specific platform folder when I run the prepare.

        To get the SDK version for the Kapsel plugins you should be able to do cmd "cordova plugins" at the command line, correct?  Based on that the SDK version is 3.0 SP14 PL2. Since this blog post applies to SP13+ I'm assuming my SDK version is ok.

        Thanks for your help

        • SP 14 should be fine.  I believe the current version is now SP 16.  Have you tried with the example shown above or with your own project perhaps created with the Hybrid App Toolkit?

          If you are having troubles with the sample, perhaps share it and I can take a look.  What I would look at is the call to sap.Logon.init in the WebInspector and verify the context object contains your customizations.

          Note I am currently on vacation so if this is urgent, perhaps open a ticket with support.


          Dan van Leeuwen



            Your advice allowed me to figure out the problem.  I wasn't including serverContext.js in my <script> tag so my customizations were never being included in the context object.  Thanks for your help!


  • Hi,

    Thanks for your extremely useful blog Daniel Van Leeuwen. Now, I am able to implement logon plugin, but I am facing one issue related to 'Forgot Passcode' functionality. Forgot Passcode is working fine with iOS, it also deleting the user registration id from SMP, but its not working with Android. After clicking on 'Forgot Passcode' in Android, user registration is not being deleted from SMP, can you please help.




    • Glad the blog post has been useful.

      I gave this a quick try.  The steps I followed were to

      register and enable the passcode screen

      remove the app from memory

      open the app

      click on forgot passcode

      In both cases the registration in the server remained.

      I believe this makes sense as the delete request would require the users credentials to be successful.  The users credentials are stored in the datavault which needs the correct passcode to be accessed.

      I believe there is a setting in server called Automatic Removal where one can specify how long an unused registration should remain before the server automatically deletes it.
      I see it mentioned in this blog post.  Perhaps this would be of use?


      Dan van Leeuwen

      • Thanks Daniel for the reply.

        I have this query due to the different behavior of Kapsel Logon Plugin for iOS & Android as SMP Registration ID is automatically deleted after clicking on Forgot Passcode in iOS, but its not being deleted in Android.




  • Hi Daniel,

    I have subscribed to the SCP with a trial account only a few days back to try out the logon and push plugins against the SCP Mobile Service just as I was doing it with the On-Premise SMP. I see that the SMP Cockpit is totally different on the SCP than what it was with the On-Premise.

    I do not see the option to specify a custom security profile (I was using the HTTP/HTTPS Auth provider). Also do not see the Notification profile for Push user/role configuration.

    Could you please guide me though the new way of achieving these things on the SCP Mobile Service Cockpit ?




  • Hi ?

    Thank you for the amazing blog post !

    When trying to install the Logon plugin, it gives me the following error: Failed to install ‘kapsel-plugin-corelibs’: Error: ENOENT: no such file or directory, open ‘C:\Users\myname\Documents\Kapsel_Projects\KapselGSDemo\platforms\android\AndroidManifest.xml’

    My Specifications are: Cordova-android: 7.0.0 / Cordova 8.0.0 / Node.js 8.11.1 / npm 4.6.1 and SMP

    I tried to downgrade to Cordova 6.1.1 as recommended is Part 1, but I got another error: Plugin doesn’t support this project’s cordova-android version. cordova-android: 6.1.1, failed version requirement: >=6.1.2 Skipping ‘kapsel-plugin-logon’ for android.

    Could you please provide me some hint of what I am doing wrong?



  • Hi Daniel,

    Is it also possible with the "custom - hidden fields'" of the context, to remove the "cancel" buton? Or do we need to do this in another way?

    "custom": { "hiddenFields": ["farmId", "resourcePath", "securityConfig", "serverPort", "https", ...? ] }


    • That doesn't appear in the list of items that can currently be customized.

      Customizing the Registration Screen

      Perhaps you could make a request for this further describing your use case.


      A temporary workaround would be to  make the change directly to the Kapsel logon plugin at


      The downside to this is that you would need to remember to remake this change each time you upgrade.


      Dan van Leeuwen


  • Kapsel Logon Plugin not working for https on non-standard port other than 443


    Hi Dan

    We have a hybrid cordova application in development on iOS platform which will connect to SMP as it’s first point of contact over a VPN tunnel, and post registration it is intended to use Fiori as backend to serve content.

    What we have noticed is the following:

    • HTTP connection with SMP works for any port
    • HTTPS connection with SMP is only successful for port 443.

    My question is: is this intended that HTTPS is only meant to work for 443 ONLY for SMP when the kapsel logon plugin connects to the backend?

    What would it take for us to ensure that kapsel logon plugin works with any non-standard https port.

    Our environment is as follows:

    • Cordova v8.1.2 with iOS platform  @ 4.5.5
    • Kapsel Logon plugin v4.0.2
    • SMP v3.0.14.6 Build 20180831-0055


    More information:

    Our investigation has led us to believe that for all non-standard ports for https, the application ends up sending multiple SSL handshake requests, and doesn’t really wait for a completed handshake to initiate the data transmission on a connected session. Even when one of the sessions is established, the subsequent SSL handshake requests the application sends – the server cancels the previously established ssl handshake sessions.

    • Here are some things that I would investigate.

      Is the certificate for the 443 port the same as the one used on the non 443 port?  Note, I don't believe self signed certificates are supported.

      Does this setup work on Android?

      What sort of error messages are in the log file?

      Does it behave differently without going through the VPN?

      Dan van Leeuwen


  • Hi Daniel,

    I created a Windows UI5 offline app with basic authentication with SCPms.

    I know there’s a timeout after 20 minutes in SCPms. I noticed that I get sometimes when I trigger an event to the server, that an authentication popup appears for logging in again.

    Do you know how I can catch this event (that triggers the authentication popup), so we can show the basic login screen again?

    Edit: added screenshot

    best regards,

    • I believe the Logon plugin in combination with AuthProxy plugin will store your credentials to the Mobile Services server when you perform the initial registration.  After that, the user should not have to reenter those credentials when accessing the same URL unless the user's password has changed.

      Is the app communicating to different URL's?

      Are there any messages in the log around the time that the authentication dialog is seen?


      Dan van Leeuwen

    • Hi Hans,

      This event cannot be caught from Kapsel side as it is coming from a lower operating system level. In the offline OData plugin this user credentials window is allowed and you cannot turn it off.

      Could you try to click on the Cancel button and see what happens then?



  • No, only 1 destination (URL) is used to the server.

    Only adding the AuthProxy plugin is enough? or do we need to do something extra with this?

    At this moment, we don't see antything extra in the log, but we'll keep an eye on this!


    • The LogonPlugin depends on the AuthProxy plugin so I would imagine if you check the plugins in your project, you will find it.

      I would recommend opening a case with support if you can create a project that support can repro the issue with.


      Dan van Leeuwen

  • Hi, Daniel Van. Hi people!
    I have a error, but I don’t know what happened. Network communication error. 

    in debbung tool console :

    iab.html showNotification() called, notificationKey: ERR_REG_FAILED_NETWORK_IO

    I have a SMP RT SP16 running Service On.
    I have SMP SDK SP16 and compile a android cordova project, following sample for Logon Kapsel with same index.html.
    I testing over a Samsung Galaxy Tab Active with Android 8.1.
    Final subject is upgrade  an app compiled for a android 4.4, this is working in SMP SP05 actually.

    not firewall active, ports is open,

    test of service odata in smp server from web browser in android tablet and this works!!!$metadata


      • Hi Daniel. thank for fast response!!!

        Now I using not secure port, 8081.

        Is mandatory https? in past app, worked without this.

        When check htpps then I get this message.

        "Server certificate failed valitadion"

        • I assume it is using HTTPS based on the URL provided above.

          Can you open that URL in Chrome on your desktop?  Is the server certificate signed by a certificate authority trusted by the Android device and your desktop?  In Chrome I believe you can press F12 to open the developer tools and there should be a tab for security where you can find more details.


          Dan van Leeuwen

          • No, is a server with a self signed certificate.

            Can you open that URL in Chrome on your desktop?   yes!

            Is the server certificate signed by a certificate authority ? No.

          • I believe the issue is related to the signing of the server certificate.  In Chrome, when you entered the URL and pressed F12 and switched to the security tab, did the security overview provide some warnings or information indicating a problem with the certificate?  I believe there also might be services to check the validity of a server certificate assuming it can be reached from the internet.  I found this one.

            Also, this older blog post might also be of some help.




            Dan van Leeuwen


          • Hi Daniel !!!

            Hi, People.
            I still have a problem with the app.
            I would like to send you a .apk that you can try with your system. I will compile it with appID = “” and try it to see if you have the same problem “Network communication error”. This app will be created only by adding the kepsel-plugin-logon on android platform. SDK Kapsel SP16, Cordova 7.0.
            The goal is help me rule out if it is my developer SMP SP16 server that does not respond properly or is the app.

            I leave the link to download the app from google drive.
            project creation log, index.html file and serverConfig.js
            and the Android APK.

          • I was able to use your app to onboard to my SAP Cloud Platform server.  One other way for you to validate this is a certificate issue would be to use port 8080 which I think is the non HTTPS port on the SAP Mobile Platform server.

            Once you do get past the registration issue, I think you will notice that the Read button is not working.  I think this is because the following file isn't included in your app.


            Dan van Leeuwen

          • Hi Daniel, Thank you… then, is my architecture or developer server or any other thing the cause.
            I even compiled the other app with sdk sp13 version and the same error appeared but with another message text “Please check your connection data.”.
            Which other tools could be help me discover what is happening?


            "Once you do get past the registration issue, I think you will notice that the Read button is not working.  I think this is because the following file isn’t included in your app.

            yes, I only want test the registration.

          • From the screenshot above, you can see that Chrome says the connection is not safe.  No es seguro.

            When using HTTPS it is important to use the fully qualified host name as that will be the name on the server's certificate.

            I wouldn't expect that or any other ip address would work on the registration screen to connect on an HTTPS port.

            I would recommend reviewing this content.

            Dan van Leeuwen

  • Hi Daniel,


    When our application (Hybrid Android app, with kapsel plugins (logon, offline, ...) remains open, we notice that after a while, our sync will fail, because of following error:

    -0.04 s
    Offline Completed MobiLink adapter request. APPCID: 08002271-65be-42e2-bfec-c0a0998a9021 , requestURI: /MobiLink/ServletAsync, requestMethod: POST, responseStatus: 200 time since handoff(ms): 59
    -0.006 s
    Proxy An Unexpected Exception occurred during the back-end request: Unexpected error while trying to retrieve logged-in user.
    0 s
    Offline Finished a delta download for an Offline OData client.
    0 s
    Offline Delta download for an Offline OData client failed.
    0 s
    Offline Retrieve metadata failed because the OData server returned HTTP code, 500, with message: null

    It seems that the OData server has an internal server error, but we don't see anything in the Gateway logs, traces, .... So it seems that the connection between SCP & our backend failed.

    I'm not sure, this is a login issue, or an offline issue.

    We've following error message from our application:

    [-10210] The operation failed due to an error on the server: -857 (SERVER_SYNCHRONIZATION_ERROR) ([-10225] Message: User exception: [-100025] An error occurred while communicating with the OData server to retrieve the result of request "$metadata".
    Error caused by: [-100010] Retrieve metadata failed because the OData server returned HTTP code, 500, with message: null) [-10210] The operation failed due to an error on the server: -857 (SERVER_SYNCHRONIZATION_ERROR) ([-10225] Message: User exception: [-100025] An error occurred while communicating with the OData server to retrieve the result of request "$metadata".
    Error caused by: [-100010] Retrieve metadata failed because the OData server returned HTTP code, 500, with message: null)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(
    at java.util.concurrent.ThreadPoolExecutor$

    Any idea what this could trigger?