วันจันทร์ที่ 24 มีนาคม พ.ศ. 2568

วิธีใช้ Auth0 กับ Next.js แบบเข้าใจง่าย

ถ้าขี้เกียจทำระบบล็อกอินเอง ให้ Auth0 จัดการให้เถอะ!

Auth0 เป็นแพลตฟอร์มจัดการการยืนยันตัวตน (Authentication) ที่ช่วยให้เราทำระบบล็อกอินได้เร็วขึ้น โดยไม่ต้องมานั่งเขียนโค้ดยาวๆ ทำให้เว็บปลอดภัยขึ้นแบบไม่ต้องปวดหัว

ในบทความนี้ เราจะมาใช้ Auth0 กับ Next.js เพื่อทำระบบล็อกอินที่รองรับ OAuth (Google, Facebook ฯลฯ) และ Email/Password ได้ง่ายๆ


🚀 ทำไมต้องใช้ Auth0?

✅ ลดเวลาพัฒนา

  •     ไม่ต้องสร้างระบบยืนยันตัวตนเอง
  •     มี UI สำเร็จรูปให้ใช้เลย

✅ รองรับหลายวิธี

  •     ล็อกอินด้วย Google, Facebook, Apple, GitHub ฯลฯ
  •     ใช้ Magic Link หรือ OTP ก็ได้
  •     ใช้ Username/Password แบบปกติก็ได้

✅ ปลอดภัยกว่า

  •     มีการเข้ารหัสและป้องกันแฮก
  •     รองรับ MFA (Multi-Factor Authentication)


สรุปง่ายๆ Auth0 = เร็ว + ปลอดภัย + ใช้งานง่าย


🎯 มาเริ่มกันเลย!

1️⃣ สร้างโปรเจ็กต์ Next.js

ถ้ายังไม่มีโปรเจ็กต์ Next.js ให้สร้างก่อน

npx create-next-app@latest auth0-demo
cd auth0-demo
npm install

2️⃣ สมัครและตั้งค่า Auth0

  1.     ไปที่ Auth0 Dashboard แล้วสมัครบัญชี
  2.     สร้าง Application ใหม่
    • เลือก Single Page Application
    • ใส่ Callback URL: http://localhost:3000/api/auth/callback/auth0
    • ใส่ Logout URL: http://localhost:3000/
  3. คัดลอก Client ID และ Client Secret


3️⃣ ติดตั้ง NextAuth.js (ใช้ Auth0 เป็น Provider)

ติดตั้งแพ็กเกจที่ต้องใช้

npm install next-auth @auth0/nextjs-auth0

4️⃣ ตั้งค่า NextAuth.js

สร้างไฟล์ pages/api/auth/[...nextauth].js

import NextAuth from "next-auth";
import Auth0Provider from "next-auth/providers/auth0";

