Authentication with Firebase
Melih Şahin
Posted on February 12, 2024
Hello there
In today's article, I will tell you how to authenticate using firebase in the Next js project.
First of all, without doing this process, we need to log in to firebase with our google account and create a project. Let's perform these steps in order.
Let's go to https://firebase.google.com and log in with our google account. A screen like the one below will greet us.
By clicking on the Create a project button, we create our project by naming it.
When we complete the steps and create the project, it shows us a screen like the one below.
When we come to the console panel, we save our web application by selecting the web section I show with the red arrow and get the information to add the firebase sdk to our project.
We create a next js project in our local and then include the firebase package in our project. We will use the firebase config information it gives us on the screen by adding it to our environment file.
After completing the above process, we have one last action to do on the console screen. We need to go to the Authentication section and select our authentication method from the "sign-in method" tab. Since we want to authenticate with email and password in this article, we select "email/password" from the native providers section.
We need to click on the "email/password" field and activate it. Then we save and complete our operations with the console.
Now let's go back to our next js project and create the protected route that only logged in users can see.
login.tsx
"use client";
import * as Yup from "yup";
import Link from "next/link";
import { useFormik } from "formik";
import { redirect } from "next/navigation";
import toast, { Toaster } from "react-hot-toast";
import { Button } from "@nextui-org/react";
import EmailInput from "@/components/emailInput/EmailInput";
import PasswordInput from "@/components/passwordInput/PasswordInput";
import { useAuthState } from "react-firebase-hooks/auth";
import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "@/lib/firebaseConfig";
const Login = () => {
const [user, loading] = useAuthState(auth);
const validationSchema = Yup.object().shape({
email: Yup.string()
.email("invalid or incomplete email")
.max(50, "email is too long")
.required("required"),
password: Yup.string()
.min(6, "password is too short must be at least 6 characters")
.required("required"),
});
const formik = useFormik({
initialValues: {
email: "",
password: "",
},
validationSchema,
onSubmit: async ({
email,
password,
}: {
email: string;
password: string;
}) => {
const res = await signInWithEmailAndPassword(auth, email, password);
if (res?.user) {
sessionStorage.setItem("user", "true");
redirect("/");
} else {
toast.error("Check your user information!");
}
},
});
const { errors, values, touched, handleSubmit, handleChange, isSubmitting } =
formik;
if (typeof window !== "undefined") {
if (user && sessionStorage.getItem("user")) return redirect("/");
}
if (loading) return <p>Checking...</p>;
return (
<div className="flex min-h-screen items-center justify-center bg-black">
<div className="flex w-full max-w-md flex-col rounded-lg bg-white p-8 shadow-md">
<div className="text-black-1 mb-12 flex flex-col items-center justify-center gap-y-3">
<p className="text-2xl font-bold">Example App</p>
</div>
<form
noValidate
onSubmit={handleSubmit}
className="flex flex-col gap-y-6"
>
<Toaster position="top-right" />
<EmailInput
handleChange={handleChange}
values={values}
errors={errors}
touched={touched}
/>
<PasswordInput
handleChange={handleChange}
values={values}
errors={errors}
touched={touched}
/>
<Button
fullWidth={true}
type="submit"
color="success"
className="bg-primary rounded-lg px-6 py-3.5 text-lg text-white hover:bg-blue-600"
isLoading={isSubmitting}
>
Login
</Button>
</form>
<p className="mt-4 text-center text-sm text-gray-600">
<Link href="/signup" className="text-blue-500">
Sign up
</Link>
</p>
</div>
</div>
);
};
export default Login;
signup.tsx
"use client";
import * as Yup from "yup";
import Link from "next/link";
import { useFormik } from "formik";
import { redirect } from "next/navigation";
import { auth } from "@/lib/firebaseConfig";
import { updateProfile } from "firebase/auth";
import toast, { Toaster } from "react-hot-toast";
import { Button, Input } from "@nextui-org/react";
import { useAuthState } from "react-firebase-hooks/auth";
import { createUserWithEmailAndPassword } from "@firebase/auth";
import EmailInput from "@/components/emailInput/EmailInput";
import PasswordInput from "@/components/passwordInput/PasswordInput";
const Signup = () => {
const [user, loading] = useAuthState(auth);
const validationSchema = Yup.object().shape({
fullName: Yup.string().required("required"),
email: Yup.string()
.email("invalid or incomplete email")
.max(50, "email is too long")
.required("required"),
password: Yup.string()
.min(6, "password is too short must be at least 6 characters")
.required("required"),
});
const formik = useFormik({
initialValues: {
email: "",
fullName: "",
password: "",
},
validationSchema,
onSubmit: async ({
email,
password,
fullName,
}: {
email: string;
password: string;
fullName: string;
}) => {
const res = await createUserWithEmailAndPassword(auth, email, password);
await updateProfile(auth?.currentUser as any, {
displayName: fullName,
photoURL: "https://i.pravatar.cc/150?u=a04258114e29026302d",
});
res?.user ? sessionStorage.setItem("user", "true") : toast.error("error");
},
});
const { errors, values, touched, handleSubmit, handleChange, isSubmitting } =
formik;
if (typeof window !== "undefined") {
if (user && sessionStorage.getItem("user")) return redirect("/login");
}
if (loading) return <p>Checking...</p>;
return (
<div className="flex min-h-screen items-center justify-center bg-black">
<div className="flex w-full max-w-md flex-col rounded-lg bg-white p-8 shadow-md">
<div className="text-black-1 mb-12 flex flex-col items-center justify-center gap-y-3">
<p className="text-2xl font-bold">Example App</p>
</div>
<form
noValidate
onSubmit={handleSubmit}
className="flex flex-col gap-y-6"
>
<Toaster position="top-right" />
<div>
<Input
size="lg"
type="text"
label="User name"
name="fullName"
labelPlacement="outside"
placeholder="Enter your name"
onChange={handleChange}
value={values?.fullName}
errorMessage={errors?.fullName}
isInvalid={(errors?.fullName && touched?.fullName) as boolean}
/>
</div>
<EmailInput
handleChange={handleChange}
values={values}
errors={errors}
touched={touched}
/>
<PasswordInput
handleChange={handleChange}
values={values}
errors={errors}
touched={touched}
/>
<Button
fullWidth={true}
type="submit"
color="success"
className="green-1 rounded-lg px-6 py-3.5 text-lg text-white hover:bg-green-600"
isLoading={isSubmitting}
>
Sign up
</Button>
</form>
<p className="mt-4 text-center text-sm text-gray-600">
<Link href="/login" className="text-blue-500">
Sign in
</Link>
</p>
</div>
</div>
);
};
export default Signup;
The part that integrates the firebase service into our project:
/lib/firebaseConfig.ts
import { getApp, getApps, initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};
const app = !getApps().length ? initializeApp(firebaseConfig) : getApp();
const auth = getAuth(app);
export { app, auth };
getApp() is the function that returns us our application registered in firebase.
initializeApp() is a function that takes our firebase environment information as a parameter to create an application object.
const app = !getApps().length ? initializeApp(firebaseConfig) : getApp();
getAuth() function returns the authentication provider according to the firebase application object we created (in our application we chose this provider as email/password)
signup.tsx
const res = await createUserWithEmailAndPassword(auth, email, password);
createUserWithEmailAndPassword() is used to create a new user on firebase side according to email and password.
updateProfile() is used to assign properties such as profile picture, full name to the created user.
Using the "react-firebase-hooks" package, we can access the logged in user information.
login.tsx
const [user, loading] = useAuthState(auth);
You can access the source codes of the sample project from this link. 🔗
Continue with content 🚀
You can access my other content by clicking this link. I would be very happy if you like and leave a comment 😇
Posted on February 12, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.