My project was created using vite + react-js. I have google auth enabled in my Supabase project with Client IDs etc, already configured from Google Cloud on Supabase already.
As I tested on localhost so I have the URL whitelisted in my Supabase project as well:
Below is how I'll implement it in my ReactJS project.
Install this first:
yarn add @supabase/supabase-js
Add a file AuthContext.tsx in your lib folder, and add this code:
import { createContext, useContext, useEffect, useState } from "react";
import type { ReactNode } from "react";
import type { Session, User } from "@supabase/supabase-js";
import { supabase } from "@/lib/supabaseClient";
import { toast } from "sonner";
type UserProfile = {
  name: string;
  email: string;
  avatarUrl: string;
};
type AuthContextValue = {
  user: User | null;
  session: Session | null;
  profile: UserProfile | null;
  isLoading: boolean;
  signInWithGoogle: () => Promise<void>;
  signOut: () => Promise<void>;
};
const AuthContext = createContext<AuthContextValue | undefined>(undefined);
const extractProfile = (user: User | null): UserProfile | null => {
  if (!user) {
    return null;
  }
  const metadata = user.user_metadata ?? {};
  const name =
    metadata.full_name ||
    metadata.name ||
    metadata.user_name ||
    (user.email ? user.email.split("@")[0] : "Anonymous");
  return {
    name,
    email: user.email ?? metadata.email ?? "",
    avatarUrl: metadata.avatar_url || metadata.picture || "",
  };
};
export const AuthProvider = ({ children }: { children: ReactNode }) => {
  const [session, setSession] = useState<Session | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [isAuthenticating, setIsAuthenticating] = useState(false);
  useEffect(() => {
    const initSession = async () => {
      const { data, error } = await supabase.auth.getSession();
      if (error) {
        console.error("Failed to get session:", error);
      }
      setSession(data.session ?? null);
      setIsLoading(false);
    };
    void initSession();
    const {
      data: { subscription },
    } = supabase.auth.onAuthStateChange((_event, nextSession) => {
      setSession(nextSession);
      setIsLoading(false);
      setIsAuthenticating(false);
    });
    return () => {
      subscription.unsubscribe();
    };
  }, []);
  const signInWithGoogle = async () => {
    try {
      setIsAuthenticating(true);
      const { error } = await supabase.auth.signInWithOAuth({
        provider: "google",
        options: {
          redirectTo: window.location.origin,
        },
      });
      if (error) {
        setIsAuthenticating(false);
        toast.error("Unable to sign in with Google.");
        console.error("Error signing in:", error);
        return;
      }
      setIsAuthenticating(false);
    } catch (error) {
      setIsAuthenticating(false);
      console.error("Unexpected error signing in:", error);
      toast.error("Unexpected error signing in.");
    }
  };
  const signOut = async () => {
    try {
      setIsAuthenticating(true);
      const { error } = await supabase.auth.signOut();
      if (error) {
        setIsAuthenticating(false);
        toast.error("Unable to sign out.");
        console.error("Error signing out:", error);
        return;
      }
      setIsAuthenticating(false);
      toast.success("Signed out.");
    } catch (error) {
      setIsAuthenticating(false);
      console.error("Unexpected error signing out:", error);
      toast.error("Unexpected error signing out.");
    }
  };
  const user = session?.user ?? null;
  const value: AuthContextValue = {
    user,
    session,
    profile: extractProfile(user),
    isLoading: isLoading || isAuthenticating,
    signInWithGoogle,
    signOut,
  };
  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
export const useAuth = () => {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error("useAuth must be used within an AuthProvider");
  }
  return context;
};
Add another file named supabaseClient.ts and in it add:
import { createClient } from "@supabase/supabase-js";
const supabaseUrl = import.meta.env.YOUR_PUBLIC_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.YOUR_SUPABASE_ANON_KEY;
if (!supabaseUrl || !supabaseAnonKey) {
  throw new Error("Missing Supabase environment variables. Please set YOUR_PUBLIC_SUPABASE_URL and YOUR_SUPABASE_ANON_KEY.");
}
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
 
 
              


 
    
Top comments (0)