export default NextAuth({
  providers: [
    Auth0Provider({
      clientId: process.env.AUTH0_CLIENT_ID,
      clientSecret: process.env.AUTH0_CLIENT_SECRET,
      issuer: process.env.AUTH0_ISSUER,
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
});

5️⃣ ตั้งค่า ENV

สร้างไฟล์ .env.local แล้วใส่ค่าเหล่านี้

AUTH0_CLIENT_ID=your-client-id
AUTH0_CLIENT_SECRET=your-client-secret
AUTH0_ISSUER=https://your-auth0-domain/
NEXTAUTH_SECRET=your-random-secret
NEXTAUTH_URL=http://localhost:3000

💡 Tip: ค่า NEXTAUTH_SECRET ใช้คำสั่งนี้สร้างแบบสุ่มได้

openssl rand -base64 32

6️⃣ สร้างปุ่ม Login / Logout

สร้างไฟล์ pages/index.js

import { useSession, signIn, signOut } from "next-auth/react";

export default function Home() {
  const { data: session } = useSession();

  return (
    <div>
      <h1>Next.js + Auth0</h1>
      {session ? (
        <>
          <p>Welcome, {session.user.name}!</p>
          <button onClick={() => signOut()}>Logout</button>
        </>
      ) : (
        <button onClick={() => signIn("auth0")}>Login with Auth0</button>
      )}
    </div>
  );
}

🔹 อธิบายโค้ด:

  •     ใช้ useSession() เช็กว่าผู้ใช้ล็อกอินหรือยัง
  •     ถ้าล็อกอินแล้ว แสดงชื่อ + ปุ่ม Logout
  •     ถ้ายังไม่ล็อกอิน แสดงปุ่ม Login


🔥 ทดสอบใช้งาน

  1.     รันเซิร์ฟเวอร์ npm run dev
  2.     เข้าไปที่หน้าเว็บ http://localhost:3000
  3.     กดปุ่ม "Login with Auth0"
  4.     ล็อกอินผ่าน Google หรือ Email/Password
  5.     ถ้าสำเร็จจะกลับมาหน้าเว็บและแสดงชื่อ! 🎉


🎨 ทำหน้า Profile

สร้างไฟล์ pages/profile.js

import { useUser } from "@auth0/nextjs-auth0/client";

export default function Profile() {
  const { user, error, isLoading } = useUser();

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    user && (
      <div>
        <h1>{user.name}</h1>
        <p>Email: {user.email}</p>
        <img src={user.picture} alt={user.name} width={100} />
      </div>
    )
  );
}

🔹 อธิบายโค้ด:

  •     ใช้ useUser() ดึงข้อมูลผู้ใช้จาก Auth0
  •     แสดง ชื่อ, อีเมล, รูปโปรไฟล์


❓ คำถามที่พบบ่อย

1️⃣ Auth0 ใช้ฟรีไหม?

ใช่! แต่แผนฟรีจำกัด 7,000 ล็อกอินต่อเดือน ถ้าใช้เยอะกว่านี้ต้องอัปเกรด

2️⃣ รองรับ Social Login อะไรบ้าง?

Google, Facebook, Apple, GitHub, Twitter ฯลฯ

3️⃣ ถ้าอยากใช้ Magic Link ต้องทำไง?

Auth0 รองรับ Passwordless Login (Magic Link, OTP) แค่เปิดใช้งานใน Dashboard


🎉 สรุป

  •     Auth0 ช่วยให้ทำระบบล็อกอินได้เร็วขึ้น
  •     ใช้ NextAuth.js เชื่อม Auth0 กับ Next.js
  •     รองรับ Social Login, Email/Password, Magic Link
  •     ปลอดภัย ไม่ต้องจัดการรหัสผ่านเอง

ลองทำดู แล้วจะติดใจ! 😉

วันอาทิตย์ที่ 23 มีนาคม พ.ศ. 2568

วิธีใช้ Magic Link Authentication ใน Next.js แบบเข้าใจง่าย

ถ้าเบื่อรหัสผ่าน มาลอง Magic Link กันเถอะ!

Magic Link Authentication เป็นวิธีล็อกอินที่ไม่ต้องใช้รหัสผ่าน ผู้ใช้แค่ใส่อีเมล แล้วระบบจะส่งลิงก์ให้คลิกเพื่อเข้าสู่ระบบ ง่าย สะดวก และปลอดภัยกว่าการจำรหัสผ่านเยอะ

ในบทความนี้ เราจะมาดูกันว่า Next.js ใช้ Magic Link ได้ยังไง โดยใช้ NextAuth.js (ตัวช่วยจัดการการยืนยันตัวตนใน Next.js) พร้อมกับ Resend (บริการส่งอีเมลที่ใช้ง่ายและเร็ว)

🎩 ทำไมต้อง Magic Link?

✅ ไม่ต้องจำรหัสผ่าน

  • ชีวิตเรามีรหัสผ่านเยอะเกินไปแล้ว! Magic Link ตัดปัญหานี้ออกไป

✅ ปลอดภัยกว่ารหัสผ่านปกติ

  •     ไม่มีรหัสผ่านให้แฮก (เพราะไม่มีเลย 🤣)
  •     ใช้ one-time link (ลิงก์ใช้ได้ครั้งเดียว) ลดความเสี่ยง

✅ UX ดีขึ้น

  •     ล็อกอินง่าย ไม่ต้องพิมพ์อะไรเยอะ
  •     ลดปัญหา "ลืมรหัสผ่าน"


สรุป: Magic Link = ง่าย + ปลอดภัย + ดีต่อผู้ใช้


🚀 มาเริ่มกันเลย!

1️⃣ สร้างโปรเจ็กต์ Next.js

ถ้ายังไม่มีโปรเจ็กต์ Next.js ให้สร้างใหม่ก่อน

npx create-next-app@latest magic-link-demo
cd magic-link-demo
npm install

2️⃣ ติดตั้ง NextAuth.js และ Resend

npm install next-auth resend

3️⃣ ตั้งค่า NextAuth.js

สร้างไฟล์ pages/api/auth/[...nextauth].js

import NextAuth from "next-auth";
import EmailProvider from "next-auth/providers/email";
import { Resend } from "resend";

const resend = new Resend(process.env.RESEND_API_KEY);

export default NextAuth({
  providers: [
    EmailProvider({
      async sendVerificationRequest({ identifier: email, url }) {
        await resend.emails.send({
          from: "no-reply@yourdomain.com",
          to: email,
          subject: "Magic Link Login",
          html: `<p>Click <a href="${url}">here</a> to log in.</p>`,
        });
      },
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
});

🔹 อธิบายโค้ด:

  •     ใช้ EmailProvider จาก NextAuth.js
  •     เมื่อผู้ใช้ใส่อีเมล ระบบจะส่ง Magic Link ไปที่อีเมลนั้น
  •     ใช้ Resend เป็นตัวช่วยส่งอีเมล
  •     ลิงก์ที่ส่งไปเป็นแบบ one-time link


🎨 สร้างหน้า Login

สร้างไฟล์ pages/login.js

import { signIn } from "next-auth/react";

export default function Login() {
  const handleLogin = async (e) => {
    e.preventDefault();
    const email = e.target.email.value;
    await signIn("email", { email });
  };

  return (
    <div>
      <h1>Magic Link Login</h1>
      <form onSubmit={handleLogin}>
        <input type="email" name="email" placeholder="Enter your email" required />
        <button type="submit">Send Magic Link</button>
      </form>
    </div>
  );
}

🔹 อธิบายโค้ด:

  •     มีฟอร์มให้ผู้ใช้กรอกอีเมล
  •     กดปุ่มแล้วระบบจะเรียก signIn("email", { email }) เพื่อขอ Magic Link
  •     NextAuth.js จะจัดการส่งอีเมลให้เอง


🎯 ทดสอบใช้งาน

  1.     รันเซิร์ฟเวอร์ npm run dev
  2.     เข้าไปที่ /login
  3.     ใส่อีเมล แล้วกดส่ง
  4.     เปิดอีเมล กดลิงก์ แล้วเข้าสู่ระบบ! 🎉



🔥 เพิ่มเติม: ตั้งค่า ENV

สร้างไฟล์ .env.local

NEXTAUTH_SECRET=your-secret-key
RESEND_API_KEY=your-resend-api-key
NEXTAUTH_URL=http://localhost:3000


❓ คำถามที่พบบ่อย

1️⃣ ถ้าไม่มีอีเมล จะล็อกอินยังไง?

Magic Link ต้องใช้อีเมลเท่านั้น ถ้าผู้ใช้ไม่มีอีเมล อาจต้องใช้ OAuth (เช่น Google, Facebook)

2️⃣ Magic Link ปลอดภัยจริงไหม?

ค่อนข้างปลอดภัย แต่ควร:

  •     ใช้ one-time link
  •     ลิงก์ควรหมดอายุเร็ว (เช่น 10 นาที)
  •     ใช้ HTTPS เสมอ

3️⃣ ถ้าอีเมลไปไม่ถึงทำไง?

  •     เช็กโฟลเดอร์ Spam
  •     ใช้อีเมลจากผู้ให้บริการที่น่าเชื่อถือ
  •     ลองเปลี่ยนไปใช้ SMTP แทน Resend


🎉 สรุป

  •     Magic Link คือการล็อกอินแบบไม่ใช้รหัสผ่าน
  •     NextAuth.js + Resend ช่วยให้ใช้งาน Magic Link ได้ง่าย
  •     UX ดีขึ้น ปลอดภัยขึ้น และลดปัญหาลืมรหัสผ่าน

ลองทำกันดู แล้วจะติดใจ! 😉

วันเสาร์ที่ 22 มีนาคม พ.ศ. 2568

การทำ Role-based Authentication ใน Next.js – แยกสิทธิ์ Admin, User, และ Guest

อยากให้เว็บ Next.js ของเรามีระบบแบ่งสิทธิ์การเข้าถึง (RBAC – Role-Based Access Control) ไหม?
เช่น Admin ดูข้อมูลทั้งหมดได้, User ใช้งานปกติ, Guest เข้าได้เฉพาะบางหน้า

🎯 วันนี้เราจะมาทำ Role-based Authentication ใน Next.js

✅ รองรับ JWT Authentication
✅ ใช้ Middleware เช็ก Role ก่อนเข้าหน้าเว็บ
✅ มีตัวอย่าง API แยกสิทธิ์ Admin และ User

🎯 Role-based Authentication คืออะไร?

RBAC (Role-Based Access Control) คือ การกำหนดสิทธิ์ของผู้ใช้ตามบทบาท (Role) เช่น

  • Admin 🛡️ – แก้ไขข้อมูลทุกอย่างได้
  • User 👤 – ใช้งานฟีเจอร์ปกติ
  • Guest 👥 – ดูข้อมูลบางอย่างได้

💡 เราจะใช้ JWT (JSON Web Token) ในการจัดการ Authentication & Role


🚀 1. ติดตั้งโปรเจกต์ Next.js และไลบรารี

เริ่มต้นด้วยการสร้างโปรเจกต์ Next.js และติดตั้งไลบรารีที่จำเป็น

npx create-next-app role-based-auth
cd role-based-auth
npm install jsonwebtoken bcryptjs cookie

  • jsonwebtoken – ใช้สำหรับสร้างและตรวจสอบ JWT
  • bcryptjs – ใช้เข้ารหัสรหัสผ่าน
  • cookie – ใช้จัดการ Token ผ่าน Cookie


🔐 2. สร้างระบบ Authentication (JWT)

📌 สร้าง API Register (สมัครสมาชิก)

📌 ไฟล์: pages/api/auth/register.js

import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";

const users = []; // จำลองฐานข้อมูลใน Memory

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { email, password, role } = req.body;
  if (!email || !password || !role) return res.status(400).json({ error: "Missing fields" });

  const hashedPassword = await bcrypt.hash(password, 10);
  const newUser = { email, password: hashedPassword, role };
  users.push(newUser);

  res.json({ message: "User registered", user: { email, role } });
}

✅ สมัครสมาชิก พร้อมเก็บ role (เช่น admin หรือ user)

📌 สร้าง API Login (เข้าสู่ระบบ)

📌 ไฟล์: pages/api/auth/login.js

import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";
import { serialize } from "cookie";

const users = []; // ใช้ฐานข้อมูลจริงในโปรเจกต์จริง

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { email, password } = req.body;
  const user = users.find((u) => u.email === email);
  if (!user) return res.status(401).json({ error: "User not found" });

  const isMatch = await bcrypt.compare(password, user.password);
  if (!isMatch) return res.status(401).json({ error: "Invalid password" });

  const token = jwt.sign({ email: user.email, role: user.role }, "SECRET_KEY", { expiresIn: "1h" });

  res.setHeader("Set-Cookie", serialize("auth_token", token, { httpOnly: true, path: "/" }));
  res.json({ message: "Login successful", token });
}

✅ ตรวจสอบรหัสผ่าน และสร้าง JWT Token
✅ เก็บ Token ใน Cookie เพื่อใช้ใน Middleware

🚦 3. สร้าง Middleware เช็ก Role

📌 ไฟล์: middleware/auth.js

import jwt from "jsonwebtoken";
import { parse } from "cookie";

export function withAuth(handler, allowedRoles) {
  return async (req, res) => {
    const cookies = parse(req.headers.cookie || "");
    const token = cookies.auth_token;

    if (!token) return res.status(401).json({ error: "Not authenticated" });

    try {
      const decoded = jwt.verify(token, "SECRET_KEY");
      if (!allowedRoles.includes(decoded.role)) {
        return res.status(403).json({ error: "Access Denied" });
      }

      req.user = decoded; // ส่งข้อมูลผู้ใช้ไปยัง API
      return handler(req, res);
    } catch (error) {
      return res.status(401).json({ error: "Invalid Token" });
    }
  };
}

✅ เช็กว่า JWT ถูกต้อง & Role ตรงกับสิทธิ์ที่กำหนด

🔥 4. สร้าง API แยกสิทธิ์

📌 API เฉพาะ Admin

📌 ไฟล์: pages/api/admin.js

import { withAuth } from "../../middleware/auth";

export default withAuth((req, res) => {
  res.json({ message: "Welcome Admin!", user: req.user });
}, ["admin"]);

✅ เฉพาะ Admin เท่านั้นที่เรียก API นี้ได้

📌 API สำหรับ User & Admin

📌 ไฟล์: pages/api/user.js

import { withAuth } from "../../middleware/auth";

export default withAuth((req, res) => {
  res.json({ message: `Welcome ${req.user.role}!`, user: req.user });
}, ["user", "admin"]);

✅ ทั้ง User & Admin ใช้งานได้


🎨 5. สร้าง UI หน้าเว็บ

📌 ไฟล์: pages/index.js

import { useState } from "react";

export default function Home() {
  const [message, setMessage] = useState("");

  const checkAdmin = async () => {
    const res = await fetch("/api/admin");
    const data = await res.json();
    setMessage(data.message || data.error);
  };

  const checkUser = async () => {
    const res = await fetch("/api/user");
    const data = await res.json();
    setMessage(data.message || data.error);
  };

  return (
    <div>
      <h1>Role-based Authentication</h1>
      <button onClick={checkAdmin}>Check Admin</button>
      <button onClick={checkUser}>Check User</button>
      <p>{message}</p>
    </div>
  );
}

✅ ทดสอบ กดปุ่ม Check Admin หรือ Check User เพื่อดูสิทธิ์



🚀 6. ทดสอบระบบ

  1. รันเซิร์ฟเวอร์ npm run dev
  2. สมัครสมาชิก → /api/auth/register
  3. ล็อกอิน → /api/auth/login
  4. ลองเรียก /api/admin และ /api/user ดูว่า Role ตรงไหม


🎯 สรุป

✅ ใช้ JWT และ Middleware จัดการ Role
✅ แยกสิทธิ์ Admin, User, Guest
✅ ใช้ API แยก Role เพื่อควบคุมสิทธิ์การเข้าถึง

💡 พร้อมใช้กับเว็บจริง! แค่เพิ่ม Database และ UI สวยๆ เท่านั้น! 🚀

วันศุกร์ที่ 21 มีนาคม พ.ศ. 2568

การใช้ Firebase Authentication กับ Next.js – ล็อกอินง่ายๆ ด้วย Google, Email, GitHub

อยากให้เว็บ Next.js ของเรามีระบบล็อกอินด้วย Google, Email หรือ GitHub ไหม? 🔑
Firebase Authentication เป็นตัวช่วยที่ ฟรี, ใช้งานง่าย, และ ปลอดภัย

วันนี้เราจะมาทำระบบ Sign-up & Login ด้วย Firebase Auth ใน Next.js แบบครบๆ พร้อมโค้ดตัวอย่าง! 🚀

🎯 เราจะทำอะไรบ้าง?

✅ สมัครสมาชิก & ล็อกอินด้วย Email/Password
✅ ล็อกอินด้วย Google, GitHub
✅ จัดการ Session ด้วย Firebase
✅ ใช้ Firebase SDK ใน Next.js

💡 ไม่ต้องทำระบบ Auth เอง! Firebase จัดการให้หมด แค่เขียนโค้ดเชื่อมต่อก็ใช้ได้เลย 🔥

🔥 ตั้งค่า Firebase Authentication

🛠️ 1. สมัคร Firebase และสร้างโปรเจกต์

  1. เข้าไปที่ Firebase Console
  2. กด "Add Project" → ตั้งชื่อโปรเจกต์ → กด "Continue"
  3. กด "Enable Google Analytics" หรือ ปิดก็ได้ → กด "Create Project"

🔑 2. เปิดใช้งาน Authentication

  1. ไปที่ "Build" → "Authentication"
  2. กด "Get Started"
  3. ไปที่ "Sign-in method"
  4. เปิดการใช้งาน Email/Password, Google, GitHub

🔗 3. ตั้งค่า Web API Key

  1. ไปที่ "Project settings" (ไอคอนรูปเฟือง)
  2. ไปที่ "General" → "Your apps" → กด "Web app"
  3. ตั้งชื่อแอป → กด "Register app"
  4. คัดลอก Firebase Config ไว้


⚙️ ติดตั้ง Firebase SDK ใน Next.js

1. สร้างโปรเจกต์ Next.js

    npx create-next-app my-firebase-auth
    cd my-firebase-auth
    npm install firebase

2. สร้างไฟล์ firebase.js เพื่อเชื่อมต่อ Firebase

📌 โค้ด: lib/firebase.js

import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
  appId: "YOUR_APP_ID",
};

const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);

💡 อย่าลืมเปลี่ยน YOUR_API_KEY เป็นค่าจริงจาก Firebase!



✉️ สมัครสมาชิก & ล็อกอินด้วย Email/Password

📌 โค้ด: pages/auth.js

import { useState } from "react";
import { auth } from "../lib/firebase";
import { createUserWithEmailAndPassword, signInWithEmailAndPassword } from "firebase/auth";

export default function AuthPage() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [message, setMessage] = useState("");

  const signUp = async () => {
    try {
      await createUserWithEmailAndPassword(auth, email, password);
      setMessage("Signup successful!");
    } catch (error) {
      setMessage(error.message);
    }
  };

  const login = async () => {
    try {
      await signInWithEmailAndPassword(auth, email, password);
      setMessage("Login successful!");
    } catch (error) {
      setMessage(error.message);
    }
  };

  return (
    <div>
      <h1>Firebase Auth</h1>
      <input type="email" placeholder="Email" onChange={(e) => setEmail(e.target.value)} />
      <input type="password" placeholder="Password" onChange={(e) => setPassword(e.target.value)} />
      <button onClick={signUp}>Sign Up</button>
      <button onClick={login}>Login</button>
      <p>{message}</p>
    </div>
  );
}

