Authenticating a consumer for access to SAP Business ByDesign depends on the concrete way chosen and them used technology. The following example shows how to login to ByDesign – with username and password – with JavaScript.

JavaScript does not allow unrestricted cross site calls. If you execute your script somewhere, the application can talk to the server it was started on (SCP account, some server, localhost), but it cannot call other systems.

This is for security reasons.

For testing purposes, you can disable security in some browsers, e.g. in Google Chrome. You can do this by closing all open Google Chrome instances and starting it from the command line (e.g. Win+R) with

chrome.exe –disable-web-security –user-data-dir=c:\temp .

Cookies should be allowed.

If you host your application on the SAP Cloud Platform, you can use destinations to access your system conveniently.

var sHost = "https://YOUR_SERVER";
var sUser = "USERNAME";
var sPassword = "PASSWORD";

var sGetTokenModulePath = sHost + "/sap/ap/ui/login";
var sUrl, sXsrfToken;

function fMain(sXsrfToken) {
  // process app (main,...)
}

function handleLoginResponse(body) {
// If no redirect is needed this code is being executed
  alert("Handle login reps");
  if (!body.login) {
    alert("Login failed");

  } else {
    if (fMain) {
      fMain(); // Remote, login is done using form based login
    }
  }
}

function handleTokenReceived(data, textStatus, XMLHttpRequest) {
  var oResponseParameters = new Object();
  oResponseParameters.sysinfo = new Object();
  sXsrfToken = XMLHttpRequest.getResponseHeader("sap-xsrf"); 
  sURL = sHost;

  // Check if already authenticated
  if (XMLHttpRequest.responseText.indexOf("state=authenticated") === -1) {

    // not authenticated, login
    var xmlDoc = $.parseXML(XMLHttpRequest.responseText);

    $(xmlDoc).find("Data").each(function() {
      $(this).find("Element").each(function() {
        oResponseParameters.sysinfo[$(this).attr("name")] =
        $(this).attr("value");
      });
    });
    var sXsrfToken = oResponseParameters.sysinfo["sap-login-XSRF"];
    $.ajax({
      url: sGetTokenModulePath,
      type: "POST",
      dataType: "json",
      data: {
        "sap-alias": sUser,
        "sap-password": sPassword,
        "sap-login-XSRF": sXsrfToken
      },
      beforeSend: function(xhr) {
        xhr.setRequestHeader("x-sap-request-xsrf", "X");
      },
      success: handleLoginResponse,
      error: function(jqXHR, textStatus, errorThrown) {
        // error callback, also called when response is not in JSON format...
        if (fMain) {
          fMain(sXsrfToken); // Remote, form based login
        }
      }
    });
  } else { // authenticated, call app main
    fMain(sXsrfToken);
  }
}

function doLogin() {
  $.ajax({
    url: sGetTokenModulePath,
    type: "POST",
    beforeSend: function(xhr) {
      xhr.setRequestHeader("x-sap-request-xsrf", "X");
    },
    success: handleTokenReceived,
    error: function(jqXHR, textStatus, errorThrown) {
      alert("Get Login Token call failed");
    }
  });
}

It starts at doLogin().

  • A POST call with set header x-sap-request-xsrf is issued to fetch the CSRF protection token.
    • If it cannot be received, the script ends with an error message.
    • Otherwise handleTokenReceived() is executed. This checks, if the consumer is already logged in.
      • If the consumer is logged in, it just calls the main function fMain() that would realize the real app functionality. The security token is passed in, as it has to be supplied with every call that changes data in the system.
      • If the consumer is not yet logged in, the security token is extracted from the returned document, and a POST call to the login URL is executed, supplying username and password, secured by the just extracted security token.
        • If this fails the script exits with an error message.
        • Otherwise, the consumer is logged in, and the main function fMain() is executed.

If login issues occur during local testing, it is often either active security functionality or rejected cookies.

To report this post you need to login first.

13 Comments

