Skip to Content
Author's profile photo Volker Buzek

Make CORS work with Gateway and Chrome for local development

Or as the subtitle could also read: Overcoming “Access-Control-Allow-Origin”- errors

Setup in this example is:

  • development machine with local (web) server running a WebApp from http://localhost:12345
  • Gateway server accessible under a different domain than the local development machine, such as
  • need to consume services onGateway server, originating from local machine => Cross-Domain Request!

There’s a lot written out there why Cross-Domain read requests (not write requests!) aren’t a good idea. They generally open up data transfer possibilities between domains. Which is something you don’t necessarily want – for production environments, that is. What you should also never cater to – use a proxy-based approach to consolidate data read access under one domain, either software-based or with middleware.

But what about development?

There are legitimate reasons to read data across domains in development scenarios. Not the least is if you want to work with features offered by SAP Gateway – accessing SAP Backend logic that is exposed via OData Services. Which means issuing cross-domain REST requests from your development machine to a Gateway instance. If you don’t have Gateway running on your development machine. Which is unlikely. So here we are…

The good and the caveat – SOP

First of all, in the Web’s overall architecture, there’s SOP or Same-Origin-Policy:

[It] restricts how a document or script
loaded from one origin can interact
with a resource from another origin.

Origin here means the combination of protocol (e.g. http), FQDN (e.g. and port (e.g. 80). So is considered an origin – so would http://localhost:12345.

And “can interact” in the quote above should be read as “scripts running from one origin are generally forbidden to interact with scripts from another origin”. (Does that mean you can’t include content from different sites? No! Read on…)

The client side

Stir in some OData- and Gateway-spice and it adds up to the following:

The user agent (e.g. Firefox) is rendering the WebApp from origin1, let’s say running on your development machine at http://localhost:12345/.

Now, if the WebApp is trying to retrieve JSON or XML via OData from, the user agent will send anXMLHttpRequest cannot load-error and block the request:

XMLHttpRequest cannot load
No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
Origin ‘http://localhost:12345/ is therefore not allowed access.

This is due to SOP being implemented in all major user agents: the scripts in the WebApp are forbidden to consume resources from origins other than (in our example) http://localhost:12345/. Retrieving OData from the same origin such as http://localhost:12345/the/odata/endpoint would be allowed, retrieving is not.

Note that we’re talking run-time and client-side here. SOP doesn’t apply to including JavaScript-files per se, it applies to the run-time interpretation of the script itself. So if you include JS-files via the <script>-tag, (e.g. <script src=”“>), the JS-file will be downloaded from the remote address first. Then it will run from your origin, being interpreted by a user agent – that’s the moment that SOP restrictions will apply, not earlier.

Disclaimer: SOP is generally a Good Thing(tm). In prevents scripts from origin A to read data from origin B and transfer it back to A.

Which is exactly what you’d like to do in development 🙂

Resolution: start-flag for Chrome

Google Chrome offers a way to turn off SOP.

If you start the binary with the switch –disable-web-security, SOP gets disabled, allowing client-side cross-domain requests.

E.g. on OS X:

    /Applications/Google\\ Chrome –disable-web-security

On Windows:

    “C:\Program Files (x86)\Google\Chrome\Application\chrome.exe” –disable-web-security

We’re half-way there – cross-domain requests are allowed on the client-side now.

The server side

Even though the client now allows requests across domain boundaries, the server still needs to grant access to those requests.

A standard way of doing this is utilizing CORS or Cross-Origin Resource Sharing on the server-side.

In essence, this means sending a an “Access-Control-Allow-Origin” header back to the client, authorizing the client’s domain – or granting general access with ‘*’.

Note: ‘*’-access is exactly what all the Northwind OData Test Services do. And what explains their popularity in example code.

Resolution: CORS with Gateway

Per default, Gateway send similar headers such as these:



Content-Type:”text/html; charset=utf-8″

Server:”SAP NetWeaver Application Server / ABAP 731″


sap-metadata-last-modified:”Tue, 08 Jul 2014 08:55:38 GMT”

In order to send an additional, custom header from a Gateway-service, use set_header from Interface /iwbep/if_mgw_conv_srv_runtime.

It takes a structure as argument, consisting of a key-value pair.

        ls            type ihttpnvp.
ls-name = 'Access-Control-Allow-Origin'.
ls-value = '*'.
/iwbep/if_mgw_conv_srv_runtime~set_header( is_header = ls ).

This will result in the desired CORS “Access-Control-Allow-Origin” header, granting all clients (“*”) read access:



Bringing all the above together means that by

  • using a switch to Google Chrome, you can get around SOP on the client side
  • sending the ‘Access-Control-Allow-Origin’ header from the Gateway-service allows CORS on the server side

And there you are, hopefully hacking away happily on your local machine, calling Gateway OData back and forth 🙂

For development purposes only – don’t unhinge these web security fundamentals just to make a quick transition into production scenarios, please!

tl;dr: Chrome –disable-web-security disables SOP, Gateway /iwbep/if_mgw_conv_srv_runtime~set_header allows CORS => developer happy

Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Paul Hardy
      Paul Hardy


      I like to think I am very conformatble inside SAP world but I have to admit to utter ignorance when it comes to terms like "starting a binary".

      In a Windows enviroment is the "disable web security" is this a setting you change when you open the Chrome internet browser, or something you have to run from the command prompt, or something utterly different yet again?

      Cheersy Cheers


      Author's profile photo Buzek Volker
      Buzek Volker
      Blog Post Author

      Hi Paul,

      the disable-web-security is a flag for starting Chrome - so you can e.g. add it to a Desktop Shortcut. You can't change that setting in about:config or such once the browser is running - the flag is valid for start-up only.

      hth, v.

      Author's profile photo Paul Hardy
      Paul Hardy


      That is a useful clue. I have a desktop shortcut for Google Chrome. I wonder if you could tell me whereabouts in the following screenshot do I put the "--disable-web-security"? I tried adding it at the end of "target" but it did not like that very much.

      Chrome Shortcut.PNG

      I appreciate this is probably obvious to most people!

      Cheersy Cheers


      Author's profile photo Prabaharan Asokan
      Prabaharan Asokan

      Hello Buzek,

      Good blog for developers.

      I would like to suggest some more content to the valuable contribution from you.

      Many Enterprise customers still use Interner Explorer as de facto standard. So we may need the same scenario above for IE.

      For Client side:

      You can set this in Internet Options: Go to the Security tab. For the current zone click the "Custom level..." button. In the next window, scroll about a third of the way down to "Miscellaneous > Access data sources across domains" and set it to "Enable". If the current zone is Internet, then you should add the site to the trusted and set this option for the trusted zone instead.

      Note that this will effectively disable CORS and will not set the Origin header in the request.




      Author's profile photo Tobias Trapp
      Tobias Trapp

      Hi Buzek,

      I like your blog 🙂 I have a question: have I to both on client an server side? I tried out the scenario and with Chrome and --disable-web-security everything is works - without and with Access-Control-Allow-Origin:


      You see that I set Access-Control-Allow-Origin, but without --disable-web-security the result is the following, although Access-Control-Allow-Origin is set:


      I use local Gateway with SAP_GWFND 7.40 SP 5. and the latest UI5 from

      Best Regards,


      Author's profile photo Buzek Volker
      Buzek Volker
      Blog Post Author

      Hi Tobias,

      if you run both the UI5 app and the OData endpoint on the same server, neither --disable-web-security (client) nor Access-Control-Allow-Origin (server) is needed - you're not violating the same domain policy. This is also the desired setup for production scenarios (often this means "proxying" the OData resource to the same domain as the UI5 app) and what you're experiencing if you're running everything against the same GW install.

      If UI5 app and OData endpoint are on different URIs (e.g. localhost:8000 and, both client-side and server-side tweaks are required to make the data provisioning work.

      HTH, Volker.

      PS: Guessing the cause of the error 500 withouth knowing more about your setup (URI, JS code, ...) is somewhat hard 😉

      Author's profile photo Paolo Romano
      Paolo Romano

      Hello Volker,

      got a question: I tried your server-side solution but I see no way to bypass the CORS check, e.g. the request seems not to arrive to my handler.

      There is some special arrangement? At which level should I put the access-control on my SICF tree ?



      Author's profile photo Buzek Volker
      Buzek Volker
      Blog Post Author

      Hi Paolo,

      I haven't made any modifications to the service in SICF after inital deployment of the OData service. This refers to GW & ERP being on the same instance. If you have GW in a stand-alone Hub install, you need to use the /iwfnd/* namespace for development instead of /iwbep/*.

      hth, v.

      Author's profile photo Mark Teichmann
      Mark Teichmann

      I cannot get the Server side working.

      On client side we either get a 405 or a 401 regarding what HEADER data we send on client side ( withCredentials: true or false).

      The Allow-Origin header fields are set in method /IWBEP/IF_MGW_CORE_SRV_RUNTIME~READ_ENTITYSET but the client first does an OPTIONS call which seems to be unsupported in SAP Gateway (740 SP10).

      Author's profile photo Buzek Volker
      Buzek Volker
      Blog Post Author

      Confirmed: up to the current GW version, OPTIONS calls are not supported:

      /IWCOR/CL_DS_PROC_DISPATCHER->/IWCOR/IF_DS_PROCESSOR~PROCESS( ) only handles GET, POST, PUT, DELETE, MERGE and PATCH (depending on the resource called).

      OPTIONS requests are typically triggered only if cusom http headers are set on the client side for the call. Your "withCredentials" flag hints that you're doing a custom ajax.get() that does just that, resulting in a "preflighted" OPTIONS request to the URL.

      So getting rid of the extra http headers in the ajax.get( ) might be a starting point for solving the issue.

      Author's profile photo Mark Teichmann
      Mark Teichmann

      Now we are omitting the withCredentials header.

      But we need to authorize at the Gateway server and also need to fetch an CSRF token, therefore

      setRequestHeader("X-CSRF-Token", "Fetch");

      is needed, but triggers also the preflight request?

      Author's profile photo Buzek Volker
      Buzek Volker
      Blog Post Author

      for authentication, you could do a GET on the service root, sending basic auth data (base64!) to Gateway (utilizing the underlying ICF basic auth).

      CSRF for POST, PUT, DELTE should work out of the box since it's designed for cross-domain security.

      All in all this looks more like a client-side issue than a GW problem - should take this offline, PM me if you want.

      Author's profile photo Basis Team
      Basis Team

      Hello Buzek/Mark,

      We have the exact same issue Mark has highlighted. Would it be possible for you to let us know how this was solved i.e. how to we ensure that that call from client does not end up being a OPTIONS method?



      Author's profile photo Mark Teichmann
      Mark Teichmann

      Hi Jay,

      I did not find any time to investigate if Volkers answer would solve my problem.

      Will keep you updated if I continue with this task but it may take some weeks...

      Cheers, Mark

      Author's profile photo ' Pavan ' Golesar
      ' Pavan ' Golesar


      I am new to Cors and its integration with GATEWAY, 😕 It'd be appreciated if someone puts more light on what is Cors, and how its related to gateway..

      Thanks alot in advance. 🙂

      --Pavan G

      Author's profile photo Former Member
      Former Member

      H Buzek,

      I tried all the steps you mentioned, but still get the CORS 401 error. the data fetch fails.

      I am running on local tomcat 8080 and trying to get the model on SAP server.

      var oModel =  new sap.ui.model.odata.ODataModel("http://sapdeverp.XXXX.XXX:1080/sap/opu/odata/sap/Z_PERSON_SRV/",true);

      in the debug I still see the cors error.. I have done everything you mentioned. Tried many blogs somehow this things is not getting solved. Do you have any clue.



      Author's profile photo Buzek Volker
      Buzek Volker
      Blog Post Author

      Hi Raghavendra,

      you're sure that the GW at http://sapdeverp.XXXX.XXX:1080 is sending the "Access Control Allow Origin" http header?

      And you're sure that your local Chrome Browser was started with the --disable-web-security flag?

      - V.

      Author's profile photo Former Member
      Former Member

      Hi Buzek,

      Thanks for your response. If I understand, you mean am I sending this one shown below.

      ******my service method*****************************

      select pernr nachn vorna UP TO 20 ROWS from pa0002 into CORRESPONDING FIELDS OF TABLE  ET_ENTITYSET.
      DATA: ls type ihttpnvp.
      ls-name = 'Access-Control-Allow-Origin'.
      ls-VALUE = '*'.
      /IWBEP/IF_MGW_CONV_SRV_RUNTIME~SET_HEADER( is_header = ls ).


      Any inputs highly appreciated, unable to crack this one for many days now.



      Author's profile photo Buzek Volker
      Buzek Volker
      Blog Post Author

      yep, that's the server-side part.

      Now you need to make sure, that you have the client-side part prepared as well.

      I assume you're consuming the service via some flavor of JS (UI5, jQuery, ...).

      When calling the above service from your client-side runtime, you can either

      - run a local proxy to consume the service (thus "hiding" the remote GW server) or

      - provide your runtime with a tailored platform, such as running the Chrome Browser with --disable-web-security

      then you should be good to go.

      Author's profile photo Former Member
      Former Member

      Hi Buzek,

      Thanks once again.. I cleared the browser cache, and did a disable security using the command --disable-web-security. Yes, the CORS vanished now. But Alas! still data does not show 🙁 ...well that is another problem. let me deal with it 🙂 .



      Author's profile photo Former Member
      Former Member

      Hello thank u for your post ,I'm new in SAPUI5 and the problem of CORS is driving me crasy 🙁 , I didn't understand this part

      in order to send an additional, custom header from a Gateway-service, use set_header from Interface /iwbep/if_mgw_conv_srv_runtime.

      It takes a structure as argument, consisting of a key-value pair.

      1. data:
      2.         ls            type ihttpnvp.
      3. ls-name = 'Access-Control-Allow-Origin'.
      4. ls-value = '*'.
      5. /iwbep/if_mgw_conv_srv_runtime~set_header( is_header = ls ).

      This will result in the desired CORS "Access-Control-Allow-Origin" header, granting all clients ("*") read access:


      ..where can I put it ?? I'm so confused

      Best regards

      Author's profile photo Former Member
      Former Member

      Hi Radhia Henouz,

      I am also facing the same issue. Could you please share if you were able to resolve this.

      Thanks in advance.


      Author's profile photo Paul Wieland
      Paul Wieland

      Can you please explain how to use the set_header in the gateway?


      Also, if the server is telling the browser that there is no access restriction, you do NOT need to disable CORS in the browser.

      If header:

      Access-Control-Allow-Origin: *

      is sent by the server, then you can use XMLHttpRequest from any webpage on any domain to pull data from it. See here for an explanation: