Cross domain communication using postMessage and local storage

Tweet about this on TwitterShare on FacebookShare on Google+

There could be scenarios like having an iFrame from sister application, which is hosted on a different domain within a host application. If data needs to be passed between these applications and server side way is ruled out, then here’s a safe way to do so entirely on client side.

AT HOST

window.postMessage API is safest way to conduct cross-origin communication. It is always recommended to give the targeted domain, which can receive the message. If you don’t want to mention it, “*” would apply to all.

/**
 * Post message to the other window and restricted to some domain
 * @param  {[type]} win    [Other window]
 * @param  {[type]} msg    [Message to be sent]
 * @param  {[type]} domain [Targeted domain]
 */
function postCrossDomainMessage(win, msg, domain) {
    if (domain) {
        win.postMessage(msg, domain);
    } else {
        win.postMessage(msg, "*");
    }
}

I’d suggest the message which is posted, should be in a particular format for the target. In this example all the messages which we’ll send would be a serialized JSON.

/**
 * This creates a message in a suitable format for reading at other window
 * @return {[string]} [Message to be sent]
 */
function createMessage(key, msg) {
    return "{\"postedmessage\":{\""+key+"\":\""+msg+"\"}}";
}

Now, the target domain, which our host want’s to communicate can be a iFrame or a pop-up window. In either case, we’d need the window object of the target. For example sake I’ve considered an iFrame to be our target window here. This is how we’d post the message:

/**
 * Initiating a message
 */
var win = document.getElementById('ifr').contentWindow;
var msg = createMessage("localstoragekey", "this is some random localstoragevalue " + Math.random().toString(36).substring(7));
postCrossDomainMessage(win, msg);

One key thing to note here is the message should be passed to the target window only once the window (here iFrame) has completely finished loading.

AT TARGET

postMessage fires a “message” event on the target. The event.data property contains the data sent by the host. To keep the message persisted on to the target domain, we’d put the message against the key, which we had set at the host.

var PERMITTED_DOMAIN = "http://example.com";
 
/**
 * Receiving message from other domain
 */
window.addEventListener('message', function(event) {
	if (event.origin === PERMITTED_DOMAIN) {
        var msg = JSON.parse(event.data).postedmessage;
        var msgKey = Object.keys(msg)[0];
        localStorage.setItem(msgKey, msg[msgKey]);
    }
});

Again it is adviced to use event.origin to permit only allowed domains. This will avoid cross site scripting hacks.

One final thing, which is optional is to write local storage event handlers. This event would let the target domain open in other window/tab about the local storage changes.

/**
 * Local storage event capture to detect changes
 */
window.addEventListener('storage', function(event) {
	if (event.key === 'localstoragekey') {
		console.log(localStorage.getItem(event.key));
		//doSomething
	}
}, false);
Tweet about this on TwitterShare on FacebookShare on Google+

Local storage service for AngularJS

Tweet about this on TwitterShare on FacebookShare on Google+

I loved the concept of Angular services. It helps in writing cleaner code, which can be shared across the app.

We use local storage a lot these days and there are plenty of wrapper around local storage. I wrote this wrapper in form of angular service. It provides a bit improved way to access the APIs.

Tweet about this on TwitterShare on FacebookShare on Google+