48

We have a javascript api.js which is hosted on domain api.abc.com. It manages the local storage.

We included this javascript in our websites at abc.com and login.abc.com as a cross domain js like

<script src="http://api.abc.com/api.js">

I understand that localstoarge is per domain basis. However since api.js is loaded from api.abc.com, I expected that it will have access to local storage of api.abc.com from both the domains. Unfortunately, it doesn't seem to be the case. When api.js stores a value in localstoarge from one domain, it's not accessible to it when loaded from other domain.

Any idea?

Ravikumar B
  • 779
  • 1
  • 14
  • 25
mesibo
  • 3,970
  • 6
  • 25
  • 43
  • 1
    I don't think so. The api.js is executed on a client side of the browser, with the domain. That's what matters. – Praveen Kumar Purushothaman Nov 27 '15 at 12:31
  • It doesn't matter from where the script came from (the script can be loaded from CND you don't expect localStorage to be saved on CDN domain), but if you need cross-domain localStorage there is a way using proxy iframe, check this article [Cross-Domain LocalStorage](https://jcubic.wordpress.com/2014/06/20/cross-domain-localstorage/). You can use iframe to interact with any API on different domain. – jcubic Oct 21 '20 at 14:53
  • Does this answer your question? [use localStorage across subdomains](https://stackoverflow.com/questions/4026479/use-localstorage-across-subdomains) – gre_gor Apr 05 '22 at 01:06

5 Answers5

22

How about using cross domain postmessage and iframes?

So on your wrong-domain-page you include an iframe that posts messages with the cookie data back.

Here is a solid example of cross domain postmessages: http://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage

live example: http://codepen.io/anon/pen/EVBGyz //forked sender code with a tiiiiiny change :) :

window.onload = function() {
    // Get the window displayed in the iframe.
    var receiver = document.getElementById('receiver').contentWindow;

    // Get a reference to the 'Send Message' button.
    var btn = document.getElementById('send');

    // A function to handle sending messages.
    function sendMessage(e) {
        // Prevent any default browser behaviour.
        e.preventDefault();

        // Send a message with the text 'Hello Treehouse!' to the new window.
        receiver.postMessage('cookie data!', 'http://wrong-domain.com');
    }

    // Add an event listener that will execute the sendMessage() function
    // when the send button is clicked.
    btn.addEventListener('click', sendMessage);
}

Receiver code:

window.onload=function(){
    var messageEle=document.getElementById('message');
    function receiveMessage(e){
        if(e.origin!=="http://correct-domain.com")
        return;
        messageEle.innerHTML="Message Received: "+e.data;
    }
    window.addEventListener('message',receiveMessage);
}
25r43q
  • 613
  • 4
  • 16
9

As noticed in your post the localStorage (sessionStorage too) won't be stored on the storage related to the domain api.abc.com. If this was the case, by using CDN version of a library using localStorage you would have to share storage with all the other websites using this library.

One good solution could be to use an iframe with postMessage as explained in the following stack overflow: use localStorage across subdomains

Community
  • 1
  • 1
  • True, your point is taken however CDN is often different domain and I wish it was allowed between subdomains just like cookies are allowed. – mesibo Nov 27 '15 at 18:02
5

You might try this cross-storage from Zendesk. Basically, There are hubs and clients:

  • hubs: reside on any server, interact directly with LocalStorage API

  • clients: load the hub using an embedded iframe, and post messages, interact with data

Key things is you can configure the permission (get, set, delete) that each host or domain client could have. The library is divided into two types of components: hubs and clients.

Care should be made to limit the origins of the bidirectional communication. As such, when initializing the hub, an array of permissions objects is passed. Any messages from clients whose origin does not match the pattern are ignored, as well as those not within the allowed set of methods. The set of permissions are enforced thanks to the same-origin policy. However, keep in mind that any user has full control of their local storage data - it's still client data. This only restricts access on a per-domain or web app level.

super1ha1
  • 629
  • 1
  • 10
  • 17
4

The other answers all ignore the fact that you're not really operating cross-domain, just between subdomains.

You still need a hidden iframe to encapsulate the origin of the localStorage store you want to access (api.abc.com), but by setting document.domain = "abc.com" on both main window and hidden iframe, they can interact directly. (Though note that this is deprecated, may have security implications, and in Chrome at least requires also sending a Origin-Agent-Cluster: ?0 header).

Then you can literally just use hiddenIFrame.contentWindow.localStorage instead of window.localStorage, and forget about the headache of doing anything via postMessage().

I posted a more detailed version of this answer here: https://stackoverflow.com/a/63602446/999120

Doin
  • 7,545
  • 4
  • 35
  • 37
  • In many cases, this may not be a good idea. Imagine there is an XSS vulnerability in one domain. Then by sharing in the above way, that leaks into the other domain. Message posting is safer because it makes you think harder about what you want to share between the two domains. – Colm Bhandal Jun 11 '22 at 20:50
  • 1
    @Colm: That's true, and I've added a note mentioning it to my more detailed linked answer. – Doin Jun 13 '22 at 02:16
  • Setting `document.domain` is now prohibited within a cross-domain iframe in Chrome, even if it's only cross-site (https://developer.chrome.com/blog/immutable-document-domain/). – Abel Wenning Aug 30 '22 at 05:23
  • @Abel, according to the article you linked, it's only prohibited by default, and can be re-enabled if the `Origin-Agent-Cluster: ?0` header is sent. – Doin Aug 31 '22 at 17:47
3

Use iframe to store data in local storage & postMessage API to communicate between parent domain & iframe

  1. Create Iframe with message event listener to store data in local storage of iframe domain

    window.addEventListener("message", handleMessage, false);
    
    function handleMessage(e) {
    let {key, value, method} = e.data;
    if (method == 'store') {
        window.localStorage.setItem(key, value); // Store data in iframe domain local storage
    } else if (method == 'retrieve') {
        let response = window.localStorage.getItem(key);
        e.source.postMessage({
            key,
            response,
            method: 'response'
        }, '*'); // Retrieve local storage data
    }
    

    }

  2. Pass Message from parent domain to iframe to store data

    document.getElementById('myFrameId').contentWindow.postMessage({
    key: 'key',
    value: data,
    method: 'store'
    });
    
  3. Retrieve data from Iframe

     document.getElementById('myFrameId').contentWindow.postMessage({
     method: 'response',
     key: 'key'
     });
    
     window.addEventListener("message", handleResponse, false);
    
     function handleResponse(e) {
      let {key,value,method} = e.data
      if (method == 'response') {
        console.log('Response Key', key);
        console.log('Response value', value)
      }
     }  
    
  • I believe there's an error in step 3. `method` when posting the message should be `retrieve`, not `response`. – Link14 Jul 12 '23 at 00:32