✅ กรอก Email & Password แล้วสมัครหรือล็อกอินได้เลย!


🔵 ล็อกอินด้วย Google

📌 โค้ด: pages/auth.js (เพิ่มปุ่ม Google Sign-in)

import { GoogleAuthProvider, signInWithPopup } from "firebase/auth";

const loginWithGoogle = async () => {
  try {
    const provider = new GoogleAuthProvider();
    await signInWithPopup(auth, provider);
    setMessage("Login with Google successful!");
  } catch (error) {
    setMessage(error.message);
  }
};

// เพิ่มปุ่ม Login with Google
<button onClick={loginWithGoogle}>Login with Google</button>;

✅ กดปุ่ม → เลือกบัญชี Google → ล็อกอินสำเร็จ!


🛡️ จัดการ Session ด้วย Firebase

Firebase มี onAuthStateChanged ให้เราตรวจสอบว่าผู้ใช้ล็อกอินอยู่หรือไม่

📌 โค้ด: pages/index.js


import { useEffect, useState } from "react";
import { auth } from "../lib/firebase";
import { onAuthStateChanged, signOut } from "firebase/auth";

export default function Home() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user);
    });
    return () => unsubscribe();
  }, []);

  return (
    <div>
      <h1>Welcome {user ? user.email : "Guest"}</h1>
      {user ? (
        <button onClick={() => signOut(auth)}>Logout</button>
      ) : (
        <a href="/auth">Go to Login</a>
      )}
    </div>
  );
}

