Search code examples
mongodbreact-nativemongodb-stitch

How to get auth code for Google OAuth using the Mongo Stitch React-Native SDK?


From the docs it seems like there is no other way to sign-in using Google other than using the GoogleCredential constructor which takes an authCode as a mandatory parameter, how should I get it?

For an example of [[loginWithRedirect]], see Facebook Authentication

Also, there are multiple references in the docs to a function called loginWithRedirect, but they don't link anywhere and there is no property in the auth object called loginWithRedirect.


Solution

  • Indeed, the RN and server SDKs do not support the redirect concept. You have to get your own authCode.

    Stitch's GoogleCredential constructor just expects a valid server auth code so that the Stitch service can use offline access.

    Use a third-party OAuth module

    I had no luck using the official google-auth-library SDK with RN. I was able to make it work (on iOS, at least -- haven't tried Android, yet) with react-native-google-signin from react-native-community. The installation process is a bit involved, so be sure to follow their instructions carefully!

    I will show how I used this specific library to sign in. Hopefully this information can be applied to other OAuth libraries and other Authentication providers (e.g. Facebook).

    Configure GoogleSignin

    The webClientId must be specified and must match the Client ID under the Google Oauth2 configuration on the Stitch UI (see screenshot). The iosClientId is found in the GoogleService-Info.plist you download after following these steps. Finally, set offlineAccess to true.

    If you use the Google iOS SDK directly or another library, note that webClientId is called serverClientID and iosClientId is simply called clientId.

    Here's my configure code (see my complete App.js file):

    componentDidMount() {
      // ...
      GoogleSignin.configure({
        webClientId: '<id>', // from Stitch UI > Users > Providers > Google
        offlineAccess: true,
        iosClientId: '<id>', // CLIENT_ID in GoogleService-Info.plist
      });
    }
    

    Render GoogleSigninButton

    react-native-google-signin provides a nice button to use, which I rendered out (see screenshot):

    const loginButton = <GoogleSigninButton
      style={{ width: 192, height: 48 }}
      size={GoogleSigninButton.Size.Wide}
      color={GoogleSigninButton.Color.Dark}
      onPress={this._onPressLogin}
      disabled={this.state.isSigninInProgress}
    />
    

    Give Stitch the serverAuthCode from GoogleSignin

    My _onPressLogin function uses GoogleSignin to get the serverAuthCode. It then passes that code to Stitch:

    _onPressLogin = async () => {
      // They recommend calling this before signIn
      await GoogleSignin.hasPlayServices();
    
      // Call signIn to get userInfo
      const userInfo = await GoogleSignin.signIn();
    
      // Check if serverAuthCode was received -- it will be null
      // if something wasn't configured correctly. Be sure to
      // log out after changing a configuration.
      const {serverAuthCode} = userInfo;
      if (serverAuthCode === null) {
        throw new Error('Failed to get serverAuthCode!');
      }
      try {
        // Pass serverAuthCode to Stitch via GoogleCredential
        const user = await this.state.client.auth.loginWithCredential(new GoogleCredential(serverAuthCode));
        console.log(`Successfully logged in as user ${user.id}`);
        this.setState({ currentUserId: user.id });
      } catch(err) {
        console.error(`Failed to log in anonymously: ${err}`);
        this.setState({ currentUserId: undefined })
      }
    

    Logging out

    I found I had to log out several times while testing (and figuring out which client IDs to use where), or else serverAuthCode would come back null. It was good to have the logout button visible at all times. My logout code looks like this:

    _onPressLogout = async () => {
      await GoogleSignin.revokeAccess();
      await GoogleSignin.signOut();
      const user = await this.state.client.auth.logout();
      console.log(`Successfully logged out`);
      this.setState({ currentUserId: undefined })
    }
    

    I hope this helps!