Expo Auth Session Forcing user sign in with default account

Please provide the following:

  1. SDK Version: 48
  2. Platforms(Android/iOS/web/all): iOS
  3. Add the appropriate “Tag” based on what Expo library you have a question on.

I’m building an iOS app with Google OAuth using a Google Workspace. We’ve configured out ClientID’s accordingly so that only emails form within the workspace should have access to the app. In the past we’ve successfully been able to select the user for which to use during the Google OAuth sign in.

The standing issue: Upon the promptAsync call, the webbrowser opens to show a failed sign in with the default account being automatically selected. The intermediary page that allows the user to select which account to sign in from is not shown and we get a 400 error. This is a new behavior and I’m not sure why it’s happening.

Here’s my code:

import { useRouter } from "expo-router";
import { useEffect, useState } from "react";
import { Dimensions, Image, StyleSheet } from "react-native";
import { Button, useThemeColor, View } from "../components/Themed";
import { useAppDispatch } from "../store/hooks";
import { setUserInfo, resetUserInfo } from "../store/signInSlice";
import { setMembershipProduct, setLocations, setCharities } from "../store/globalsSlice";
import axios from "axios";
import server from "../constants/Server";
import { BCBoldText, BCRegularText } from "../components/StyledText";

import * as WebBrowser from 'expo-web-browser';
import * as Google from 'expo-auth-session/providers/google';
import * as AuthSession from 'expo-auth-session';
import AsyncStorage from '@react-native-async-storage/async-storage';
import Colors from "../constants/Colors";
import objectHash from "object-hash";
import { AnimatedSelectInput, SelectionModal } from "../components/CustomerDetails";

WebBrowser.maybeCompleteAuthSession();

const version = '1.0.16';
const { width } = Dimensions.get('screen'); 