✅ ถ้าล็อกอินอยู่จะแสดง Email ของผู้ใช้
✅ ถ้ายังไม่ล็อกอินจะแสดงปุ่ม Go to Login


🚀 ทดสอบระบบ

  1. รันเซิร์ฟเวอร์ npm run dev
  2. เปิด http://localhost:3000/auth
  3. ลองสมัครสมาชิก & ล็อกอิน
  4. เช็คหน้าแรก ว่ามี Session หรือไม่?

🎉 เรียบร้อย! Firebase Auth ใช้งานได้แล้ว!


🎯 สรุป

✅ ใช้ Firebase Authentication ใน Next.js ได้ง่ายๆ
✅ รองรับ Email/Password, Google, GitHub
✅ Session จัดการอัตโนมัติ ด้วย Firebase SDK
✅ ใช้ onAuthStateChanged เช็กสถานะผู้ใช้

🚀 พร้อมใช้ในโปรเจกต์จริง! แค่เพิ่ม UI สวยๆ และ Database ก็เปิดให้คนใช้ได้เลย!

วันพฤหัสบดีที่ 20 มีนาคม พ.ศ. 2568

การจัดการ Session และ Cookie ใน Next.js แบบเข้าใจง่าย!

Session และ Cookie เป็นสิ่งที่ขาดไม่ได้ในระบบเว็บแอป Next.js ไม่ว่าจะเป็นการ จัดการผู้ใช้ (Authentication), จดจำค่าต่างๆ หรือ รักษาความปลอดภัยของแอป

