Skip to content
← All Skills
🔥

Firebase

InfrastructureOfficial Site ›

Firebase Authentication — email/phone login, custom claims สำหรับ RBAC, token management

What I Can Do

  • ใช้ Firebase Authentication เป็น identity provider สำหรับ microservices
  • Implement custom claims สำหรับ RBAC — role/permissions ฝังใน JWT token
  • Verify Firebase ID tokens ที่ backend (Go/Node.js) โดยไม่ต้อง call Firebase ทุก request
  • จัดการ user lifecycle — create, disable, delete, password reset
  • ใช้ Firebase Admin SDK สำหรับ server-side user management

Commands I Use Daily

bash
# install Firebase Admin SDK (Go)
go get firebase.google.com/go/v4

# install Firebase Admin SDK (Node.js)
npm install firebase-admin

# install Firebase Client SDK (frontend)
npm install firebase

# deploy Firebase rules / functions
firebase deploy

# list Firebase projects
firebase projects:list

# emulator สำหรับ local development
firebase emulators:start --only auth

Firebase Authentication Overview

Firebase Auth จัดการ user authentication ให้ — sign up, sign in, password reset, social login (Google, Facebook, Apple) ออก JWT token (ID token) ที่ backend verify ได้โดยไม่ต้อง call Firebase ทุก request

Auth Flow กับ Microservices

text
Client → Firebase Auth (login) → ID Token (JWT)
Client → API Gateway → Backend (verify token) → Response
  1. Client login ผ่าน Firebase SDK (email/password, Google, etc.)
  2. Firebase ออก ID token (JWT) ให้ client
  3. Client ส่ง token ใน Authorization: Bearer <token> header ทุก request
  4. Backend verify token ด้วย Firebase Admin SDK — ไม่ต้อง call Firebase server

Verify ID Token (Go)

go
client, err := app.Auth(ctx)
token, err := client.VerifyIDToken(ctx, idToken)

// token.UID = Firebase user ID
// token.Claims = custom claims (roles, permissions)
userID := token.UID
role := token.Claims["role"].(string)

Verify ใช้ public keys ที่ cache ไว้ — ไม่ต้อง network call ทุก request, เร็วมาก

Verify ID Token (Node.js)

javascript
const decodedToken = await admin.auth().verifyIdToken(idToken);
const uid = decodedToken.uid;
const role = decodedToken.role;

Custom Claims สำหรับ RBAC

Custom claims = data ที่ฝังใน JWT token — backend อ่านได้ทันทีหลัง verify ไม่ต้อง query DB

go
// Set custom claims (Admin SDK)
claims := map[string]interface{}{
    "role":  "trader",
    "orgID": "org_123",
    "permissions": []string{"orders:create", "orders:read", "orders:cancel"},
}
err := client.SetCustomUserClaims(ctx, uid, claims)

ข้อจำกัด: custom claims มี max size 1000 bytes — เก็บเฉพาะ role/orgID แล้ว resolve permissions ที่ backend ถ้า permissions เยอะ

Custom Claims + RBAC Flow

text
1. Admin เปลี่ยน role ของ user → API call ไป backend
2. Backend update role ใน DB + set custom claims ผ่าน Admin SDK
3. Force token refresh → client ได้ token ใหม่ที่มี claims ใหม่
4. ทุก request หลังจากนี้ backend อ่าน role จาก token.Claims ได้เลย

ข้อดี: ไม่ต้อง query DB ทุก request เพื่อตรวจ role — อ่านจาก token เลย ข้อเสีย: เปลี่ยน role แล้วต้อง force refresh token ถึงจะมีผล

Force Token Refresh

หลังเปลี่ยน custom claims ต้องบอก client refresh token:

javascript
// Client-side: force refresh token
await firebase.auth().currentUser.getIdToken(true);

หรือ backend revoke tokens เก่าทั้งหมด:

go
// Revoke refresh tokens (Admin SDK)
client.RevokeRefreshTokens(ctx, uid)

User Management (Admin SDK)

go
// สร้าง user
params := (&auth.UserToCreate{}).Email("user@example.com").Password("secret")
user, err := client.CreateUser(ctx, params)

// ดึง user by email
user, err := client.GetUserByEmail(ctx, "user@example.com")

// disable user
params := (&auth.UserToUpdate{}).Disabled(true)
client.UpdateUser(ctx, uid, params)

