How to solve React Native expo authSession google login issue?

Viewed 149

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
1 Answers

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>
  );
}
Related