📌 บทความนี้จะอธิบายว่า Session & Cookie คืออะไร และ ใช้งานใน Next.js ยังไง พร้อมตัวอย่างโค้ดแบบจับมือทำ! 🚀

🎯 Session และ Cookie คืออะไร?

🍪 Cookie

Cookie เป็นข้อมูลเล็กๆ ที่ browser เก็บไว้ในเครื่องของผู้ใช้ โดยส่งไปพร้อมกับทุกๆ request เพื่อให้เซิร์ฟเวอร์จำผู้ใช้ได้

🔹 ใช้สำหรับ จดจำสถานะของผู้ใช้ (เช่นล็อกอินอยู่หรือเปล่า?)
🔹 สามารถตั้งค่า หมดอายุ (Expire) ได้
🔹 มีการจำกัดขนาดข้อมูล (โดยทั่วไปไม่เกิน 4KB)

🔐 Session

Session คือการเก็บข้อมูลของผู้ใช้ ฝั่งเซิร์ฟเวอร์ และอ้างอิงด้วย Session ID ที่เก็บไว้ใน Cookie

🔹 ปลอดภัยกว่าการเก็บข้อมูลใน Cookie เพราะข้อมูลไม่ได้ถูกเก็บไว้ที่ฝั่งผู้ใช้
🔹 ต้องใช้ Session Storage เช่น Redis, Database หรือ Memory
🔹 มีอายุการใช้งานตามที่กำหนด (เช่น 30 นาที)

💡 โดยทั่วไป Session & Cookie ใช้งานร่วมกัน คือ เก็บ Session ID ไว้ใน Cookie เพื่อให้เซิร์ฟเวอร์ดึงข้อมูลผู้ใช้มาใช้ได้


🚀 วิธีใช้งาน Cookie ใน Next.js

📌 ติดตั้งไลบรารีจัดการ Cookie

npm install cookie


🔹 สร้าง API ที่ใช้ Cookie ใน Next.js

📌 โค้ด: pages/api/auth/set-cookie.js

import { serialize } from "cookie";

export default function handler(req, res) {
  const token = "my_secure_token"; // จำลอง token

  res.setHeader("Set-Cookie", serialize("auth_token", token, {
    httpOnly: true, // ป้องกันการเข้าถึงจาก JavaScript
    secure: process.env.NODE_ENV === "production", // ใช้ https ในโหมด production
    maxAge: 60 * 60 * 24, // 1 วัน
    sameSite: "strict",
    path: "/",
  }));

  res.json({ message: "Cookie set!" });
}

✅ API นี้จะสร้าง auth_token แล้วฝังไว้ใน Cookie
✅ ตั้งค่า httpOnly เพื่อให้ปลอดภัยจาก XSS
✅ หมดอายุใน 1 วัน

🔹 อ่านค่า Cookie

📌 โค้ด: pages/api/auth/get-cookie.js

import { parse } from "cookie";

export default function handler(req, res) {
  const cookies = parse(req.headers.cookie || "");
  res.json({ token: cookies.auth_token || "No token found" });
}

✅ API นี้จะอ่านค่า auth_token จาก Cookie

🔹 ลบ Cookie (Logout)

📌 โค้ด: pages/api/auth/logout.js

import { serialize } from "cookie";

export default function handler(req, res) {
  res.setHeader("Set-Cookie", serialize("auth_token", "", {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    expires: new Date(0), // ลบ Cookie
    path: "/",
  }));

  res.json({ message: "Logged out!" });
}

