Next.js এর হাতেখড়ি (পর্ব ১০) – Next.js + Firebase: Auth ও RTDB একসাথে

Next.js এবং Firebase Auth ও RTDB একসাথে

পর্ব ৯-এ Middleware সার্ভারে চলে আর Firebase Auth ব্রাউজারে — এই দ্বন্দ্বের কথা বলেছিলাম। এই পর্বে সেই সমস্যার সম্পূর্ণ সমাধান দেখব — Firebase Auth-এর সাথে সেশন কুকি জোড়া লাগানো, আর Server Component থেকে সরাসরি RTDB ব্যবহার করা।

দুটো ভিন্ন জগৎ — Client Auth vs Server Session

Firebase এর হাতেখড়ি পর্ব ২-৩-এ যা শিখেছিলাম (signInWithEmailAndPassword, onAuthStateChanged) সবই ব্রাউজারে চলে — Client Component-এর জগৎ। কিন্তু পর্ব ৪-এর Server Component-এ ডেটা আনতে বা পর্ব ৯-এর Middleware-এ Auth চেক করতে, সার্ভারেরও জানা দরকার ইউজার লগইন করা কিনা। এই দুটো জগৎ জোড়া লাগাতেই সেশন কুকি লাগে।

ধাপ ১ — লগইন (Client Component)

লগইন নিজেই এখনো ব্রাউজারে হয় — Firebase এর হাতেখড়ি পর্ব ২-এর কোডই এখানে ব্যবহার হচ্ছে, শুধু একটা অতিরিক্ত ধাপ যোগ হবে।

// app/login/LoginForm.js
"use client";
import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "../../firebase";
import { useRouter } from "next/navigation";

export default function LoginForm() {
  const router = useRouter();

  async function handleLogin(email, password) {
    const userCredential = await signInWithEmailAndPassword(auth, email, password);
    const idToken = await userCredential.user.getIdToken(); // Firebase-এর ID Token

    // ধাপ ২-এর API Route-এ পাঠানো, সেশন কুকি সেট করতে
    await fetch("/api/session", {
      method: "POST",
      body: JSON.stringify({ idToken }),
    });

    router.push("/dashboard"); // useRouter দিয়ে নেভিগেশন
  }

  // ... ফর্ম JSX ...
}

useRouter এখানে নতুন — এটা Next.js-এর নিজস্ব Hook, Client Component থেকে প্রোগ্রাম্যাটিকভাবে পেজ বদলাতে ব্যবহার হয় (পর্ব ২-এর Link কম্পোনেন্ট যেখানে ইউজার ক্লিক করে, useRouter সেখানে কোড থেকে নেভিগেট করায়)।

ধাপ ২ — সেশন কুকি সেট করা (API Route)

এই API Route Firebase-এর ID Token যাচাই করে, একটা নিরাপদ কুকি সেট করে — এখানেই সার্ভার প্রথমবার জানে ইউজার আসলেই লগইন করা।

// app/api/session/route.js
import { cookies } from "next/headers";

export async function POST(request) {
  const { idToken } = await request.json();

  // বাস্তবে এখানে Firebase Admin SDK দিয়ে idToken যাচাই করা হয়
  // (Firebase এর হাতেখড়ি পর্ব ১১-এর firebase-admin-এর মতোই)

  cookies().set("session", idToken, {
    httpOnly: true,   // JavaScript দিয়ে পড়া যাবে না, শুধু সার্ভার
    secure: true,     // শুধু HTTPS-এ পাঠানো হবে
    maxAge: 60 * 60 * 24 * 5, // ৫ দিন
  });

  return Response.json({ success: true });
}

httpOnly: true খুবই গুরুত্বপূর্ণ — এটা মানে এই কুকি ব্রাউজারের JavaScript দিয়ে পড়া যাবে না, শুধু সার্ভার-সাইড কোড (Middleware, Server Component) পড়তে পারবে। এটা XSS আক্রমণ থেকে সুরক্ষা দেয়।

ধাপ ৩ — Middleware-এ চেক (পর্ব ৯-এর প্যাটার্ন সম্পূর্ণ করা)

// middleware.js
import { NextResponse } from "next/server";

export function middleware(request) {
  const sessionCookie = request.cookies.get("session");

  if (!sessionCookie) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/dashboard/:path*"],
};

