最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - OAuth popup cross-domain security React.js - Stack Overflow

programmeradmin2浏览0评论

I'm interested in how to implement OAuth in React using popup (window.open).

For example I have:

  1. mysite — this is where I open the popup.
  2. passport.mysite/oauth/authorize — popup.

The main question is how to create connection between window.open (popup) and window.opener (as it's known the window.opener is null due to cross-domain security therefore we can't use it anymore).

window.opener is removed whenever you navigate to a different host (for security reasons), there is no way around it. The only option should be doing the payment in a frame if it is possible. The top document needs to stay on the same host.

Scheme:

Possible solutions:

  1. Check an opened window using setInterval described here.
  2. Using cross-storage (not worth it imho ).

So what's the best remended approach in 2019?

Wrapper for React -

I'm interested in how to implement OAuth in React using popup (window.open).

For example I have:

  1. mysite. — this is where I open the popup.
  2. passport.mysite./oauth/authorize — popup.

The main question is how to create connection between window.open (popup) and window.opener (as it's known the window.opener is null due to cross-domain security therefore we can't use it anymore).

window.opener is removed whenever you navigate to a different host (for security reasons), there is no way around it. The only option should be doing the payment in a frame if it is possible. The top document needs to stay on the same host.

Scheme:

Possible solutions:

  1. Check an opened window using setInterval described here.
  2. Using cross-storage (not worth it imho ).

So what's the best remended approach in 2019?

Wrapper for React - https://github./Ramshackle-Jamathon/react-oauth-popup

Share Improve this question edited Nov 9, 2019 at 12:58 Arthur asked Nov 6, 2019 at 14:21 ArthurArthur 3,5167 gold badges35 silver badges65 bronze badges 5
  • 2 In 2019, localStorage support is much better. I would go with localStorage approach (described in stackoverflow./questions/18625733/…) as it does not seem like much a workaround. The parent window does not need to periodically check for the child window status.setInterval could be used as fallback for localStorage – Khanh TO Commented Nov 9, 2019 at 5:40
  • @KhanhTO, yeah, I pletely agree with you about localStorage, but it only works for the same domain so it doesn't work in my condition – Arthur Commented Nov 9, 2019 at 9:32
  • 2 After you finish with OAuth, the child window is redirected back to your domain, you are in the same domain now with the parent – Khanh TO Commented Nov 9, 2019 at 9:43
  • @KhanhTO, hm, this is great idea! I should have known.. – Arthur Commented Nov 9, 2019 at 12:29
  • 1 It would be even better if the browser restores window.opener after redirecting back to our domain, but this is not the case – Khanh TO Commented Nov 9, 2019 at 13:06
Add a ment  | 

2 Answers 2

Reset to default 10

Suggested by Khanh TO. OAuth popup with localStorage. Based on react-oauth-popup.

Scheme:

Code:

oauth-popup.tsx:

import React, {PureComponent, ReactChild} from 'react'

type Props = {
  width: number,
  height: number,
  url: string,
  title: string,
  onClose: () => any,
  onCode: (params: any) => any,
  children?: ReactChild,
}

export default class OauthPopup extends PureComponent<Props> {

  static defaultProps = {
    onClose: () => {},
    width: 500,
    height: 500,
    url: "",
    title: ""
  };

  externalWindow: any;
  codeCheck: any;

  ponentWillUnmount() {
    if (this.externalWindow) {
      this.externalWindow.close();
    }
  }

  createPopup = () => {
    const {url, title, width, height, onCode} = this.props;
    const left = window.screenX + (window.outerWidth - width) / 2;
    const top = window.screenY + (window.outerHeight - height) / 2.5;

    const windowFeatures = `toolbar=0,scrollbars=1,status=1,resizable=0,location=1,menuBar=0,width=${width},height=${height},top=${top},left=${left}`;

    this.externalWindow = window.open(
        url,
        title,
        windowFeatures
    );

    const storageListener = () => {
      try {
        if (localStorage.getItem('code')) {
          onCode(localStorage.getItem('code'));
          this.externalWindow.close();
          window.removeEventListener('storage', storageListener);
        }
      } catch (e) {
        window.removeEventListener('storage', storageListener);
      }
    }

    window.addEventListener('storage', storageListener);

    this.externalWindow.addEventListener('beforeunload', () => {
      this.props.onClose()
    }, false);
  };

  render() {
    return (
      <div onClick={this.createPopup)}>
        {this.props.children}
      </div>
    );
  }
}

app.tsx

import React, {FC} from 'react'

const onCode = async (): Promise<undefined> => {
  try {
    const res = await <your_fetch>
  } catch (e) {
    console.error(e);
  } finally {
    window.localStorage.removeItem('code'); //remove code from localStorage
  }
}

const App: FC = () => (
  <OAuthPopup
    url={<your_url>}
    onCode={onCode}
    onClose={() => console.log('closed')}
    title="<your_title>">
    <button type="button">Enter</button>
  </OAuthPopup>
);

export default App;

I once encounter an issue on my oauth login flow with window.open/window.opener bug on ms-edge

My flow before this issue was

  • On login button click open a popup
  • After successful login the oauth app redirect to my domain's page
  • Then i call a function of the parent window from with in the popup (window.opener.fn) with data from oauth response and the parent window then close the child popup window

My flow after this issue was

  • On login button click open a popup
  • Create a setinterval in case (window.opener is undefined)
  • After successful login the oauth app redirect to my domain's page
  • Check if window.opener is available then do #3 from the above flow and clearInterval
  • If window.opener is not available then since i am on my domains page i try to set localstorage and try to read the localstorage from inside the setInterval function in parent window then clear the localstorage and setInterval and proceed.
  • (for backward patibility) If localstorage is also not available then set a client side cookie with the data with a short expiry (5-10 sec) time and try to read the cookie (document.cookie) inside the setInterval function in parent window and proceed.
发布评论

评论列表(0)

  1. 暂无评论