// delete user
client.DeleteUser(ctx, uid)

// list users
iter := client.Users(ctx, "")

Email/Password Authentication

Login ด้วย email + password — ใช้สำหรับ backoffice, admin panel, trading platform:

javascript
// Client: sign up
const userCredential = await createUserWithEmailAndPassword(auth, email, password);

// Client: sign in
const userCredential = await signInWithEmailAndPassword(auth, email, password);

// Client: password reset
await sendPasswordResetEmail(auth, email);
  • เปิด email verification บังคับ verify ก่อนใช้งาน
  • ตั้ง password policy: minimum length, complexity
  • ใช้คู่กับ custom claims สำหรับ RBAC — login เสร็จ token มี role มาเลย

Phone Authentication (OTP)

Login ด้วยเบอร์โทร + SMS OTP — ใช้สำหรับ mobile apps, user onboarding, 2FA:

javascript
// Client: ส่ง OTP
const confirmationResult = await signInWithPhoneNumber(auth, "+66812345678", appVerifier);

// Client: verify OTP ที่ user กรอก
const userCredential = await confirmationResult.confirm(otpCode);

Backend verify phone number:

go
// ตรวจว่า user login ด้วย phone จริง
token, _ := client.VerifyIDToken(ctx, idToken)
phoneNumber := token.Claims["phone_number"].(string)
// token.Firebase.SignInProvider == "phone"

สิ่งที่ต้องรู้:

  • Firebase ส่ง SMS ให้อัตโนมัติ — ไม่ต้อง integrate SMS provider เอง
  • ค่า SMS: ฟรี 10K verifications/เดือน หลังจากนั้นคิดตาม usage
  • reCAPTCHA verifier ป้องกัน abuse (web), SafetyNet/App Check (mobile)
  • Phone auth สร้าง Firebase user เหมือน email — UID เดียวกัน ใช้ custom claims ได้

Account Linking (Email + Phone)

User คนเดียวสามารถ link ทั้ง email และ phone number:

javascript
// User login ด้วย email อยู่แล้ว → link phone number เพิ่ม
const credential = PhoneAuthProvider.credential(verificationId, otpCode);
await linkWithCredential(auth.currentUser, credential);
  • ใช้ phone เป็น 2FA สำหรับ sensitive operations (withdrawal, transfer)
  • User login ได้ทั้ง email หรือ phone — Firebase จัดการ account เดียวกัน
  • Backend ดู linked providers: user.ProviderUserInfo ตรวจว่ามี phone verified หรือไม่

Auth Providers ที่รองรับ

  • Email/Password — basic auth + email verification
  • Phone (SMS OTP) — mobile-first authentication
  • Google — OAuth 2.0, popular ที่สุด
  • Apple — required สำหรับ iOS apps
  • Facebook, GitHub, Microsoft — OAuth providers

ใช้ provider เดียวหรือหลายตัวต่อ user ได้ — Firebase จัดการ account linking ให้

Firebase Auth Emulator

ใช้ emulator สำหรับ local development — ไม่ต้อง connect Firebase จริง:

bash
firebase emulators:start --only auth
# Auth emulator runs at http://localhost:9099
  • สร้าง test users ได้อิสระ
  • ไม่เสียค่า API calls
  • ทดสอบ custom claims, token verify ได้ครบ
  • CI/CD ใช้ emulator สำหรับ integration tests

Security Rules

  • ปิด anonymous auth ถ้าไม่ใช้ — ลด attack surface
  • ตั้ง password requirements: minimum length, complexity
  • เปิด email verification สำหรับ email/password auth
  • Rate limit auth attempts ที่ Firebase console
  • Monitor suspicious activity ใน Firebase Authentication dashboard

Firebase + Kong/Nginx

ใช้ Firebase Auth ร่วมกับ API Gateway:

  • Kong: ใช้ JWT plugin verify Firebase token ที่ gateway layer — backend ไม่ต้อง verify เอง
  • Nginx: forward Authorization header ไป backend, verify ที่ application layer
  • ทั้งสองแบบ: custom claims ถูกส่งต่อใน token — backend อ่านได้เลย

Token Lifecycle

  • ID Token — short-lived (1 ชั่วโมง), auto refresh ผ่าน SDK
  • Refresh Token — long-lived, ใช้ขอ ID token ใหม่
  • Custom Token — backend สร้างเอง สำหรับ custom auth flows
  • Client SDK จัดการ token refresh อัตโนมัติ — developer ไม่ต้อง handle เอง

