Search code examples
javascripthtmliframexmlhttprequestsame-origin-policy

One iframe randomly fails to XHR


I have a page on http://localhost:3000 that contains an iframe whose src is http://localhost:3010/login. The iframe does the following:

  • Requests the src html.
  • After receiving a 302 redirect, it follows it to http://localhost:3000/oauth/authorize?response_type=code&client_id=1&redirect_uri=http%3A%2F%2Flocalhost%3A3011%2Fauthorization_code&state={state}.
  • The iframe is then redirected back to its own origin: http://localhost:3010/authorization_code?code={code}&state={state}.
  • The iframe-embedded app's server successfully exchanges the authorization code for an access token and redirects to http://localhost:3010 with a cookie set to the OAuth2 access_token.
  • Some JavaScript code makes an XHR to http://localhost:3010/api/customerInfo.
  • The customer information is returned and rendered in the iframe using JavaScript.

So this all works just fine.

However, when I add a second iframe-embedded app with its own origin localhost:3020, which goes through the same flow, one of the apps' first XHR will fail with the following error:

XMLHttpRequest cannot load http://localhost:3000/oauth/authorize?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3011%2Fauthorization_code&state=17nCw5o0Tr11Y6z8&client_id=1. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3010' is therefore not allowed access. The response had HTTP status code 400.

The seems a bit odd because it's saying it cannot load a URL via XHR that it has already loaded via a redirect.

Sometimes one iframe fails and sometimes the other. Every single time and in every browser, one iframe can execute an XHR the other one causes this error. I have even delayed both iframes' initial XHR by different amounts so that they don't overlap, but to no avail.

The iframes are generated dynamically (via React) and have this attribute: sandbox='allow-forms allow-scripts allow-same-origin'.


Solution

  • This is caused by cookies not being port-specific, unlike the same-origin policy which considers the port number to be part of the origin. In this case, both iframes were sharing cookies and both were using access_token as the name of the cookie containing the OAuth access token. The second iframe to complete the authorization process would overwrite the first iframe's access_token cookie, causing subsequent iframe calls from the latter iframe to fail. I fixed this by using unique cookie names. An alternative fix would be to use different host names and edit the computer's hosts file.