📜 ⬆️ ⬇️

Cross domain postMessage or how browsers support standards

While screwing up cloud storage to the backup script, it became necessary to use OAuth 2 authorization, for use with different cloud APIs. In principle, with the authorization itself no difficulties arose, but the problem arose in a little unexpected place.

Considering the audience using the software, it was decided to abandon the support of ancient browsers, and everything was sharpened for modern browsers that use HTML5, which would seem quite well and equally support the standards.

But it was not there…

Interpretation of postMessage by different browsers


As it turned out, cross-domain (when pages from different domains) communicate between browser windows / tabs using postMessage is possible only in Chrome and Firefox (tested in Chrome 30 and Firefox 25).
')
In IE, postMessage only works when using frame / iframe (including IE 11).

Opera unexpectedly surprised. In version 12, everything works fine. But in Opera 17, which is made on the same engine as Chrome, behaves differently. If the domains are different, then postMessage works only in frame / iframe, and does not work in separate windows / tabs. If the domains, more precisely, origin (ie, protocol + domain + port) are the same, then messages work, both between frames and between windows / tabs.

It would seem that if all browsers support cross-domain communication between frames, so why not open the iframe authorization window in the application right away? But here the careful X-Frame-Options puts the footboard - almost on all OAuth servers it is forbidden to open the login page in the frame.

Proxy frame


Despite the scary name, this is a regular iframe downloaded from the application site, and its task is to transfer received tokens to the application window, since it cannot be directly transferred due to limitations in Opera and IE.

After various options were tried, I settled on the following fairly simple solution for obtaining a token.

For convenience, we use the following definitions:
  1. Application (the web application is located on the user's domain, which is not known in advance)
  2. Proxy frame (intermediate frame located on the application server, embedded with the iframe in the application)
  3. Application site (site to which the user is redirected after OAuth authorization)
  4. OAuth server (the server you want to access)

In total, we use 3 domains: domain1 - where the user application is located, domain2 - the proxy frame and application site, domain3 - the OAuth server.

The procedure for obtaining a token is as follows:
  1. On the application page embedded proxy frame.
  2. After clicking the button located in the proxy frame, the OAuth server authorization page opens in a new window / tab.
  3. After the user's consent, the OAuth server sends the user to the Application site, with an authorization code in the request parameters.
  4. The application site makes a POST request to the OAuth server, and exchanges the authorization code and application password for the access token and / or the token for the update.
  5. The resulting token is inserted into the text field (in case you cannot automatically copy it). After that, the token is sent to the proxy frame, by changing the location.hash (this works in all browsers, since the proxy frame and application site have the same protocol, domain, port). In fact, the use of location.hash is needed only for IE (including in IE 11), since in it postMessage does not work in different windows.
  6. Using the onhashchange event, the proxy frame immediately after changing the hash sends the token using postMessage (since the domains are now different) and closes the open window / tab opened for authorization.
  7. An application using the onmessage event receives a token and already uses it as intended.


Schematic illustration



I'm not special, though, according to beautiful schemes. But I hope it will be clear.

Demonstration


On this page, you can see a live example , except that the OAuth authorization itself is simulated, so that the real server is not overwhelmed.

In normal mode, the transfer of the token occurs so quickly that the page with the text field is not visible (it closes quickly). Therefore, who wants to see in more detail, here is an example in which the window closes with a delay of 5 seconds .

What else to read about postMessage


learn.javascript.ru/cross-window-messaging-with-postmessage
javascript.ru/ajax/cross-origin-2
html5demos.com/postmessage2
habrahabr.ru/post/120336
caniuse.com/#search=postmessage

PS If you are interested, I can put the source codes of the scripts from the demo in the archive.

Source: https://habr.com/ru/post/197038/


All Articles