6

I built an auth function that looks like this:

const handleLogin = async (type) => {
    const { user, error } =
      type === "LOGIN"
        ? await supabase.auth.signIn({ email, password })
        : await supabase.auth.signUp({ email, password });

    if (error) {
      alert(error);
    } else if (!user && !error) {
      alert("An email has been sent to you for verification!");
    }
  };

Fetching the jwt and getting the user:

   useEffect(() => {
    
        async () => {
          const jwt = await AsyncStorage.getItem("user");
          const currentUser = supabase.auth.api.getUser(jwt)
          console.log(currentUser)
        }
    
    
        const session = supabase.auth.session();
        setUser(session?.user ?? null);
    
        const { data: authListener } = supabase.auth.onAuthStateChange(
          async (event, session) => {
            const currentUser = session?.user;
            await AsyncStorage.setItem("user", session.access_token);
            console.log(await AsyncStorage.getItem("user"));
            setUser(currentUser ?? null);
          }
        );
    
        return () => {
          authListener?.unsubscribe();
        };
      }, [user]);

but I can't seem to find a way to keep the user logged in inside the app. everytime it restarts the user needs to login again.

Any ideas? Thanks in advance!

4 Answers 4

6

Do make sure to instantiate the supabase client with the AsyncStorage and the following options:

import AsyncStorage from '@react-native-async-storage/async-storage';
import { createClient } from '@supabase/supabase-js'

const supabaseUrl = YOUR_REACT_NATIVE_SUPABASE_URL
const supabaseAnonKey = YOUR_REACT_NATIVE_SUPABASE_ANON_KEY

export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
  localStorage: AsyncStorage as any,
  autoRefreshToken: true,
  persistSession: true,
  detectSessionInUrl: false,
});
0
2

but I can't seem to find a way to keep the user logged in inside the app. everytime it restarts the user needs to login again.

The JS library should already be detecting the user session from the AsyncStorage and restoring it automatically. You can see this logic inside the Auth lib:

Call from constructor: https://github.com/supabase/gotrue-js/blob/8d7eef85a41c5e94a1336f0f44eacc5253186e9b/src/GoTrueClient.ts#L106-L107

Which calls this function: https://github.com/supabase/gotrue-js/blob/8d7eef85a41c5e94a1336f0f44eacc5253186e9b/src/GoTrueClient.ts#L637

You should be able to just add a listener (supabase.auth.onAuthStateChange()) and it will get triggered once the library has refreshed the session. You can add the listener in a useEffect (like you do above), but without the [user] argument so that it is set up immediately.

1

I didn't want to invoke supabase client everytime I needed to access user auth info, so I made a simple context to keep track of the user session.

It loads the session the first time the component loads - since it's a provider, you wrap your app with AuthContextProvider and you should have your session restored when the app loads.

Hope this helps

import { createContext, ReactNode, useEffect, useState } from 'react';
import { Session } from '@supabase/supabase-js';
import { supabase } from '@services/supabase';
import { updateGraphqlClient } from '@services/graphql/client';
import * as SecureStore from 'expo-secure-store';

export const AuthContext = createContext<{ session: Session }>({ session: null });

export const AuthContextProvider = ({ children }: { children: ReactNode }) => {
    const [ session, setSession ] = useState<Session | null>(null);

    useEffect(() => {
        // restores session on app start
        restoreSession();

        // listener for auth changes
        supabase.auth.onAuthStateChange(async (_, session) => {
            if (session === null) {
                await SecureStore.deleteItemAsync(`supabase-token`);
                setSession(null);
            } else {
                await SecureStore.setItemAsync(`supabase-token`, session.access_token);
                setSession(session);
            }

            // triggers logic to update graphql client header with new token
            updateGraphqlClient();
        });
    }, []);

    const restoreSession = async () => {
        const { data } = await supabase.auth.getSession();
        if (data) {
            setSession(data.session);
            updateGraphqlClient();
        }
    };

    return <AuthContext.Provider value={{ session }}>{children}</AuthContext.Provider>;
};

0

You can use the following method to acheive this.

  1. Use AsyncStorage to store token locally.
  2. in UseEffect of App.js get token from AsyncStorage if user receives the token then navigate app to your Home Screen.
  3. if token is not received navigate app to login Screen.
1
  • The logic works, the problem stays where I can't get the user data: async () => { const jwt = await AsyncStorage.getItem("user"); const currentUser = supabase.auth.api.getUser(jwt) console.log(currentUser) } I get the proper data, but the session authentication somewhat isn't working. I dont get any user data and I need to login again to see it. something with my session code is faulty. added it to my question May 22, 2022 at 23:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.