How to handle Google OAuth flow via redux-saga

906 views Asked by At

I am trying to implement Google OAuth 2 with with redux saga.

I have a watcher in my saga listening for GOOGLE_AUTH action which then executes googleLogin

function *watchGoogleAuth() {
   yield *takeLatest(GOOGLE_AUTH, googleLogin)
}

function *googleLogin() {
  const id_token = yield call(GoogleSignIn);
  console.log(id_token);
  const response = yield call(HttpHelper, 'google_token', 'POST', id_token, null);
  console.log(response);
}

The implementation for GoogleSignIn is in apis.js

export function GoogleSignIn() {
  const GoogleAuth = window.gapi.auth2.getAuthInstance();

    GoogleAuth.signIn({scope: 'profile email'})
      .then(
        (res) => {
          const GoogleUser = GoogleAuth.currentUser.get();
          return {
            id_token: GoogleUser.getAuthResponse().id_token
          };
        },
        (err) => {
          console.log(err)
        }
      )
}

But saga doesn't seem to wait for the GoogleSignIn to complete. As soon as OAuth consent screen pops up, saga proceeds executing the console.log without waiting for google signin promise to return actual data.

Is there any better way to handle this situation? Thanks!

1

There are 1 answers

0
Ezra Chang On

To expand on @HenrikR's answer, the generator will not wait unless it receives a promise.

export const GoogleSignIn = () => {
  const GoogleAuth = window.gapi.auth2.getAuthInstance();

  return new Promise((resolve, reject) => {
    GoogleAuth.signIn({scope: 'profile email'})
      .then(
        (res) => {
          const GoogleUser = GoogleAuth.currentUser.get();
          resolve(GoogleUser.getAuthResponse().id_token);
        },
        (err) => {
          reject(err);
        }
      );
  });
};

Accordingly, you should wrap the yield statement in a try/catch. Simplified and somewhat lazy:

function *googleLogin() {
  try {
    const id_token = yield call(GoogleSignIn);
    if (id_token) { /* Possibly with more checks and validations */
      console.log(id_token);
      const response = yield call(HttpHelper, 'google_token', 'POST', id_token, null);
      console.log(response);
    }
  } catch (e) {
    console.log(e);
  }
}