react-nativeexposupabasesupabase-js

react native supabase auth with google - no session update


I am setting up an android app using rn & expo. I have supabase auth setup for my web app but am stuck trying to set it up on android. The google auth "Choose an account" prompt appears as expected, but when I select an account to login, my session state doesn't update in my console.log check:

useEffect(() => {
    console.log('session changed...') //does not fire besides on initial null value
    console.log(session) //does not fire besides on initial null value
  }, [session])

For my setup I have...

Created Google OAuth Client ID in Google Cloud Console using $ cd android && ./gradlew signingReport's 'debug' config SHA1 and the android package name in app.json.

Configured my OAuth Consent Screen using my supabase url as an authorized domain.

Added my OAuth Client ID to the Google provider on the Supabase Dashboard, using a comma to separate from my web-app auth Client ID

Setup my Supabase login component (4):

import { AppState } from 'react-native'
import 'react-native-url-polyfill/auto'
import AsyncStorage from '@react-native-async-storage/async-storage'
import { createClient } from '@supabase/supabase-js'

const YOUR_REACT_NATIVE_SUPABASE_ANON_KEY = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY
const YOUR_REACT_NATIVE_SUPABASE_URL = process.env.EXPO_PUBLIC_SUPABASE_PROJECT_URL

const supabaseUrl = YOUR_REACT_NATIVE_SUPABASE_URL
const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_ANON_KEY

export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
  
  auth: {
    storage: AsyncStorage,
    autoRefreshToken: true,
    persistSession: true,
    detectSessionInUrl: false,
  },
})


// Tells Supabase Auth to continuously refresh the session automatically
// if the app is in the foreground. When this is added, you will continue
// to receive 'onAuthStateChange' events with the 'TOKEN_REFRESHED' or
// 'SIGNED_OUT' event if the user's session is terminated. This should
// only be registered once.
AppState.addEventListener('change', (state) => {
  if (state === 'active') {
    supabase.auth.startAutoRefresh()
  } else {
    supabase.auth.stopAutoRefresh()
  }
})

Added my session state in my app (6):

import 'react-native-url-polyfill/auto'
import { useState, useEffect } from 'react'
import { supabase } from './lib/supabase'
import Auth from './components/Auth'
import { View, Text } from 'react-native'
import { Session } from '@supabase/supabase-js'

export default function App() {
  const [session, setSession] = useState<Session | null>(null)

  useEffect(() => {
    supabase.auth.getSession().then(({ data: { session } }) => {
      setSession(session)
    })

    supabase.auth.onAuthStateChange((_event, session) => {
      setSession(session)
    })
  }, [])
  //...
}

Setup my auth signup button:

import {
    GoogleSignin,
    GoogleSigninButton,
    statusCodes,
  } from '@react-native-google-signin/google-signin'
  import { supabase } from '../hooks/supabase'
  import { Pressable } from 'react-native'
  import AntDesign from '@expo/vector-icons/AntDesign';

  const webClientId = process.env.EXPO_PUBLIC_GOOGLE_AUTH_ANDROID_CLIENT_ID
  
  export default function GoogleSigninButtonAndroid () {
    GoogleSignin.configure({
      scopes: ['https://www.googleapis.com/auth/drive.readonly'],
      webClientId: webClientId,
    })

    return (
      <Pressable
        style={{
          padding: 12,
          marginTop: 4
        }}
        onPress={async () => {
          try {
            await GoogleSignin.hasPlayServices()
            console.log('sign in pressed')
            const userInfo = await GoogleSignin.signIn()
            if (userInfo.data.idToken) {
              console.log('signed in')
              const { data, error } = await supabase.auth.signInWithIdToken({
                provider: 'google',
                token: userInfo.data.idToken,
              })
              console.log(error, data)
            } else {
              throw new Error('no ID token present!')
            }
          } catch (error: any) {
            if (error.code === statusCodes.SIGN_IN_CANCELLED) {
              // user cancelled the login flow
            } else if (error.code === statusCodes.IN_PROGRESS) {
              // operation (e.g. sign in) is in progress already
            } else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
              console.log('play')
              // play services not available or outdated
            } else {
              // some other error happened
            }
          }
        }}
      >
        <AntDesign name="google" size={26} color="black" />

      </Pressable>
    )
  }

Updated app.json to accomodate react-native-google-signin:

{
  "expo": {
    "plugins": ["@react-native-google-signin/google-signin"],
    "android": {
      "googleServicesFile": "./google-services.json"
    },
    "ios": {
      "googleServicesFile": "./GoogleService-Info.plist"
    }
  }
}

And rebuilt the app npx expo prebuild --clean, npx expo run:android && npx expo run:ios

I am expecting the supabase auth session state to populate when I select an account on my google auth popup, but it does not change.


Solution

  • This worked for me! I used the wrong SHA1 when setting up Google OAuth Client ID in Google Cloud Console. $ cd android && ./gradlew signingReport gives you the right SHA1, use debug variant when running npx expo run:android

    I found the solution here: React-native google signin gives Developer Error