Kinde and edge worker services
Integrations
Firebase is a comprehensive app development platform by Google, offering tools and services to streamline backend processes like real-time databases, cloud storage, and more.
In this article, we’ll walk through building a secure and scalable guestbook application by integrating Firebase Firestore with Kinde Auth. By combining Firestore’s real-time database capabilities with Kinde’s seamless authentication, you’ll ensure that only authenticated users can post and view messages, creating a functional foundation you can easily expand with more advanced features.
Go to your Firebase console and select Create a new Firebase project.
Enter the name of your project and select Continue.
Switch off Enable Google Analytics for this project and select Create project.
Your Firebase project is created. Select continue to go to your project overview.
Select the web </> icon to configure the project for your web application.
Enter a nickname for your app and select Register app.
You will be shown the configuration steps for adding Firebase to a JavaScript project.
Take note of your Firebase configuration object.
You will need this in the upcoming steps when you add Firebase to your web application.
const firebaseConfig = { apiKey: "YOUR_FIREBASE_API_KEY", authDomain: "<DOMAIN>.firebaseapp.com", projectId: "PROJECT_ID", storageBucket: "<BUCKET_NAME>.firebasestorage.app", messagingSenderId: "SENDER_ID", appId: "YOUR_FIREBASE_APP_ID",};Select Continue to console.
Select Cloud Firestore > Create database, a pop-up appears.
Install the Firebase package in your project by running the following command in your terminal:
npm install firebaseCreate a Firebase configuration file inside the /src directory with the following command:
touch src/firebaseConfig.jsAdd the following code to the firebaseConfig.js file. Replace the firebaseConfig object with the info you obtained from the previous step. This:
db function to interact with the database// Import the functions you need from the SDKs you needimport { initializeApp } from "firebase/app";import { getFirestore } from "firebase/firestore";
// Your web app's Firebase configurationconst firebaseConfig = { apiKey: "YOUR_FIREBASE_API_KEY", authDomain: "<DOMAIN>.firebaseapp.com", projectId: "PROJECT_ID", storageBucket: "<BUCKET_NAME>.firebasestorage.app", messagingSenderId: "SENDER_ID", appId: "YOUR_FIREBASE_APP_ID",};
// Initialize Firebaseconst app = initializeApp(firebaseConfig);
// Initialize Firestoreconst db = getFirestore(app);
export { db };Select Save.
Create a new server action file by typing the following command:
touch src/app/actions.tsAdd the following code to the newly created actions.ts file.
Here’s what the code does.
addPost to call from the form page:
/login route/guestbook route once completed"use server";
import { db } from "@/firebaseConfig";import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";import { addDoc, collection } from "firebase/firestore";import { redirect } from "next/navigation";
export async function addPost(formData: FormData) { const { getUser } = getKindeServerSession();
const user = await getUser(); if (!user) { return redirect("/login"); }
const data = Object.fromEntries(formData.entries()); const messageObj = { kindeId: user?.id, message: data.message, timestamp: new Date(), name: user?.given_name, };
const postsCol = collection(db, "posts"); await addDoc(postsCol, messageObj);
redirect("/guestbook");}Create a new page route by typing the following command:
mkdir src/app/addtouch src/app/add/page.tsxAdd the following code to the newly created page.tsx file and Save.
This code:
addPost server action.import { addPost } from "@/app/actions";
export default async function Page() { return ( <div className="container"> <h1 className="heading">Sign the Guestbook</h1> <form className="guestbook_form" action={addPost}> <label htmlFor="message">Your Message:</label> <textarea name="message" id="message" cols={40} rows={5} required /> <br /> <button type="submit">Submit</button> </form> </div> );}Create the /guestbook route by typing the following command.
mkdir src/app/guestbooktouch src/app/guestbook/page.tsxAdd the following code to the newly created page.tsx file and Save.
This code:
posts collection in Firestore.import { db } from "@/firebaseConfig";import { collection, getDocs } from "firebase/firestore";import Link from "next/link";
export default async function Page() { const postsCol = collection(db, "posts"); const postsSnapshot = await getDocs(postsCol); const posts = postsSnapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), }));
return ( <div className="container"> <h1 className="heading">Guestbook</h1> <div> {posts.map((post) => ( <div className="guestbook_entry" key={post.id || Math.random()}> <h3 className="title">{post.name}</h3> <p className="message">{post.message}</p> </div> ))} </div> <br /> <Link className="guestbook_link" href="/add"> Sign the guestbook </Link> </div> );}Add the following CSS styles after the existing code in src/app/globals.css file:
.heading { font-size: 1.7rem; margin-bottom: 1rem;}
.guestbook_form label { display: block; font-weight: bold; margin-block: 1rem; color: gray;}
.guestbook_form textarea { padding: 10px; border-radius: 5px; border: 1px solid #ccc; margin-bottom: 10px; font-family: inherit; font-size: 1rem;}
.guestbook_form button { font-size: 1rem; padding: 7px 15px; border-radius: 5px; border: 0; background-color: black; color: #fff; cursor: pointer;}
.guestbook_entry { max-width: 500px; margin-bottom: 20px; padding: 20px; border: 1px solid #ccc; border-radius: 5px; background-color: #f9f9f9;}
.guestbook_entry .title { font-size: 1rem; margin-bottom: 1rem; color: gray;}
.guestbook_entry .message { font-size: 1rem; font-style: italic;}
.guestbook_link { background-color: #fff6b3; padding: 10px 20px; border-radius: 5px; border: 1px dashed #ccc;}
.guestbook_link:hover { text-decoration: underline;}Run the development server by running this command:
npm run devVisit http://localhost:3000/ and sign up or sign in to your project.
Go to http://localhost:3000/add to see the guestbook form in action.
Enter a message and select Submit to test it out.
You will be redirected to the /guestbook route to see the entries.
Update the add/page.tsx with the following code.
The code adds a check to see if the user is authenticated by Kinde using the isAuthenticated method.
If the user is not logged in, it will not display the input form, and prompt the user to log in first.
import { addPost } from "@/app/actions";import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server";
export default async function Page() { const { isAuthenticated } = getKindeServerSession();
if (!(await isAuthenticated())) { return <h2>You must be logged in to sign the guestbook</h2>; }
return ( <div className="container"> <h1 className="heading">Sign the Guestbook</h1> <form className="guestbook_form" action={addPost}> <label htmlFor="message">Your Message:</label> <textarea name="message" id="message" cols={40} rows={5} required /> <br /> <button type="submit">Submit</button> </form> </div> );}You can further protect your Firestore database by using appropriate security rules in the Rules section:
You have successfully integrated Firebase Firestore with Kinde Auth to create a secure and scalable guestbook application.
By combining Firestore’s real-time database capabilities with Kinde’s authentication, you’ve ensured that your app is both functional and secure for authenticated users. This set up lays the groundwork for building more advanced features and taking your app to the next level. Keep exploring, and happy coding!
If you need help, reach out to us at support@kinde.com. You can also connect with the team and other developers in the Kinde Slack community or Discord. We’re here to support you.