%% generate tags start %% #software-engineering %% generate tags end %% #software-engineering/remix #software-engineering/supabase #software-engineering/authentication ## Set up authentication with remix 1. create a supabase project, when setting the database, make sure the location is close to vercel function deployment 2. install the supabase packages and set up the login component 3. change the provider to only google so that the UI is correct 4. change the view to `magic_link`, see https://supabase.com/docs/guides/auth/auth-helpers/auth-ui#supported-views:~:text=The%20Auth%20component%20is,on%20that%20repo. 5. add a signout button 6. try to sign in and see the user in the ==local env== %% INCOMPLETE(should combine with [[set up google auth]]) %% you final code will be something like this: ```typescript import type { MetaFunction } from "@remix-run/node"; import { useState, useEffect } from "react"; import { Session, createClient } from "@supabase/supabase-js"; import { Auth } from "@supabase/auth-ui-react"; import { ThemeSupa } from "@supabase/auth-ui-shared"; export const meta: MetaFunction = () => { return [ { title: "New Remix App" }, { name: "description", content: "Welcome to Remix!" }, ]; }; const supabase = createClient( "https://chkkxvbeomvrcnlirzww.supabase.co", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNoa2t4dmJlb212cmNubGlyend3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDUwMDI5MDUsImV4cCI6MjAyMDU3ODkwNX0.I13OaImphZrEoY5VMtSojZyKivwtpvlJi3XuttXIsMU" ); export default function App() { const [session, setSession] = useState<Session | null>(null); useEffect(() => { supabase.auth.getSession().then(({ data: { session } }) => { setSession(session); }); const { data: { subscription }, } = supabase.auth.onAuthStateChange((_event, session) => { setSession(session); }); return () => subscription.unsubscribe(); }, []); if (!session) { return ( <Auth supabaseClient={supabase} appearance={{ theme: ThemeSupa }} providers={["google"]} view="magic_link" theme="dark" /> ); } else { return ( <div> Logged in! <button onClick={() => supabase.auth.signOut()}>Signout</button> </div> ); } } ``` resources: 1. [Use Supabase Auth with React | Supabase Docs](https://supabase.com/docs/guides/auth/quickstarts/react) 2. [Auth UI | Supabase Docs](https://supabase.com/docs/guides/auth/auth-helpers/auth-ui) ## (optioanl) Replace auth UI with custom ui component It would be easier if we simply use our own custom component. Two login methods must be supported: 1. google login 2. Magic link OTP ```tsx import type { MetaFunction } from "@remix-run/node"; import { useState, useEffect, FormEventHandler } from "react"; import { Provider, Session, createClient } from "@supabase/supabase-js"; export const meta: MetaFunction = () => { return [ { title: "New Remix App" }, { name: "description", content: "Welcome to Remix!" }, ]; }; const supabase = createClient( "https://chkkxvbeomvrcnlirzww.supabase.co", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNoa2t4dmJlb212cmNubGlyend3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3MDUwMDI5MDUsImV4cCI6MjAyMDU3ODkwNX0.I13OaImphZrEoY5VMtSojZyKivwtpvlJi3XuttXIsMU" ); export default function App() { const [email, setEmail] = useState(""); const handleLogin: FormEventHandler<HTMLFormElement> = async (e) => { e.preventDefault(); const { data, error } = await supabase.auth.signInWithOtp({ email: email, options: { // set this to false if you do not want the user to be automatically signed up shouldCreateUser: true, emailRedirectTo: "http://localhost:3000", }, }); // Handle login success or error here if (error) { console.error("Error logging in:", error); } else { console.log("User logged in:", data); } }; const handleOAuthLogin = async (provider: Provider) => { const { data, error } = await supabase.auth.signInWithOAuth({ provider, }); // Handle OAuth login success or error here if (error) { console.error("Error logging in:", error); } else { console.log("OAuth login successful:", data); } }; const [session, setSession] = useState<Session | null>(null); useEffect(() => { supabase.auth.getSession().then(({ data: { session } }) => { setSession(session); }); const { data: { subscription }, } = supabase.auth.onAuthStateChange((_event, session) => { setSession(session); }); return () => subscription.unsubscribe(); }, []); if (!session) { return ( <div> <form onSubmit={handleLogin}> <input type="email" placeholder="Your email" value={email} onChange={(e) => setEmail(e.target.value)} /> <button type="submit">Sign In</button> </form> <button onClick={() => handleOAuthLogin("google")}> Sign in with Google </button> </div> ); } else { return ( <div> Logged in! <button onClick={() => supabase.auth.signOut()}>Signout</button> </div> ); } } ``` ## What is next? > [!warning] now you should be sign in the user in the local env but not able to do this in preview and production because you haven’t set up the env yet. 1. [[set up tailwind in remix]] 2. [[Set up env in remix]]