ปัญหาที่เจอบ่อย & วิธีแก้

Custom claims ไม่ update ทันที

เปลี่ยน role แล้วแต่ user ยังเห็นสิทธิ์เดิม

สาเหตุ: custom claims ฝังใน JWT token — token เก่ายังใช้ได้อีกสูงสุด 1 ชั่วโมง จนกว่าจะ refresh

วิธีแก้:

  • Force token refresh ทันทีหลังเปลี่ยน claims: getIdToken(true) ที่ client
  • ใช้ realtime listener (Firestore/RTDB) แจ้ง client ว่า claims เปลี่ยน → trigger refresh
  • สำหรับ critical permissions: double-check กับ DB ที่ backend เป็น safety net ไม่พึ่ง claims อย่างเดียว

Custom claims เกิน 1000 bytes

ใส่ permissions เยอะเกินใน claims แล้ว Firebase reject

สาเหตุ: Firebase จำกัด custom claims ไว้ที่ 1000 bytes — ใส่ array ของ permissions ยาวๆ ไม่ได้

วิธีแก้:

  • เก็บแค่ role และ orgID ใน claims (~50 bytes) — ไม่ใช่ permissions ทั้งหมด
  • Resolve role → permissions ที่ backend (จาก DB หรือ Redis cache)
  • ใช้ claims เป็น fast-path check, DB เป็น source of truth

Token verify fail — clock skew

Backend verify token แล้วได้ error token used before issued หรือ token expired

สาเหตุ: server clock ไม่ตรงกับ Firebase server — token ที่ issue เมื่อกี้ถูกมองว่า "ยังไม่ถึงเวลา" หรือ "หมดอายุแล้ว"

วิธีแก้:

  • Sync server clock ด้วย NTP: sudo ntpdate pool.ntp.org หรือใช้ chrony
  • Docker: ใช้ host clock (--privileged หรือ mount /etc/localtime)
  • เพิ่ม clock skew tolerance ใน verify logic (Firebase SDK มี built-in ~5 นาที)

Firebase Auth ช้าตอน cold start

Request แรกหลัง deploy ใช้เวลานานกว่าปกติ

สาเหตุ: Firebase Admin SDK ต้อง fetch public keys สำหรับ verify tokens ครั้งแรก — network call ไป Google servers

วิธีแก้:

  • Initialize Firebase Admin SDK ตอน app startup ไม่ใช่ตอน request แรก
  • SDK cache public keys อัตโนมัติ — requests หลังจากนั้นเร็วปกติ
  • ใช้ health check endpoint warm up service หลัง deploy

Account linking conflict

User login ด้วย Google แล้ว login ด้วย email/password ใช้ email เดียวกัน — ได้ 2 accounts

สาเหตุ: Firebase default สร้าง account ใหม่ต่อ provider — ถ้าไม่ enable "One account per email" จะได้ duplicate

วิธีแก้:

  • เปิด "One account per email address" ใน Firebase Console → Authentication → Settings
  • Handle account-exists-with-different-credential error — แจ้ง user ให้ login ด้วย provider เดิมแล้ว link account
  • Backend ใช้ uid (ไม่ใช่ email) เป็น primary key สำหรับ user identification

Service account key หลุด

Service account JSON key ถูก commit เข้า git หรือ expose

สาเหตุ: ใส่ service account key ใน code, commit เข้า repo, หรือ expose ผ่าน public endpoint

วิธีแก้:

  • ใช้ environment variable: GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json
  • อย่า commit key file — ใส่ใน .gitignore เสมอ
  • ถ้าหลุดแล้ว: revoke key ทันทีใน Google Cloud Console → สร้าง key ใหม่
  • Production: ใช้ workload identity (GCP) หรือ instance metadata แทน key file

Related Skills

  • RBAC System — role-based access control ที่ใช้ Firebase custom claims
  • Gin — Go backend ที่ verify Firebase tokens
  • Fiber — Go backend ที่ verify Firebase tokens
  • Kong Gateway — API gateway ที่ verify JWT จาก Firebase
  • Redis — cache permissions ที่ resolve จาก Firebase claims
  • GCP — Firebase อยู่ภายใต้ Google Cloud ecosystem