Search code examples
react-nativeexpogoogle-signindeprecation-warning

How to solve React Native expo authSession google login issue?


I wanted to implement login with google feature on my React native app. I'm using expo-cli and I used expo authSession for this.

LoginScreen.js

import * as React from "react";
import * as WebBrowser from "expo-web-browser";
import * as Google from "expo-auth-session/providers/google";
import { Button, View, Text, TouchableOpacity } from "react-native";

WebBrowser.maybeCompleteAuthSession();

export default function LoginScreen() {
  const [googleAccessToken, setGoogleAccessToken] = React.useState(null);
  const [userInfo, setUserInfo] = React.useState(false);

  const [request, response, promptAsync] = Google.useAuthRequest({
    expoClientId: "###",
    iosClientId: "###",
    androidClientId: "###",
    webClientId: "###",
  });

  React.useEffect(() => {
    if (response?.type === "success") {
      const { authentication } = response;
      setGoogleAccessToken(authentication.accessToken);
      fetchUserInfo();
    }
    
  }, [response]);

  const fetchUserInfo = () => {
    if (googleAccessToken) {
      fetch("https://www.googleapis.com/oauth2/v3/userinfo", {
        headers: { Authorization: `Bearer ${googleAccessToken}` },
      })
        .then((response) => response.json())
        .then((userInfoObj) => {
          setUserInfo(userInfoObj);
          console.log(userInfoObj);
        })
        .catch((err) => {
          console.log(err);
        });
    }
  };

  return (
    <View>
      <Button
        disabled={!request}
        title="Login Here"
        onPress={() => {
          promptAsync();
        }}
      />

      {userInfo ? <Text>{userInfo.email}</Text> : <Text>Nope</Text>}
    </View>
  );
}

But once, I click LOGIN HERE button and login with google account it doesn't set userInfo state in the first time. I have to click LOGIN HERE button again to login. Even though I have authenticated with google, it doesn't set userInfo state in the first time. But once I click LOGIN HERE again and after continue the process, then it works. How can I solve this issue?

Also I'm getting this warning as well.

Warning

EventEmitter.removeListener('url', ...): Method has been deprecated. Please instead use `remove()` on the subscription returned by `EventEmitter.addListener`.
at node_modules/react-native/Libraries/vendor/emitter/_EventEmitter.js:164:4 in EventEmitter#removeListener
at node_modules/react-native/Libraries/EventEmitter/NativeEventEmitter.js:108:4 in removeListener
at node_modules/react-native/Libraries/Linking/Linking.js:57:4 in removeEventListener
at node_modules/expo-web-browser/build/WebBrowser.js:354:4 in _stopWaitingForRedirect
at node_modules/expo-web-browser/build/WebBrowser.js:347:31 in _openAuthSessionPolyfillAsync

Solution

  • I found the answer for this question by myself. You need to put fetchUserInfo() inside useEffect.

    import * as React from "react";
    import * as WebBrowser from "expo-web-browser";
    import * as Google from "expo-auth-session/providers/google";
    import { Button, View, Text, TouchableOpacity } from "react-native";
    
    WebBrowser.maybeCompleteAuthSession();
    
    export default function LoginScreen() {
      const [googleAccessToken, setGoogleAccessToken] = React.useState(null);
      const [userInfo, setUserInfo] = React.useState(false);
    
      const [request, response, promptAsync] = Google.useAuthRequest({
        expoClientId: "###",
        iosClientId: "###",
        androidClientId: "###",
        webClientId: "###",
      });
    
      React.useEffect(() => {
        const fetchUserInfo = () => {
          if (googleAccessToken) {
            fetch("https://www.googleapis.com/oauth2/v3/userinfo", {
              headers: { Authorization: `Bearer ${googleAccessToken}` },
            })
              .then(response => response.json())
              .then(userInfoObj => {
                setUserInfo(userInfoObj);
                console.log(userInfoObj);
              })
              .catch(err => {
                console.log(err);
              });
          }
        };
        if (response?.type === "success") {
          const { authentication } = response;
          setGoogleAccessToken(authentication.accessToken);
          fetchUserInfo();
        }
      }, [response]);
    
      return (
        <View>
          <Button
            disabled={!request}
            title="Login Here"
            onPress={() => {
              promptAsync();
            }}
          />
    
          {userInfo ? <Text>{userInfo.email}</Text> : <Text>Nope</Text>}
        </View>
      );
    }