export default function () {
  const dispatch = useAppDispatch();
  const router = useRouter();
  const backgroundColor = useThemeColor({}, 'background');
  const [signedInToday, setSignedInToday] = useState(null);
  const [selections, setSelections] = useState({ store: {
    id: '',
    name: '',
  }});
  const [visible, setVisible] = useState(false);
  const [modalLocations, setModalLocations] = useState([]);
  const [userData, setUserData] = useState(null);
  // const [auth, setAuth] = useState();
  // const [requireRefresh, setRequireRefresh] = useState(false);
  
  async function getLocations() {
    const storedLocations = await AsyncStorage.getItem('locations');
    if (storedLocations !== null) {
      const locationsNodeArray = JSON.parse(storedLocations);
      const locationsArray = locationsNodeArray.map(node => node.node);
      dispatch(setLocations(locationsArray));
      setModalLocations(locationsNodeArray);
    } else {
      axios.get(server.uri + '/locations')
        .then(res => {
          const locationsNodeArray = res.data.locations.edges.map(node => ({ node: { id: node.node.id.replace('gid://shopify/Location/', ''), name: node.node.name } })).filter(e => e.node.name !== 'Returns Only');
          const locationsArray = locationsNodeArray.map(node => node.node);
          AsyncStorage.setItem('locations', JSON.stringify(locationsNodeArray));
          dispatch(setLocations(locationsArray));
          setModalLocations(locationsNodeArray);
        })
        .catch(err => console.error(err));
    }

  }

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

  useEffect(() => {
    if (response?.type === 'success') {      
      getUserInfo();
      persistAuth();
      persistStore();
    }
  }, [response]);

  useEffect(() => {
    if (selections.store.name.length === 0) persistStoreCheck();
    if (signedInToday !== null) getLocations();
    if (signedInToday) persistAuthCheck();
    else if (signedInToday === false) handleHardSignOut();
  }, [signedInToday]);

  useEffect(() => {
    getSignedInToday();
  }, []);

  async function getSignedInToday() {
    const today = new Date().toDateString();
    const lastSignIn = await AsyncStorage.getItem('lastSignIn');
    setSignedInToday(lastSignIn === today);
  }

  async function persistAuthCheck() {
    const jsonValue = await AsyncStorage.getItem('auth');
    if (jsonValue !== null) {
      getUserInfo(JSON.parse(jsonValue));
      // setAuth(JSON.parse(jsonValue));
      // setRequireRefresh(!AuthSession.TokenResponse.isTokenFresh());
    }
  }

  async function persistStoreCheck() {
    const jsonValue = await AsyncStorage.getItem('store');
    if (jsonValue !== null) {
      setSelections(JSON.parse(jsonValue));
    }
  }
  
  async function persistAuth() {
    const today = new Date().toDateString();
    await AsyncStorage.setItem('lastSignIn', today);
    await AsyncStorage.setItem('auth', JSON.stringify(response));
  }

  async function persistStore() {
    await AsyncStorage.setItem('store', JSON.stringify(selections));
  }

  async function getUserInfo(auth) {
    // console.log('getting user info');
    const userJSON = await AsyncStorage.getItem('user');
    if (userJSON !== null) {
      const user = JSON.parse(userJSON);
      dispatch(setUserInfo(user));
      setUserData(user);
      router.push('/product');
      getBackgroundData(user);
    } else {
      fetch('https://www.googleapis.com/userinfo/v2/me', {
        headers: { Authorization: `Bearer ${auth ? auth.authentication.accessToken : response.authentication.accessToken}` }
      })
      .then(data => data.json())
      .then(user => {
        user['store'] = selections.store;
        AsyncStorage.setItem('user', JSON.stringify(user));
        dispatch(setUserInfo(user));
        setUserData(user);
        return user;
      })
      .then(user => {
        router.push('/product');
        getBackgroundData(user);
      })
      .catch(err => console.error(err));
    }
  }

  async function getBackgroundData(user) {
    ...
  }

  function handleHardSignOut() {
    AsyncStorage.removeItem('user');
    AsyncStorage.removeItem('auth');
    AsyncStorage.removeItem('locations');
    AsyncStorage.removeItem('store');
    AsyncStorage.removeItem('membership');
    // AsyncStorage.removeItem('charities');
    dispatch(resetUserInfo());
    setUserData(null);
  }

  return <View style={[styles.container, { backgroundColor }]}>
    <View style={{ justifyContent: 'center', gap: 24 }}>
      <View style={{height: 48}}>
        <AnimatedSelectInput placeholder='Your Store' value={selections.store.name} lightColor={Colors.light.background} darkColor={Colors.dark.background} onPress={() => setVisible(true)} /> 
      </View>
      <Button disabled={selections.store.name.length === 0} onPress={() => promptAsync({ showInRecents: true })} style={[styles.button, selections.store.name.length === 0 ? { backgroundColor: Colors.palette.darkerGrey, opacity: 0.4 } : { backgroundColor: Colors.palette.blue }]} >
        <Image source={selections.store.name.length === 0 ? require('../assets/images/google_disabled.png') : require('../assets/images/google.png')} style={[{ height: 72, width: 72, position: 'absolute', left:-6, top:-9, bottom:0 }]} />
        <BCBoldText fontSize={width < 390 ? 24 : 28} color={Colors.palette.coolNeutral} style={{ paddingLeft: 72 }}>Sign in with Google</BCBoldText>
      </Button>
    </View>
    <View style={styles.version}>
      <BCRegularText fontSize={16} style={{ alignSelf: 'flex-start'}}>Sales Saver 2 v{version}</BCRegularText>
    </View>
    <SelectionModal visible={visible} setVisible={setVisible} selection={selections} setSelection={setSelections} data={modalLocations} field='store' itemFontSize={28} />
  </View>
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingHorizontal: 32,
  },
  button: {  
    paddingVertical: 8, 
    borderRadius: 6, 
    height: 52,
    justifyContent: 'center',
    position: 'relative',
    overflow: 'hidden', 
  },
  version: {
    position: 'absolute',
    bottom: 48,
    left: 0,
    right: 0,
    flexDirection: 'row',
    justifyContent: 'center',
    width,
  },
  debug: {
    borderWidth: 1,
    borderRadius: 6,
    borderColor: '#0f0',
  }
})

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.