Firebase
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
# 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 authFirebase 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
Client → Firebase Auth (login) → ID Token (JWT)
Client → API Gateway → Backend (verify token) → Response- Client login ผ่าน Firebase SDK (email/password, Google, etc.)
- Firebase ออก ID token (JWT) ให้ client
- Client ส่ง token ใน
Authorization: Bearer <token>header ทุก request - Backend verify token ด้วย Firebase Admin SDK — ไม่ต้อง call Firebase server
Verify ID Token (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)
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
// 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
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:
// Client-side: force refresh token
await firebase.auth().currentUser.getIdToken(true);หรือ backend revoke tokens เก่าทั้งหมด:
// Revoke refresh tokens (Admin SDK)
client.RevokeRefreshTokens(ctx, uid)User Management (Admin SDK)
// สร้าง 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:
// 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:
// Client: ส่ง OTP
const confirmationResult = await signInWithPhoneNumber(auth, "+66812345678", appVerifier);
// Client: verify OTP ที่ user กรอก
const userCredential = await confirmationResult.confirm(otpCode);Backend verify phone number:
// ตรวจว่า 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:
// 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 จริง:
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
Authorizationheader ไป 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-credentialerror — แจ้ง 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