0

I am bulding a web app: a SPA using React in frontend and Django rest framework to API endpoints.

I am in the part of the social login, which is done entirely in the backend (there is a exchange of providers tokens by own JWTs), so it is necessary make the request to the server, which redirect the user to the login of the specific provider. However, due to Facebook, Google and others providers do not permit this request using AJAX, I decided to create a popup (through window.open()) to make this redirection.

Whether login is successful this window is redirect again towards a View of Django that returns a JSON with the JWT. Hence, this secondary window has a JWT in the domain of my server (Django). I planned read this JSON from the body of this secondary window to get the JWT, and I read (Code response form parent window, SecurityError: Blocked... and others) the only way to communicate windows in different domains is with postMessage(). But when I try, I receive the next message:

SecurityError: Permission denied to access property "document" on cross-origin object

In fact both of them are runnning in localhost, just with different port. That's the reason why is activate the same-origin policy.

Example of my button to open the window of social network login.

<button
    className="facebookI"
    title="Facebook"
    type="button"
    onClick={loginSocial}
>
    <i className="fab fa-facebook-f" title="Facebook"></i>
</button>

The functions that manage the click and made the read attempt.

const loginSocial = ({target}) => {
    let socialWindow = null;
    socialNetwork = target.title.toLowerCase();
    request = `/kuku_api/social-auth/login/${socialNetwork}/`;

    if(socialWindow === null || socialWindow.closed) // If there is no window open
       socialWindow = openWindow(request, width, height, x, y);

    main = socialWindow.opener;
    // I coded a setTimeout to made the next after the login
    main.postMessage(socialWindow?.document?.body, 'http://local.react:3000');
}

const openWindow = (request, width, height, x, y) => {
    return window.open(
        'http://local.django:8000' + request,
        'SocialLogin',
        'popup,location,width=' + width + ',height=' + width + ',left=' + x + ',top=' + y + ''
    );
}

And the listener of the 'message'.

useEffect(() =>{
        window.addEventListener('message', handleMessage);
        return () => ( window.removeEventListener('message', handleMessage) );
}, []);

const handleMessage = (e) => {
        if(e.origin !== 'http://local.react:3000'){
            return;
        }
        console.log(`Test ${e?.origin}`);
        console.log(`Test ${e?.source}`);
        console.log(`Test ${e?.data}`);
    };

Where is my mistake? Or, there is any way to could read this JWT of the body of the secondary window?

Maybe, I have taken a wrong approach. Please feel free of make suggestions about how achieve this in a better way.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Jony_23
  • 322
  • 4
  • 12
  • You can't and shouldn't access the body of another window. Windows should exchange messages in some way. In case you need to receive something from a popup (socialWindow), it should post a message to its window.opener. I'm not sure what exactly is the flow here so cannot recommend a specific solution. – Estus Flask Dec 15 '21 at 21:00
  • Thanks for the comment. A brief of the flow: . popup -> request (specific social network) -> Python-social-auth (a third-party package) redirects to the login site (with all parameters necessary: state mainly) * if login is successful, I received the tokens of this provider -> instantly there is a redirect to an a View that generate my own tokens (to use as JWT) -> send these tokens response of all the request. I created this popup because I want to redirect users to the social login in the main window, but if I can't read the data in the secondary window, maybe that's the only solution. – Jony_23 Dec 15 '21 at 21:17
  • It's python side that needs to call window.opener.postMessage with respective jwt data. React side needs to listen for the message. If it's guaranteed that they'll run on the same origin in production, it's preferable to fix this in dev server instead, would be easier to handle without postMessage – Estus Flask Dec 15 '21 at 21:23
  • OK, I have my doubts about the reference 'window.opener' woks, but I will try to send the data in python side. Yeah in production must be configured a proxy using Nginx to this run in the same origin. Really, thank you for the help. I hope this works. – Jony_23 Dec 15 '21 at 21:34
  • I've had to do this before because there were multiple domains in my case. If origin is the same in production then postMessage is unnecessarily complex workaround for the issue that doesn't exist. If your problem is that it doesn't work in development, use dev proxy for backend requests (if you use CRA, it has a built-in proxy) or Nginx – Estus Flask Dec 16 '21 at 05:01
  • I did the attempt with proxy: 'http-proxy-middleware' of Node. I can make the request, but now, for example with Google I receive: > Request from another origin blocked: the same origin policy prevents reading the remote resource in 'some_url_play_google'. I think could be I don't have SSL certificates(as it is mentioned in [Using HTTPS]: https://create-react-app.dev/docs/using-https-in-development/) , then I created a couple with OpenSSL, but when I click in button, there is an error: >(UNABLE_TO_VERIFY_LEAF_SIGNATURE) As far as I read, it is a problem with the SSL certificates. – Jony_23 Dec 16 '21 at 16:16
  • Strangely, just twitter allow me to login when is the proxy is activate; but after redirect to its main login page, not with the third-party-app login. I will continue with the normal request and try to send the data in side python. **Again many thanks for the help.** – Jony_23 Dec 16 '21 at 17:15
  • There shouldn't be problems with unsafe https without certs for google, but I believe that you have to explicitly allow the origin that you use in dev mode for most auth providers. – Estus Flask Dec 16 '21 at 19:19
  • I tried a little more and apparently I use the dev proxy, my request, for example, to: 'https://accounts.google.com/o/oauth2/v2/auth' it is make it to 'url_proxy/api/social-auth/login/google-openidconnect/' (the url through the proxy). That's the problem: the proxy not permit redirect correctly to the URL of the Oauth provider. Hence, I have to make a normal request. Actually, I am already capable to send the data with postMessage() in python side. Thank you! – Jony_23 Dec 17 '21 at 00:12

0 Answers0