✅ API นี้จะลบ Cookie โดยตั้งค่า expire เป็น 0


🚀 วิธีใช้งาน Session ใน Next.js

📌 ติดตั้งไลบรารี Session

npm install next-session

next-session เป็นไลบรารีที่ช่วยจัดการ Session ใน Next.js API Routes ได้ง่าย

🔹 ตั้งค่า Session Middleware

📌 โค้ด: lib/session.js

import { withIronSessionApiRoute } from "iron-session/next";

export function withSession(handler) {
  return withIronSessionApiRoute(handler, {
    cookieName: "session_cookie",
    password: "complex_password_123", // ควรใช้ env variable
    cookieOptions: {
      secure: process.env.NODE_ENV === "production",
    },
  });
}

✅ ใช้ iron-session เก็บ Session อย่างปลอดภัย
✅ ตั้งค่า session_cookie เป็นที่เก็บ Session

🔹 สร้าง API ที่ใช้ Session

📌 โค้ด: pages/api/auth/login.js

import { withSession } from "../../lib/session";

export default withSession(async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  req.session.user = { id: 1, username: "admin" };
  await req.session.save();

  res.json({ message: "Login successful", user: req.session.user });
});

✅ เมื่อล็อกอินสำเร็จ จะเก็บข้อมูลผู้ใช้ใน Session

🔹 ดึงข้อมูลจาก Session

📌 โค้ด: pages/api/auth/me.js

import { withSession } from "../../lib/session";

export default withSession(async function handler(req, res) {
  if (!req.session.user) {
    return res.status(401).json({ error: "Not authenticated" });
  }

  res.json({ user: req.session.user });
});

✅ API นี้จะเช็กว่า มี Session ไหม? ถ้ามีแสดงข้อมูลผู้ใช้

🔹 ลบ Session (Logout)

📌 โค้ด: pages/api/auth/logout.js

import { withSession } from "../../lib/session";

export default withSession(async function handler(req, res) {
  req.session.destroy();
  res.json({ message: "Logged out!" });
});

✅ API นี้จะ ลบ Session แล้วทำให้ผู้ใช้ต้องล็อกอินใหม่

🎨 สร้างหน้า UI สำหรับ Login

📌 โค้ด: pages/index.js

import { useState } from "react";

export default function Home() {
  const [message, setMessage] = useState("");

  const login = async () => {
    const res = await fetch("/api/auth/login", { method: "POST" });
    const data = await res.json();
    setMessage(data.message);
  };

  const checkSession = async () => {
    const res = await fetch("/api/auth/me");
    const data = await res.json();
    setMessage(data.user ? `Logged in as ${data.user.username}` : "Not authenticated");
  };

  return (
    <div>
      <h1>Session & Cookie in Next.js</h1>
      <button onClick={login}>Login</button>
      <button onClick={checkSession}>Check Session</button>
      <p>{message}</p>
    </div>
  );
}

✅ UI นี้จะ Login แล้วเช็กว่า Session ยังอยู่ไหม?


🚀 ทดสอบระบบ

  1. รันเซิร์ฟเวอร์ npm run dev
  2. เปิด http://localhost:3000
  3. กด Login แล้วดูว่ามี Session หรือไม่


🎯 สรุป

✅ Cookie – ใช้เก็บข้อมูลเล็กๆ ฝั่ง client
✅ Session – ใช้เก็บข้อมูลฝั่งเซิร์ฟเวอร์
✅ Next.js API Routes รองรับทั้ง Cookie & Session
✅ ใช้ iron-session ทำให้การจัดการ Session ง่ายขึ้น

วันพุธที่ 19 มีนาคม พ.ศ. 2568

การสร้างระบบสมาชิก (Sign-up & Login) ใน Next.js แบบเข้าใจง่าย!

อยากทำระบบ สมัครสมาชิก (Sign-up) + ล็อกอิน (Login) ใน Next.js ใช่ไหม? 🤔 ไม่ต้องห่วง บทความนี้จะพาไปทำแบบ step-by-step ตั้งแต่สร้างบัญชี, เข้ารหัสรหัสผ่าน, จัดการ JWT Token, ยันป้องกัน API รับรองว่าอ่านจบแล้วทำเป็นแน่นอน!

🎯 แผนที่ที่เราจะทำ

✅ สมัครสมาชิก (Sign-up)
✅ เข้าสู่ระบบ (Login) พร้อมสร้าง JWT Token
✅ ป้องกัน API ด้วย Token
✅ แสดงข้อมูลผู้ใช้ที่ล็อกอินอยู่

💡 ใช้แค่ Next.js API Routes, bcrypt, และ JSON Web Token (JWT) ไม่ต้องมีเซิร์ฟเวอร์เพิ่ม!


🛠️ ติดตั้ง Next.js และไลบรารีที่จำเป็น

ก่อนอื่นต้องมีโปรเจกต์ Next.js ถ้ายังไม่มีให้สร้างเลย

npx create-next-app@latest my-auth-app
cd my-auth-app
npm install bcryptjs jsonwebtoken

👉 bcryptjs – ใช้เข้ารหัสรหัสผ่าน
👉 jsonwebtoken – ใช้สร้างและตรวจสอบ JWT Token


🔐 สร้าง API สำหรับ สมัครสมาชิก (Sign-up)

📌 โค้ด: pages/api/auth/signup.js

import bcrypt from "bcryptjs";

let users = []; // จำลองเป็น Database (จริงๆ ควรใช้ MongoDB หรือ PostgreSQL)

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { username, password } = req.body;

  if (users.find((u) => u.username === username)) {
    return res.status(400).json({ error: "Username already exists" });
  }

  const hashedPassword = await bcrypt.hash(password, 10);
  const newUser = { id: Date.now(), username, password: hashedPassword };

  users.push(newUser);
  res.json({ message: "User registered", user: { id: newUser.id, username: newUser.username } });
}