You must be Logged on to comment or reply to a post.

  1. Oscar Espinar Lázaro

    Hi Thomas,

    Thanks so much for your blog series about HCP and ByD.

    This is a very useful docs for ones we want to develop HCP Mobile Apps using ByDesign as Backend.

    I was wondering if there is a way to read ByDesign Work Centers and Access Restriction assigned to the Identity used to login from your JavaScript sample.

    After a research I couldn’t find any Business Object in the repository with this information. I don’t know if this information could be exposed also as an oData Service.

    Thanks so much and regards,

    Óscar Espinar Lázaro

    (1) 
  2. Thomas Salvador Post author

    Hi Oscar,

    thanks for your kind feedback, and Kudos for identifying the report. It is *the* best way I know for getting this information.

    I do not think there is a Business Object exposing it in a PSM released way – at leased I have not found any in the last days.

    Thanks and regards,

    Thomas Salvador.

     

    (1) 
  3. Oscar Espinar Lázaro

    Hi Thomas,

    I was wondering if there is a url to force the logging of Bydesign.

    I’ve tried something like this:

    $.ajax({
       url: "/sap/public/ap/ui/runtime",
       type: "POST",
       dataType: "json",
       data: {
    	"logoff":  "1"
       },
       success: function(body) {
       // do something	      				
       },
       error: function(jqXHR, textStatus, errorThrown) {
       // do something	 
       }
    });

     

    But always get “Method Not Allowed” into «errorThrown» error var.

    If I try this from Postman (after LoginIn) I get the standard ByDesign after logoff screen.

    Any idea?

    Thanks so much for your time and regards,

    Óscar Espinar Lázaro

    (0) 
  4. Oscar Espinar Lázaro

    Thanks Thomas,

    Finally I’m using GET with this url “/sap/ap/ui/runtime”.

    The result now is “success” and in the body I’m getting the Login screen instead Reset Application screen. At the same time, the authentication still continue, so no Logoff is done.

    Spying logoff button in ByD, I see these headers in /sap/public/ap/ui/runtime?logoff=1 GET call:

    Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Accept-Encoding:gzip, deflate, sdch, br
    Accept-Language:en,es;q=0.8,en-US;q=0.6
    Connection:keep-alive
    Cookie:sap-usercontext=sap-language=EN&sap-client=227; MYSAPSSO2=AjQxMDMBABhLADgAWgBBAFIAVwBUADUANwA1AEQAIAACAAYyADIANwADABBMAEIAWQAgACAAIAAgACAABAAYMgAwADEANwAwADUAMAA1ADIAMQAxADYABQAEAAAACAYAAlgACQACRQD%2fAPowgfcGCSqGSIb3DQEHAqCB6TCB5gIBATELMAkGBSsOAwIaBQAwCwYJKoZIhvcNAQcBMYHGMIHDAgEBMBkwDjEMMAoGA1UEAxMDTEJZAgcgFBIVFDAnMAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNzA1MDUyMTE2MjlaMCMGCSqGSIb3DQEJBDEWBBTDu5CVWSVL1wLir6aNYiTe48HtPzAJBgcqhkjOOAQDBC4wLAIUQIo%21IzbAkWdec3oK5RGrnGYoCOoCFFaNsPs0SR4IOR15A2i%21h7RJZ1F8; SAP_SESSIONID_LBY_227=gNfXJjS4KOT0DsJ1T2uDahsU3ZMx2BHnv4UAFj4SO0w%3d; sap_c4c_logon_record=00163E123B4C1EE78CBB0365EBE2BF85; saplbLBY=vaai02lby_LBY_00
    Host:myxxxxxx.sapbydesign.com
    Referer:https://myxxxxxx.sapbydesign.com/sap/public/ap/ui/repository/SAP_UI/HTMLOBERON5/client.html?client_type=html&app.component=/SAP_UI_CT/Main/root.uiccwoc&rootWindow=X&redirectUrl=/sap/public/ap/ui/runtime
    Upgrade-Insecure-Requests:1
    User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36

    Maybe Cookie header is the key to logoff from ByD but I don’t know how to get this value (not included in the original login response).

    Do you have more information about logoff process?

    Thanks so much for your kind response,

    Óscar Espinar Lázaro

    (0) 
  5. Thomas Salvador Post author

    Hi Oscar,

    I think, you first have to do a POST to ap/ui/json to close the session, then do the GET to ap/ui/runtime to logout.

    Something like this:

    $.ajax({
      url: "/sap/public/ap/ui/json",
      type: "POST",
      dataType: "json",
      data: {
        "sessionclose": "X"
      },
      success: function(body) {
        $.ajax({
          url: "/sap/public/ap/ui/runtime",
          type: "GET",
          dataType: "json",
          data: {
            "logoff": "1"
          },
          success: function(body) {
          // do something 
          },
          error: function(jqXHR, textStatus, errorThrown) {
          // do something 
          }
        });
      },
      error: function(jqXHR, textStatus, errorThrown) {
      // do something 
      }
    });

    If this alone does not work, it might really be the cookies. ByD logout clears a couple of them on logout. Maybe you could then try to replicate that.

    The value you see as Cookie there is available to JavaScript in document.cookie

    But please note, that this value contains all the cookies, separated by semicolon, so you have a sap-usercontext cookie, a sap_c4c_logon_record cookie, an so on.

    It is in the form ‘name1=value1;name2=value2;…’

    it should be sufficient to assign new values to clear these, and ideally, set expires to the past and path to root, like

    document.cookie = ‘sap_c4c_logon_record=; SAP_SESSIONID_LBY_227=0;….; expires=Tue, 01-Jan-1980 00:00:01 GMT; path=/’ // and so on

    Thanks and regards,
    Thomas Salvador.

    (0) 
  6. Oscar Espinar Lázaro

    Hi Thomas,

    Thanks again for your response.

    After a lot of tests I have not been able to disconnect from ByD.

    Let me show you the problems I found:

    1.- Implementing the above code, it’s working in a strange way. Only the first call ( to /json or /runtime url) works. For the second one always receive a error message:

    “Method Not Allowed”

    “<html><head><title>Error report</title></head><body><h1>HTTP Status 405 – Bad Method</h1></body></html>”.

    2.- I’ve tried to call only /runtime method because in the response, I get a new “sap-login-XSRF” value. I’ve saved and used to login again, but ByD continue logged with the same user.

    3.- Following your advice about cookies, I found that the is no cookies from ByDesign ( document.cookie is empty). Reviewing application cookies on the browser, I see that there is no difference before or after being connected to ByD. This make me think that, using HCPms, there is a kind of proxy which is saving this stuff. Not sure but I think the problem with logoff could be related.

    Thanks so much and best regards,

    Óscar Espinar Lázaro

    (0) 
  7. Oscar Espinar Lázaro

    Hi Thomas,

    Finally I could fix the point 1 (it was a issue with HCP and HCPms destinations) so I’m using your code as you write it, with success in both calls.

    Unfortunately, the logged ByD user is still alive.

    «document.cookie» continue empty, so my resources seem almost finished.

    Thanks again and regards,

    Óscar

    (0) 
  8. Thomas Salvador Post author

    Hi Oscar,

    I do not understand, why your document.cookie is empty. If I add an

    alert(document.cookie);

    to the success callback, I get the alert popup with the expected cookies. (?)

     

    I found

    $.get('/sap/public/ap/ui/runtime?logoff=1');

    to be working for me. A reload of the base URL afterwards gives me the login page. Turns out, that it does the logout for me without this sessionclose step.

    The real difference seems to be, that I do not use JSON: Hence adapting your code would result in just

    $.ajax({ 
      url: "/sap/public/ap/ui/runtime?logoff=1", 
      type: "GET",
      success: function(){alert('ok')}
    });

    Thanks and regards,

    Thomas Salvador.

    (0) 
  9. Oscar Espinar Lázaro

    Hi Thomas.

    I tested your code in a standalone application and it’s working perfectly.The same code (with some small changes) in my Kapsel App does not work, so I am totally convinced that the problem is in HCP and HCPms.

    The document.cookie is empty in the mobile application, so I am pretty sure that the connection is maintained in HCP. And even though the logoff request is being sent correctly (in fact, it always returns successfully state) HCP is not disconnected from ByD.

    I’ll try to find some light in this black hole that is HCP.

    Thanks for your time and expertise.

    Regards,

    Óscar Espinar Lázaro.

    (0) 
  10. Thomas Salvador Post author

    Hi Oscar,

    Maybe I am misunderstanding, but I would think, it depends on the concrete destination setup.

    For example, if I maintain a destination, I set an authentication strategy, like basic authentication with this ‘username’ and that ‘password’.

    The authentication itself is then transparent. If the destination is used, the user is logged into ByDesign authenticated as this ‘username’. HCP did it.

    In such a case, one can (in my opinion) not log out, because even, if the current session would end, using the destination again would re-log-in one anyway. Therefore one would need to logoff and then disable the destination. I do not think, this is possible, as it would effect all users of the destination.

    How do you use the destination?

     

    Thanks and regards,

    Thomas Salvador.

    (0) 
  11. Oscar Espinar Lázaro

    Hi Thomas,

    Let me tell you about my scenario.

    The App consumes two services form ByDesign: one is a Custom oData Service and the other is a report also exposed as oData service.  In HCP and HCPms I have defined two destinations authenticated with a “general” ByDesign user. It’s working fine.

     

    But the App should display data depending of a ByDesign user. So the first screen in the App (after HCP Logon Manager) is a standard form asking for UserId and Password. Using this form data, I check if user exists in ByDesign (using your login code) I get the authorizations (Workcenters, assigned Companies, etc.). The App only manages data assigned to logged user.

    After the user has finished the work (this is a warehouse App), should logoff from ByDesign in order that another user can use the same device and App and connect with his own ByDesign user.

    So, in order to login and logout from ByDesign, I’ve defined another three destination without any authentication.

     

    Except for the logoff issue, everything else is working fine.

    Thanks and best regards,

    Óscar Espinar Lázaro

    (0) 

Leave a Reply