Skip to main content

Authentication

Problem​

Supabase uses email and password for auth but this project only uses username and password and is currently not supported as of writing this (1/4/2023).
If authentication method is done through tables this will give up the supabase sdk and other features like providers.

Solution​

There's a work around suggested by the community and that is to put suffix in the front end before authenticating @fakeemail.com supabase then will consider it an email and will work.


Client side validation​

Formik and Yup are used to handle all client side validation.

Login and Register​

The code will speak for itself it is written pretty well - Vergara, Mark Matthew

const authHandler = async () => {
setIsLoading(true);

const email = usernameToEmail(formik.values.username);
const password = formik.values.password;
const userData = { email, password };

let error: AuthError | null = null;
let response: AuthResponse | null = null;

if (formState == "Login") response = await supabase.auth.signInWithPassword(userData);
if (formState === "Signup") response = await supabase.auth.signUp(userData);
if (response) error = response.error || null;

if (error) {
setAuthError(error?.message || "Error Occured");
} else {
toast.success("Authenticated");
router.push("/");
setAuthError(null);
}
setIsLoading(false);
};

using the supabase sdk built in method for authentication

Logout​

Using the supabase sdk a simple function will log the user out

  const logoutHandler = async () => {
const { error } = await supabase.auth.signOut();
if (error) toast.error(error.message);
if (!error) toast.success("Logout Success");
Router.push("/auth");
};

Role Context API​

App wide state that takes the user role info which are "user" and "admin" this will help to conditionally render some ui depending on the role of the user. Ofcourse when it comes to routes additional checks are made in the server side to make sure only user with "x" role can access that route.

type role = "user" | "admin" | null;
export const RoleContext = createContext<role>(null);
export const RoleContextProvider = (props: JSX.Element) => {
const supabase = useSupabaseClient<DatabaseTypes>();
const user = useUser();
const [role, setRole] = useState<role>(null);
useEffect(() => {
const setRoleFromPofile = async () => {
if (!user?.id) {
setRole(null);
return;
}
console.log("AUTH CONTEXT USE EEFFECT");
const { data, error } = await supabase.from("profiles").select("*").eq("id", user.id).maybeSingle();
if (error) {
toast.error(error.message);
return;
}
if (!data) {
setRole(null);
return;
}

let role: role = null;
if (data.role === "admin") role = data.role;
if (data.role === "user") role = data.role;
setRole(role);
};
setRoleFromPofile();
}, [user]);

return <RoleContext.Provider value={role} {...props} />;
};

export const useUserRole = () => {
const context = useContext(RoleContext);
if (context === undefined) {
throw new Error("useRole must be used within a RoleContextProvider.");
}
return context;
};