tayden tayden - 2 months ago 30
React JSX Question

3 legged OAuth with React and Redux

What's the accepted method of authenticating with OAuth2 in React using Redux?

My current setup involves wrapping react-router components using Redux-Auth-Wrapper, and if the user is not authenticated, dispatching an action that makes the necessary external URL GET request to an OAuth provider (google in this case).

OAuth2 requires sending a callback URL with your request, so I've set up a react-router url endpoint/component that, when onComponentDidMount fires, dispatches actions to parse the returned hash that comes from the OAuth provider, store that data in the redux store, and redirect the user to the page they originally requested, which is stored in the state parameter of the OAuth request.

This all seems very hacky. It is also difficult to manage the OAuth2 callback URL between production and development environments. Does anybody have a slick OAuth2 workflow working?

P.S. I need to get the Auth Token to the client so that it can be used to make client side API requests that use that token to check the user has access to those resources.

Answer

The following is a function that will fetch the token and expiry data from google and store it in local storage. It could be modified to simply return that data as an object.

function oAuth2TokenGet() {
  // TODO: First try to get the token from sessionStorage here

  // Build the oauth request url
  const responseType = 'token';
  const clientId = 'YOUR-GOOGLE-CLIENT-ID';
  const redirectUri = 'YOUR-REDIRECT-URL';
  const scope = 'email profile';
  const prompt = 'select_account';
  const url = `https://accounts.google.com/o/oauth2/v2/auth?response_type=${responseType}&client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}&prompt=${prompt}`;

  // Open a new window
  const win = window.open(url, 'name', 'height=600,width=450');
  if (win) win.focus();

  const pollTimer = window.setInterval(() => {
    try {
      if (!!win && win.location.href.indexOf(redirectUri) !== -1) {
        window.clearInterval(pollTimer);

        // Get the URL hash with your token in it
        const hash = win.location.hash;
        win.close();

        // Parse the string hash and convert to object of keys and values
        const result = hash.substring(1)
          .split('&')
          .map(i => i.split('='))
          .reduce((prev, curr) => ({
            ...prev,
            [curr[0]]: curr[1],
          }), {});

        // Calculate when the token expires and store in the result object
        result.expires_at = Date.now() + parseInt(hash.expires_in, 10);

        //  TODO: Persist result in sessionStorage here
      }
    } catch (err) {
      // do something or nothing if window still not redirected after login
    }
  }, 100);
}