🔹 เช็กว่าชื่อผู้ใช้ซ้ำหรือไม่
🔹 เข้ารหัสรหัสผ่านก่อนบันทึก


🔑 สร้าง API สำหรับ เข้าสู่ระบบ (Login)

📌 โค้ด: pages/api/auth/login.js

import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";

let users = []; // จำลอง Database (ใช้ร่วมกับ signup.js)

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { username, password } = req.body;
  const user = users.find((u) => u.username === username);

  if (!user || !(await bcrypt.compare(password, user.password))) {
    return res.status(401).json({ error: "Invalid credentials" });
  }

  const token = jwt.sign({ userId: user.id, username: user.username }, "SECRET_KEY", { expiresIn: "1h" });

  res.json({ message: "Login successful", token });
}

🔐 ถ้าล็อกอินสำเร็จ จะสร้าง JWT Token และส่งกลับไปให้ client


🛡️ สร้าง API ที่ต้องใช้ Token ในการเข้าถึง

📌 โค้ด: pages/api/auth/me.js

import jwt from "jsonwebtoken";

export default function handler(req, res) {
  const { authorization } = req.headers;
 
  if (!authorization) return res.status(401).json({ error: "No token provided" });

  try {
    const token = authorization.split(" ")[1];
    const decoded = jwt.verify(token, "SECRET_KEY");
    res.json({ message: "Authenticated", user: decoded });
  } catch (err) {
    res.status(401).json({ error: "Invalid token" });
  }
}

🔒 API นี้ต้องใช้ JWT Token ใน Authorization header เพื่อเข้าถึง


🎨 สร้างหน้า UI สำหรับ สมัครสมาชิก + ล็อกอิน

📌 โค้ด: pages/index.js

import { useState } from "react";

export default function Home() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [token, setToken] = useState(null);
  const [message, setMessage] = useState("");

  const signup = async () => {
    const res = await fetch("/api/auth/signup", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username, password }),
    });

    const data = await res.json();
    setMessage(data.message);
  };

  const login = async () => {
    const res = await fetch("/api/auth/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username, password }),
    });

    const data = await res.json();
    if (data.token) {
      setToken(data.token);
      setMessage("Login successful!");
    } else {
      setMessage("Login failed");
    }
  };

  const getUserData = async () => {
    const res = await fetch("/api/auth/me", {
      headers: { Authorization: `Bearer ${token}` },
    });

    const data = await res.json();
    setMessage(data.message || "Access denied");
  };

  return (
    <div>
      <h1>Sign-up & Login System</h1>
      <input type="text" placeholder="Username" onChange={(e) => setUsername(e.target.value)} />
      <input type="password" placeholder="Password" onChange={(e) => setPassword(e.target.value)} />
      <button onClick={signup}>Sign Up</button>
      <button onClick={login}>Login</button>
      <button onClick={getUserData} disabled={!token}>Get User Data</button>
      <p>{message}</p>
    </div>
  );
}

💡 อธิบายโค้ด:

✅ กรอกชื่อผู้ใช้ + รหัสผ่าน แล้วกด Sign Up เพื่อสมัคร
✅ กด Login ถ้าสำเร็จจะได้ JWT Token
✅ กด Get User Data เพื่อเรียก API ที่ป้องกันไว้


🚀 ทดสอบระบบ

  1. รันเซิร์ฟเวอร์ npm run dev
  2. เปิด http://localhost:3000
  3. ลอง Sign-up > Login > กด Get User Data

ถ้า JWT Token ถูกต้อง API จะให้เข้าถึงข้อมูลได้! 🎉


🎯 สรุป

✅ Sign-up พร้อมเข้ารหัสรหัสผ่าน
✅ Login แล้วสร้าง JWT Token
✅ ป้องกัน API ด้วย JWT
✅ ใช้ Next.js API Routes ทำระบบ Authentication แบบ stateless

🚀 พร้อมใช้ในโปรเจกต์จริง เพิ่ม Database และ refresh token ได้เลย!

วันอังคารที่ 18 มีนาคม พ.ศ. 2568

การใช้ JWT Authentication ใน Next.js แบบง่ายแต่โหด

ถ้าคุณกำลังทำเว็บแอปด้วย Next.js และอยากได้ระบบล็อกอินที่ปลอดภัยแต่ไม่ยุ่งยาก JWT Authentication คือคำตอบ! 😎

JWT (JSON Web Token) เป็นมาตรฐานสำหรับการส่งข้อมูลแบบ secure ระหว่าง client และ server โดยไม่ต้องใช้ session บนเซิร์ฟเวอร์ให้ยุ่งยาก ซึ่งเหมาะกับแอปที่ต้องการ stateless authentication เช่น Next.js API Routes หรือ Serverless Functions

บทความนี้จะพาไปดูวิธีใช้งาน JWT Authentication ใน Next.js ตั้งแต่เริ่มต้น ยันการป้องกัน API ให้ปลอดภัย 💪

🎯 JWT คืออะไร?

JWT (JSON Web Token) เป็นโทเค็นเข้ารหัสที่ใช้แทน session ในการตรวจสอบตัวตน (Authentication) ของผู้ใช้ โดยมันจะถูกฝังข้อมูล เช่น user ID, role, email ไว้ข้างใน และสามารถใช้ยืนยันตัวตนในทุกๆ Request ได้

JWT มี 3 ส่วนหลักๆ คือ

  • Header – บอกว่าใช้การเข้ารหัสแบบไหน
  • Payload – ข้อมูลของผู้ใช้ เช่น ID, ชื่อ, อีเมล
  • Signature – ใช้สำหรับยืนยันว่าโทเค็นถูกต้อง


