Firebase
Setup with Firebase
Before we get started, you have to setup the firebase config through google. This is really simple and all you need is your google account. Follow the link below, specifically the Create a Firebase project section.
Dependencies
Before you can start using Firebase, you'll need to install the Firebase SDK. In your project directory, run:
npm install firebase
This will add Firebase to your project's dependencies.
Auth Object
The Auth object in Firebase is central to handling user authentication. It provides methods for managing users, including creating new users, signing in, signing out, and resetting passwords.
App Object
The App object is the heart of your Firebase project. It’s initialized with your Firebase configuration and gives you access to the various Firebase services like Authentication, Firestore, and more.
Helper Functions
Helper functions are used to simplify and streamline interactions with Firebase services. For example, functions to sign users in, sign users out, or send a password reset email can be abstracted into reusable helper functions.
Sample Code
App and Auth
Here is how you set up your Firebase app and authentication:
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
// your config
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
export { app, auth };
Helper Functions
Here’s a set of helper functions to manage Firebase authentication tasks like signing in with email and password, signing in with Google, and more:
import { auth } from "./firebase";
import {
createUserWithEmailAndPassword,
signInWithEmailAndPassword,
sendPasswordResetEmail,
sendEmailVerification,
updatePassword,
signInWithPopup,
GoogleAuthProvider,
} from "firebase/auth";
export const doCreateUserWithEmailAndPassword = async (email, password) => {
return createUserWithEmailAndPassword(auth, email, password);
};
export const doSignInWithEmailAndPassword = (email, password) => {
return signInWithEmailAndPassword(auth, email, password);
};
export const doSignInWithGoogle = async () => {
const provider = new GoogleAuthProvider();
const result = await signInWithPopup(auth, provider);
const user = result.user;
// Add user to Firestore (optional)
};
export const doSignOut = () => {
return auth.signOut();
};
export const doPasswordReset = (email) => {
return sendPasswordResetEmail(auth, email);
};
export const doPasswordChange = (password) => {
return updatePassword(auth.currentUser, password);
};
export const doSendEmailVerification = () => {
return sendEmailVerification(auth.currentUser, {
url: `${window.location.origin}/home`,
});
};
Login with Tailwind CSS for Styling
Below is an example of a login component using React, Firebase, and Tailwind CSS for styling. This component handles user login via email and password or Google Sign-In:
import React, { useState } from 'react';
import { Navigate, Link } from 'react-router-dom';
import { Input, Checkbox, Button, Typography } from "@material-tailwind/react";
import { doSignInWithEmailAndPassword, doSignInWithGoogle } from '../../../firebase/auth';
import { useAuth } from '../../../contexts/authContext';
import { addUserToDictionary } from '@/data/AsyncFunctions/getAddUserAccount';
export function Login() {
const { userLoggedIn } = useAuth();
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [isSigningIn, setIsSigningIn] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const onSubmit = async (e) => {
e.preventDefault();
if (!isSigningIn) {
setIsSigningIn(true);
try {
await doSignInWithEmailAndPassword(email, password);
} catch (err) {
setErrorMessage('Failed to sign in');
} finally {
setIsSigningIn(false);
}
}
};
const onGoogleSignIn = async (e) => {
e.preventDefault();
if (!isSigningIn) {
setIsSigningIn(true);
try {
await doSignInWithGoogle();
} catch (err) {
setErrorMessage('Failed to sign in with Google');
} finally {
setIsSigningIn(false);
}
}
};
if (userLoggedIn) {
return <Navigate to='/home' replace />;
}
return (
<section className="m-8 flex gap-4">
<div className="w-full lg:w-3/5 mt-24">
<div className="text-center">
<Typography variant="h2" className="font-bold mb-4">Sign In</Typography>
<Typography variant="paragraph" color="blue-gray" className="text-lg font-normal">Enter your email and password to Sign In.</Typography>
</div>
<form onSubmit={onSubmit} className="mt-8 mb-2 mx-auto w-80 max-w-screen-lg lg:w-1/2">
<div className="mb-1 flex flex-col gap-6">
<Typography variant="small" color="blue-gray" className="-mb-3 font-medium">Your email</Typography>
<Input
type="email"
size="lg"
placeholder="name@mail.com"
className="!border-t-blue-gray-200 focus:!border-t-gray-900"
labelProps={{ className: "before:content-none after:content-none" }}
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<Typography variant="small" color="blue-gray" className="-mb-3 font-medium">Password</Typography>
<Input
type="password"
size="lg"
placeholder="********"
className="!border-t-blue-gray-200 focus:!border-t-gray-900"
labelProps={{ className: "before:content-none after:content-none" }}
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
{errorMessage && <Typography variant="small" color="red" className="font-bold">{errorMessage}</Typography>}
<Checkbox
label={
<Typography variant="small" color="gray" className="flex items-center justify-start font-medium">
I agree to the
<a href="#" className="font-normal text-black transition-colors hover:text-gray-900 underline">Terms and Conditions</a>
</Typography>
}
containerProps={{ className: "-ml-2.5" }}
/>
<Button type="submit" className={`mt-6 ${isSigningIn ? 'bg-gray-300 cursor-not-allowed' : 'bg-indigo-600 hover:bg-indigo-700'} `} fullWidth disabled={isSigningIn}>
{isSigningIn ? 'Signing In...' : 'Sign In'}
</Button>
<div className="flex items-center justify-between gap-2 mt-6">
<Checkbox
label={<Typography variant="small" color="gray" className="flex items-center justify-start font-medium">Subscribe me to newsletter</Typography>}
containerProps={{ className: "-ml-2.5" }}
/>
<Typography variant="small" className="font-medium text-gray-900">
<a href="#">Forgot Password</a>
</Typography>
</div>
<div className="space-y-4 mt-8">
<Button
size="lg"
color="white"
className={`flex items-center gap-2 justify-center shadow-md ${isSigningIn ? 'cursor-not-allowed' : 'hover:bg-gray-100'} `}
fullWidth
onClick={onGoogleSignIn}
disabled={isSigningIn}
>
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clipPath="url(#clip0_1156_824)">
<path d="M16.3442 8.18429C16.3442 7.64047 16.3001 7.09371 16.206 6.55872H8.66016V9.63937H12.9813C12.802 10.6329 12.2258 11.5119 11.3822 12.0704V14.0693H13.9602C15.4741 12.6759 16.3442 10.6182 16.3442 8.18429Z" fill="#4285F4" />
<path d="M8.65974 16.0006C10.8174 16.0006 12.637 15.2922 13.9627 14.0693L11.3847 12.0704C10.6675 12.5584 9.7415 12.8347 8.66268 12.8347C6.5756 12.8347 4.80598 11.4266 4.17104 9.53357H1.51074V11.5942C2.86882 14.2956 5.63494 16.0006 8.65974 16.0006Z" fill="#34A853" />
<path d="M4.16852 9.53356C3.83341 8.53999 3.83341 7.46411 4.16852 6.47054V4.40991H1.51116C0.376489 6.67043 0.376489 9.33367 1.51116 11.5942L4.16852 9.53356Z" fill="#FBBC04" />
<path d="M8.65974 3.16644C9.80029 3.1488 10.9026 3.57798 11.7286 4.36578L14.0127 2.08174C12.5664 0.72367 10.6469 -0.0229773 8.65974 0.000539111C5.63494 0.000539111 2.86882 1.70548 1.51074 4.40987L4.1681 6.4705C4.8001 4.57449 6.57266 3.16644 8.65974 3.16644Z" fill="#EA4335" />
</g>
<defs>
<clipPath id="clip0_1156_824">
<rect width="16" height="16" fill="white" transform="translate(0.5)" />
</clipPath>
</defs>
</svg>
{isSigningIn ? 'Signing In...' : 'Sign in With Google'}
</Button>
<Button
size="lg"
color="white"
className={`flex items-center gap-2 justify-center shadow-md ${isSigningIn ? 'cursor-not-allowed' : 'hover:bg-gray-100'} `}
fullWidth
disabled={isSigningIn}
>
<img src="/img/twitter-logo.svg" height={24} width={24} alt="" />
{isSigningIn ? 'Signing In...' : 'Sign in With Twitter'}
</Button>
</div>
<Typography variant="paragraph" className="text-center text-blue-gray-500 font-medium mt-4">
Not registered?
<Link to="/sign-up" className="text-gray-900 ml-1">Create account</Link>
</Typography>
</form>
</div>
<div className="w-2/5 h-full hidden lg:block">
<img
src="/img/pattern.png"
className="h-full w-full object-cover rounded-3xl"
/>
</div>
</section>
);
}
export default Login;
Going Forward
The app and useAuth object are now very powerful because they store user information that allows you to create a dynamic user experience. to use you just have to import them wherever they are needed.