Error implementing Google authentication in React Native app with Expo

Overview

I am developing an app in React Native using Expo, and I am trying to implement authentication with Google. However, when I try to log in, I get an error and cannot complete the authentication flow, Despite having configured google cloud with the Oauth2 and the consent screen and having made a build and run in an emulator the app with the command “npx expo run:android”

Things that i made:

  1. I set up the google play console, created the OAuth consent screen with the publication type in Test, some test users, and created OAuth 2.0 credentials.
  2. In the OAuth2.0 I added the package name that corresponds with my expo.android.package and the SHA-1 certificate Fingerprint, pulled it using eas credentials command
    ,then in the Custom URI scheme, I enabled the checkbox, otherwise it wouldn’t work directly for me.
  3. I implemented the google auth functionality with the library expo-auth-session with the provider providers/google
  4. I have created a build using the command npx expo run:android to run the app on an emulator, as I’ve seen in several videos

A small aside
Before I had the authentication working, but now it doesn’t work anymore, so I have generated new credentials with the “eas credentials” and added the new sha1key in the new OAuth2 credential, actually using (1), as Default.

enter image description here

Result:

Even though the browser opens, allows me to select a user, and provides the requested data,
Once it closes, I don’t receive the user’s information for some reason.

enter image description here
enter image description here

And the console.log “response” is always null…

My code of the log-in Page:

import React, {useContext, useEffect, useState} from 'react';
import {Form, H4, Spinner, Input, View, Text, H6} from 'tamagui'
import {Button} from "tamagui.config"
import {Pressable, SafeAreaView, Platform, Image, StyleSheet} from "react-native";
import {loadUser, login, register} from "~/services/AuthService";
import * as WebBrowser from "expo-web-browser";
import * as Google from "expo-auth-session/providers/google";
import {getUserInfo} from "~/services/GoogleAuthService";
import {useAuth} from "~/contexts/NewAuthContext";
import {useRouter} from "expo-router";

WebBrowser.maybeCompleteAuthSession();

// @ts-ignore
const Login = () => {
  const { signIn } = useAuth();
  const router = useRouter()
  const [isLoadingLogin, setIsLoadingLogin] = useState(false)
  const [email, setEmail] = useState("")
  const [password, setPassword] = useState("")
  const [errors, setErrors] = useState({})
  // const {setUser} = useContext(AuthContext);

  const [request, response, promptAsync] = Google.useAuthRequest({
    androidClientId: "....CLIENT_ID.....",
  })

  useEffect(() => {
    handleSingInWithGoogle()
  }, [response])

  async function handleSingInWithGoogle(){
    // Here the response is always "null"....
    console.log("response", response)
    if(response?.type === "success"){
      // It never happens because it is always null...
      console.log("response success", response)
      const googleAccessToken = response.authentication.accessToken

      const googleUserData = await getUserInfo(googleAccessToken)

      try {
        await register({
          "email": googleUserData.email,
          "name": googleUserData.given_name,
          "surname": googleUserData.family_name,
          "picture": googleUserData.picture,
          "google_id": googleUserData.id,
          "register_type": "google_auth",
          "device_name": `${Platform.OS} - ${Platform.Version}`
        })
        const user = await loadUser();
        signIn(user)
      } catch (e) {
        console.error("error login-in with google")
      }
    }
  }

  function validateForm() {
    const newErrors = {};

    if (!email.trim()) {
      newErrors.email = "empty";
    }

    if (!password.trim()) {
      newErrors.password = "empty";
    }

    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  }

  async function submitLoginForm(){
    try {
      setIsLoadingLogin(true)

      // Solo continúa si la validación es exitosa
      if (!validateForm()) {
        return; // Detiene la ejecución si hay errores
      }

      await login({
        email,
        password,
        device_name: `${Platform.OS} - ${Platform.Version}`
      });

      const user = await loadUser();
      console.info("login function user : ", user)
      signIn(user)

    } catch(e){
      if (e.response.status === 422){
        setErrors({password: "credentials not found"});
      }
    } finally {
      setIsLoadingLogin(false)
    }
  }

  function redirectRegister() {
    setErrors({})
    router.push("/(auth)/register")
  }

  return (
    <SafeAreaView style={{flex: 1, backgroundColor: "#e3e3e3"}}>
        <Form
          display="flex"
          justifyContent="center"
          alignItems="center"
          gap="$2"
          height={550}
          onSubmit={() => submitLoginForm()}
          backgroundColor="#e3e3e3"
          padding="$10"
        >
          <H4>Log-in</H4>

          <View minWidth={350} marginVertical={12} flex={1} gap={10}>
            <View marginBottom={10}>
              <Input
                placeholder="Email"
                value={email}
                onChangeText={(text) => {
                  setEmail(text);
                  // Limpia el error cuando el usuario empieza a escribir
                  if (errors.email) {
                    setErrors(prev => ({ ...prev, email: null }));
                  }
                }}
                keyboardType="email-address"
                autoCapitalize="none"
              />
              {errors.email && <Text style={styles.errorText}>El email no puede estar vacio</Text>}
            </View>
            <View>
              <Input
                placeholder="Contraseña"
                value={password}
                onChangeText={setPassword}
                secureTextEntry={true}
                autoCapitalize="none"
              />
              {errors.password && errors.password !== 'credentials not found' && <Text style={styles.errorText}>La contraseña no puede estar vacía</Text>}
              {errors.password && errors.password === 'credentials not found' && <Text style={styles.errorText}>No existe ningun registro con ese email y contraseña</Text>}
            </View>

            <View>

              <Pressable
                onPress={() => promptAsync()}
                style={({ pressed }) => ({
                  flexDirection: 'row',
                  alignItems: 'center',
                  justifyContent: 'center',
                  padding: 10,
                  borderRadius: 30,
                  backgroundColor: pressed ? '#f0f0f0' : '#ffffff',
                  borderWidth: 1,
                  borderColor: '#dcdcdc',
                })}
              >
                <Text paddingRight={9} fontWeight={600} fontSize={15.5}>
                  Entrar con Google
                </Text>
                <Image
                  source={require('~/assets/images/google-logo.png')}
                  style={{
                    width: 22,
                    height: 22,
                  }}
                />
              </Pressable>
            </View>

            <Form.Trigger asChild disabled={isLoadingLogin}>
              <Button theme="blue" icon={isLoadingLogin ? () => <Spinner /> : undefined}>
                {isLoadingLogin ? 'Iniciando sesión...' : 'Iniciar sesión'}
              </Button>
            </Form.Trigger>
          </View>

        </Form>
    </SafeAreaView>
  )
}


export default Login;