ตัวอย่าง JWT แบบดิบๆ 👇

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImlhdCI6MTYxNjIzOTAyMn0.PF-0Ff_q2Gsk2tKAlDhEwMzMfJvc_ZjZbnF0qU4aMSk

ลองเอาไป Decode ได้ที่ jwt.io 😃



🛠️ ติดตั้ง Next.js และ JWT

ก่อนอื่นต้องมีโปรเจกต์ Next.js ก่อน ถ้ายังไม่มี ก็กดสร้างเลย

npx create-next-app@latest jwt-auth-app
cd jwt-auth-app
npm install jsonwebtoken bcryptjs

👉 jsonwebtoken – ใช้สำหรับสร้างและตรวจสอบ JWT
👉 bcryptjs – ใช้เข้ารหัสรหัสผ่าน


🔐 สร้าง API สำหรับ JWT Authentication

1️⃣ สร้าง API สำหรับ ล็อกอิน และสร้าง JWT

ไปที่ pages/api/auth/login.js แล้วใส่โค้ดนี้

import jwt from "jsonwebtoken";
import bcrypt from "bcryptjs";

// ข้อมูลผู้ใช้ตัวอย่าง (จริงๆ ควรใช้ DB)
const users = [{ id: 1, username: "admin", password: "$2a$10$KIX/b0WwQJHsc/mxL6RoGuLbqVZXuWEC1Q2tB3MTzK8K4NrdH5r3W" }]; // รหัสผ่าน: 123456

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { username, password } = req.body;
  const user = users.find((u) => u.username === username);

  if (!user || !(await bcrypt.compare(password, user.password))) {
    return res.status(401).json({ error: "Invalid credentials" });
  }

  const token = jwt.sign({ userId: user.id, username: user.username }, "SECRET_KEY", { expiresIn: "1h" });

  res.json({ token });
}

🔹 เราใช้ bcryptjs เพื่อตรวจสอบรหัสผ่าน
🔹 ถ้าล็อกอินสำเร็จ จะสร้าง JWT Token แล้วส่งกลับไปให้ client

2️⃣ สร้าง API สำหรับ ป้องกัน API ด้วย JWT

สร้างไฟล์ pages/api/protected.js

import jwt from "jsonwebtoken";

export default function handler(req, res) {
  const { authorization } = req.headers;
 
  if (!authorization) return res.status(401).json({ error: "No token provided" });

  try {
    const token = authorization.split(" ")[1];
    const decoded = jwt.verify(token, "SECRET_KEY");
    res.json({ message: "Protected data", user: decoded });
  } catch (err) {
    res.status(401).json({ error: "Invalid token" });
  }
}

🔒 API นี้จะตรวจสอบว่า

✅ มี JWT Token ใน Authorization header ไหม
✅ ถอดรหัสแล้วถูกต้องหรือไม่

3️⃣ สร้าง API สำหรับ สมัครสมาชิก

สร้างไฟล์ pages/api/auth/register.js

import bcrypt from "bcryptjs";

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { username, password } = req.body;
  const hashedPassword = await bcrypt.hash(password, 10);

  // จำลองการบันทึกลง DB
  const newUser = { id: Date.now(), username, password: hashedPassword };

  res.json({ message: "User registered", user: newUser });
}

🔹 ใช้ bcryptjs เพื่อเข้ารหัสรหัสผ่านก่อนบันทึก
🔹 จำลองว่าเราเก็บข้อมูลผู้ใช้ใน DB


🎨 สร้าง UI สำหรับล็อกอิน

เปิดไฟล์ pages/index.js แล้วใส่โค้ดนี้

import { useState } from "react";

export default function Home() {
  const [token, setToken] = useState(null);
  const [message, setMessage] = useState("");

  const login = async () => {
    const res = await fetch("/api/auth/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username: "admin", password: "123456" }),
    });

    const data = await res.json();
    if (data.token) {
      setToken(data.token);
      setMessage("Login successful!");
    } else {
      setMessage("Login failed");
    }
  };

  const accessProtected = async () => {
    const res = await fetch("/api/protected", {
      headers: { Authorization: `Bearer ${token}` },
    });

    const data = await res.json();
    setMessage(data.message || "Access denied");
  };

  return (
    <div>
      <h1>JWT Authentication in Next.js</h1>
      <button onClick={login}>Login</button>
      <button onClick={accessProtected} disabled={!token}>Access Protected API</button>
      <p>{message}</p>
    </div>
  );
}

💡 อธิบายโค้ด:

  • ปุ่ม Login จะส่ง Username และ Password ไปที่ API
  • ถ้าล็อกอินสำเร็จจะได้ JWT Token มาเก็บไว้
  • ปุ่ม Access Protected API จะส่ง JWT Token ไปที่ API ที่ต้องการป้องกัน


🚀 ทดสอบระบบ JWT Authentication

  1.     รันเซิร์ฟเวอร์ npm run dev
  2.     เปิด http://localhost:3000
  3.     กดปุ่ม "Login"
  4.     กดปุ่ม "Access Protected API" เพื่อดูว่ามีสิทธิ์เข้าถึงหรือไม่


🎯 สรุป

✅ JWT Authentication ทำให้ระบบล็อกอินเป็นแบบ stateless และปลอดภัย
✅ ไม่ต้องใช้ session storage บนเซิร์ฟเวอร์
✅ ใช้งานง่ายกับ Next.js API Routes

แค่นี้ก็ได้ระบบล็อกอินเทพๆ ไปใช้ในแอป Next.js แล้ว! 🔥

การใช้ Image Optimization ใน Next.js: โหลดไว SEO ดี ประหยัดแบนด์วิธ!

เคยเจอปัญหาเว็บโหลดช้าเพราะรูปภาพขนาดใหญ่หรือเปล่า? 📷 ถ้าใช่ Next.js มีฟีเจอร์ Image Optimization ที่ช่วยให้รูปภาพโหลดเร็วขึ้น อัตโนมัติ ไม...