এখন পর্ব ৯-এ যে ফাঁক ছিল, সেটা পূরণ হয়ে গেলো — Firebase Auth (ব্রাউজার) → API Route (সেশন কুকি সেট) → Middleware (সেই কুকি চেক) — পুরো চক্র সম্পূর্ণ।

Server Component থেকে RTDB ব্যবহার

পর্ব ৪-এর প্যাটার্নেই Firebase এর হাতেখড়ি পর্ব ৭-এর REST API endpoint ব্যবহার করা যায় — Cloudflare এর হাতেখড়ি পর্ব ৬-এর Worker-থেকে-Firebase কলের মতোই ধারণা, শুধু এবার Next.js Server Component থেকে সরাসরি।

// app/dashboard/page.js — Server Component
import { cookies } from "next/headers";

async function getMyBooks(userId) {
  const res = await fetch(
    `https://my-first-app-default-rtdb.firebasedatabase.app/books.json?orderBy="ownerId"&equalTo="${userId}"`,
    { cache: "no-store" } // পর্ব ৫-এর SSR — ইউজার-নির্দিষ্ট ডেটা
  );
  return res.json();
}

export default async function DashboardPage() {
  const sessionCookie = cookies().get("session");
  // বাস্তবে এখানে sessionCookie থেকে userId বের করা হতো (decoded token থেকে)
  const userId = "user123";

  const books = await getMyBooks(userId);

  return (
    <div>
      <h1>আমার বইয়ের তালিকা</h1>
      <ul>
        {Object.values(books || {}).map((book, i) => (
          <li key={i}>{book.title}</li>
        ))}
      </ul>
    </div>
  );
}

এখানে কোনো useEffect, কোনো onAuthStateChanged লিসেনার লাগেনি — Middleware ইতিমধ্যে নিশ্চিত করেছে ইউজার লগইন করা, আর Server Component সরাসরি ডেটা এনে HTML হিসেবে পাঠিয়ে দিচ্ছে।

লগআউট — কুকি মুছে ফেলা

// app/actions.js — Server Action (পর্ব ৮)
"use server";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";

export async function logout() {
  cookies().delete("session");
  redirect("/login");
}

ইন্টারেক্টিভ — পুরো Auth ফ্লো

নিচে লগইন থেকে প্রোটেক্টেড ড্যাশবোর্ড দেখা পর্যন্ত পুরো প্রক্রিয়া ধাপে ধাপে দেখো।

ভালো অভ্যাস

  • সবসময় httpOnly কুকি ব্যবহার করুন — সেশন টোকেন ব্রাউজার JavaScript-এ এক্সপোজ করলে XSS আক্রমণে চুরি হতে পারে
  • প্রোডাকশনে অবশ্যই Firebase Admin SDK দিয়ে ID Token যাচাই করুন — উপরের উদাহরণে সরলীকরণের জন্য এই ধাপ বাদ দেওয়া হয়েছে, বাস্তবে এটা বাদ দিলে নিরাপত্তাহীন
  • Middleware আর RTDB Security Rules দুটোই রাখুন — Middleware UI-level সুরক্ষা দেয়, কিন্তু আসল ডেটা সুরক্ষা Firebase এর হাতেখড়ি পর্ব ৮-এর Rules-এই থাকা উচিত

নিজে চেষ্টা করো

Exercise:

  1. নিজের Next.js প্রজেক্টে Firebase SDK ইনস্টল করো, পর্ব ১-এর প্যাটার্নে firebase.js কনফিগ ফাইল বানাও।
  2. একটা লগইন ফর্ম বানাও, সফল লগইনে /api/session-এ ID Token পাঠাও।
  3. /api/session route বানাও, একটা httpOnly কুকি সেট করো।
  4. Middleware দিয়ে /dashboard প্রোটেক্ট করো, লগইন ছাড়া অ্যাক্সেস করার চেষ্টা করে দেখো রিডাইরেক্ট হচ্ছে কিনা।
  5. একটা লগআউট Server Action বানাও, কুকি মুছে ফেলে /login-এ ফিরিয়ে আনো।

পরের পর্বে যা থাকছে

পরের পর্বে আমরা শিখব Image ও SEO Optimizationnext/image দিয়ে স্বয়ংক্রিয় ছবি অপটিমাইজেশন, আর Metadata API দিয়ে প্রতিটা পেজের জন্য সঠিক title, description বসানো।

একটি মন্তব্য পোস্ট করুন

নবীনতর পূর্বতন

যোগাযোগ ফর্ম