3

Google and Facebook both allow users to "Login with _____". The website developer normally just has to include a Javascript and provide a callback to handle the login response. From my understanding of the JavaScript security in browsers, this should not be possible.

I've read several methods of cross-origin JavaScript communication, such as Porthole or easyXDM. In each of these methods, a small static HTML file is required to be hosted by the developer so that either Facebook or Google (i.e., the 'included' content) can communicate back to the parent frame. An example would be an application (app.example.com) that included an iframe from Google (google.com) which includes an iframe from the application again (app.example.com). The innermost iframe's JavaScript can communicate with the top most window since they are in the same domain (via this.parent.parent).

+-------------------------------------------------------------+
| https://app.example.com                                     |
+-------------------------------------------------------------+
|                                                             |
|  +------------(hidden iframe)-----------------------------+ |
|  | https://whatever.google.com                            | |
|  +--------------------------------------------------------+ |
|  |                                                        | |
|  |  +---------(hidden iframe)--------------------------+  | |
|  |  | https://app.example.com/receiver                 |  | |
|  |  +--------------------------------------------------+  | |
|  |  |                                                  |  | |
|  |  | (script that calls this.parent.parent.callback)  |  | |
|  |  |                                                  |  | |
|  |  +--------------------------------------------------+  | |
|  |                                                        | |
|  +--------------------------------------------------------+ |
|                                                             |
+-------------------------------------------------------------+

However, this requires that the innermost iframe contain a 'receiver' page on the app.example.com domain. It's sole purpose is to read it's URL bar and then pass that data up to the parent window. With the Google and Facebook solutions however, no static HTML page is needed. So what mechanism are they using to pass the data back up if not a static receiver page? The JavaScript in their frame should have no access to the parent JavaScript. The Window.PostMessage seems dubious at best, seeing as it's IE8, IE9, and IE10 implementations are either broken or quirky.

Community
  • 1
  • 1
Huckle
  • 1,810
  • 3
  • 26
  • 40
  • JSONP and CORS are two of the methods for doing ajax calls outside the page origin. – jfriend00 Nov 18 '14 at 00:00
  • These are generally not AJAX calls, rather they normally utilize a pop-up window and then some login data is returned from that pop-up window to a callback in the parent page. – Huckle Nov 18 '14 at 00:01
  • Click the 'Google' link in my question and then press the sign in button under 'Try It'. This will launch a new pop up window. https://developers.google.com/+/web/signin/add-button – Huckle Nov 18 '14 at 00:05
  • The 'Facebook' link doesn't have a live demo, but it describes a pop-up window being launched when the sign in button is clicked. https://developers.facebook.com/docs/plugins/login-button – Huckle Nov 18 '14 at 00:07
  • actually, you DO need an html page on your site to land on (static or php) for oauth. the popup returns to the page on your site before closing, passing info from google to it via URL fragments (hash). once back at your site, the popup can talk to opener, pass along the info, and close the popup. the secret mechanism you are after is just the lowly location.hash, which can be SET x-domain on popups or iframes. for example: top.location.href="#secret123"; – dandavis Nov 25 '14 at 23:16
  • also, postMessage works fine with iframes in old IE, just not popups. you can still use the xdmomain property window.name, which any domain can read and write, and which persists across refreshes. you can also ajax the data from a 3rd party server, or use GET search params (but hash is better because it doesn't go over the routing/logging mechanisms of the intertubes. – dandavis Nov 25 '14 at 23:25
  • @dandavis I wrote a proof of concept where I put an iframe from whatever.google.com in the app.example.com's site. The iframe was able to communicate via postMessage with the host window. I then had the iframe open a popup window in whatever.google.com's domain. Although this worked in Chrome, IE blocks the pop-up window as it treats the postMessage as asynchronous. Chrome treats it as synchronous for the purposes of not blocking pop-ups. The Google and Facebook SDKs each work in IE though, so they must pop the window from the host window? – Huckle Nov 26 '14 at 06:18

2 Answers2

3

Let me first point you in the right direction and then explain them briefly. The magic word that you are looking for is OAuth.

About CORS... it is a request attribute from the view point of a client and the responding server can or can't accept it. If the responding server does accept it and decides to allow a CORS request, then the responding server has to return CORS Headers in its response.

About Login with ____, what happens is, basically two entities are working here. One is the OAuth provider and the other is OAuth user. So, imagine you have a site that uses the Login with Facebook button. Now, what you do is include the JS SDK in your application. You start off by init-ing the application with your credentials, that you have created in your application's FB page. This JS code is as follows:

<script>
  window.fbAsyncInit = function() {
    FB.init({
      appId      : 'your-app-id',
      xfbml      : true,
      version    : 'v2.1'
    });
  };

  (function(d, s, id){
     var js, fjs = d.getElementsByTagName(s)[0];
     if (d.getElementById(id)) {return;}
     js = d.createElement(s); js.id = id;
     js.src = "//connect.facebook.net/en_US/sdk.js";
     fjs.parentNode.insertBefore(js, fjs);
   }(document, 'script', 'facebook-jssdk'));
</script>

Explanation:

1. js = d.createElement(s); 
2. js.src = "//connect.facebook.net/en_US/sdk.js";

Line No. 1 -> Create an element by the ID of 's'; Line No. 2 -> The source attribute of this script element is set to the FB connect JS Library URL;

Now that URL is already in the FB domain, so there is not CORS involved. It can create a pop-up in your current page context and also it can communicate with FB domain object.

This is not WHAT FB Does but to give you an easy explanation: Imagine, you have a simple PHP SESSION variable set in your server. This client JS sends a GET request, obviously the PHP SESSION COOKIE would be included in the request without violating any JS security because they are in the same FB Domain. And that GET Request can easily be validated with a return response as well.

Bonanza This JS can open pop-ups in your html page context as well. Much like you can include JQuery from Google in you html context and use it like a local library.

I hope that answers your question. Good Luck!

Chris Roy
  • 945
  • 1
  • 7
  • 19
1

The simplest way to do CORS is by using http request instead of ajax request. In this method a callback function name is passed which will execute after the http call finished. This method is called as JSONP. i.e JSON with padding.

Laxmikant Dange
  • 7,606
  • 6
  • 40
  • 65
  • CORS works fine for RESTful operations, however in both of the examples in the question a GUI is presented to the end user to interact with. This cannot be done via CORS. JSONP is a less secure means to doing the same thing as CORS. – Huckle Nov 26 '14 at 19:44