Client Types
ทำไมประเภทของ client จึงสำคัญ
หัวข้อที่มีชื่อว่า “ทำไมประเภทของ client จึงสำคัญ”เมื่อแอปพลิเคชันของคุณขอ token จาก Keycloak Keycloak จำเป็นต้องรู้ว่า: แอปพลิเคชันนี้เก็บความลับได้หรือไม่? native mobile app หรือ browser-based SPA แจกจ่าย code ของตัวเองไปยังอุปกรณ์ของ end-user ซึ่งไม่มีที่ปลอดภัยให้เก็บ client secret ส่วนแอปพลิเคชันฝั่ง server รันอยู่ในสภาพแวดล้อมที่ควบคุมได้ ซึ่งสามารถเก็บความลับให้พ้นมือคนอื่นได้ ความแตกต่างนี้เองที่นำไปสู่การแบ่งเป็น public กับ confidential
Public client
หัวข้อที่มีชื่อว่า “Public client”public client ไม่สามารถถือความลับได้ source code, compiled bundle หรือ binary ของตัวเองถูกส่งไปยังอุปกรณ์หรือ browser ของ user ซึ่งสามารถถูกตรวจสอบดูได้ เนื่องจากไม่มีความลับ Keycloak จึงไม่สามารถยืนยันตัวตนของ client เองได้ — ยืนยันได้เพียงตัว user เท่านั้น
ใช้ public client สำหรับ:
- Single-page application (React, Vue, Angular, Svelte)
- แอปพลิเคชันบน mobile และ desktop (iOS, Android, Electron)
- เครื่องมือ CLI ที่ทำงานแทน user ที่เป็นมนุษย์
PKCE — การป้องกันสำหรับ public client
หัวข้อที่มีชื่อว่า “PKCE — การป้องกันสำหรับ public client”หากไม่มี client secret Authorization Code flow จะมีช่องโหว่ต่อการ intercept code: ผู้โจมตี intercept authorization code แล้วนำไปแลก token ก่อนที่แอปของคุณจะทำได้ PKCE (Proof Key for Code Exchange, RFC 7636) ปิดช่องโหว่นี้
PKCE ทำงานอย่างไร:
- แอปของคุณสร้าง random string ที่เรียกว่า code verifier
- แอปของคุณ hash ค่านี้ (SHA-256) เพื่อสร้าง code challenge
- แอปของคุณส่ง code challenge ไปยัง Keycloak ตอนเริ่ม login
- Keycloak เก็บ code challenge ไว้
- หลังจาก user ยืนยันตัวตน Keycloak ส่ง authorization code ไปยัง redirect URI ของคุณ
- แอปของคุณส่ง authorization code และ code verifier ตัวเดิม เพื่อแลกเป็น token
- Keycloak hash verifier นั้น เทียบกับ challenge ที่เก็บไว้ และจะออก token ให้ก็ต่อเมื่อตรงกันเท่านั้น
ผู้โจมตีที่ intercept code ได้จะไม่มี verifier จึงไม่สามารถนำไปแลกได้ PKCE เป็นสิ่งบังคับสำหรับ public client บน Keycloak สมัยใหม่; admin console จะเตือนคุณหากปล่อยให้ PKCE ปิดอยู่
การตั้งค่า public client
หัวข้อที่มีชื่อว่า “การตั้งค่า public client”- ใน admin console ให้เปิดแท็บ Settings ของ client คุณ
- ยืนยันว่า Client authentication เป็น Off — สิ่งนี้กำหนดให้ client เป็น public
- เลื่อนไปที่ Advanced (หรือแท็บ Advanced) แล้วยืนยันว่า Proof Key for Code Exchange Code Challenge Method ถูกตั้งค่าเป็น S256
public client จะไม่มีการสร้าง client secret ขึ้นมา แอปพลิเคชันของคุณจะใช้เพียง client ID เท่านั้น
Confidential client
หัวข้อที่มีชื่อว่า “Confidential client”confidential client สามารถถือความลับได้เพราะรันอยู่ในสภาพแวดล้อมฝั่ง server ที่ควบคุมได้ Keycloak จะออก client secret ที่แอปพลิเคชันของคุณต้องแสดงควบคู่ไปกับ authorization code เมื่อแลกเป็น token สิ่งนี้พิสูจน์ต่อ Keycloak ว่าคำขอมาจาก server ที่ถูกต้องของคุณ ไม่ใช่จากคนที่ intercept code ไป
ใช้ confidential client สำหรับ:
- แอปพลิเคชันเว็บฝั่ง server (Node.js/Express, Spring Boot, Django, Laravel)
- backend service ที่เรียก API อื่นในนามของตัวเอง (machine-to-machine / client credentials flow)
- worker และ daemon
การเปิดใช้งาน client authentication
หัวข้อที่มีชื่อว่า “การเปิดใช้งาน client authentication”- ใน admin console ให้เปิดแท็บ Settings ของ client คุณ
- สลับ Client authentication ไปเป็น On
- คลิก Save
Keycloak จะสร้าง client secret ให้โดยอัตโนมัติและแสดงแท็บ Credentials บน client
การค้นหา client secret
หัวข้อที่มีชื่อว่า “การค้นหา client secret”- เปิด client ใน admin console
- คลิกแท็บ Credentials
- ช่อง Client secret จะแสดงค่าความลับ คลิกไอคอนรูปตาเพื่อดูค่า หรือคลิก Copy to clipboard
- หากต้องการหมุน (rotate) secret ให้คลิก Regenerate — secret เดิมจะถูกยกเลิกทันที
curl -X POST http://localhost:8080/realms/my-app/protocol/openid-connect/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials' \
-d 'client_id=my-backend-service' \
-d 'client_secret=YOUR_CLIENT_SECRET'curl นี้สาธิต grant แบบ client credentials — flow แบบ machine-to-machine ที่ไม่มี user เข้ามาเกี่ยวข้อง แทนที่ my-app, my-backend-service และ YOUR_CLIENT_SECRET ด้วยค่าของคุณ
Bearer-only และ service account
หัวข้อที่มีชื่อว่า “Bearer-only และ service account”มี client mode เพิ่มเติมอีกสองแบบที่ควรรู้จัก:
Bearer-only (legacy)
หัวข้อที่มีชื่อว่า “Bearer-only (legacy)”bearer-only client ไม่มีส่วนร่วมใน login flow แต่ทำหน้าที่ตรวจสอบ token ที่ client อื่นได้มาเท่านั้น แบบนี้เคยพบได้ทั่วไปใน Keycloak setup รุ่นเก่าสำหรับ REST API server ล้วน ๆ แต่ใน Keycloak สมัยใหม่ bearer-only ถูกแทนที่ไปเป็นส่วนใหญ่แล้วด้วยการใช้ confidential client กับ client credentials grant หรือด้วยการตั้งค่าให้ API server ของคุณตรวจสอบ JWT โดยตรงผ่าน JWKS endpoint ของ realm โดยไม่ต้องลงทะเบียน client พิเศษ
Service account (client credentials)
หัวข้อที่มีชื่อว่า “Service account (client credentials)”เมื่อคุณเปิดใช้งาน Client authentication บน client และติ๊ก Service accounts roles ใต้ Capability config ด้วย Keycloak จะสร้าง virtual user ที่เรียกว่า service account ขึ้นมาสำหรับ client นั้น คุณสามารถกำหนด realm role และ client role ให้กับ service account นี้ได้ และจะปรากฏใน token แบบ machine-to-machine นี่คือ pattern ที่ถูกต้องสำหรับ backend service ที่ต้องการสิทธิ์แบบจำกัดขอบเขต
ตารางสรุป
หัวข้อที่มีชื่อว่า “ตารางสรุป”| ประเภท client | มี secret | กรณีใช้งานทั่วไป | วิธี auth |
|---|---|---|---|
| Public | ไม่มี | SPA, mobile, CLI | Authorization Code + PKCE |
| Confidential | มี | แอปฝั่ง server | Authorization Code + client secret |
| Confidential (service account) | มี | M2M / daemon | Client credentials grant |
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
| Public client + PKCE | ไม่มี secret ให้รั่วไหล เหมาะกับ SPA/mobile ที่ควบคุม code ฝั่ง client ไม่ได้ | Keycloak ยืนยันตัวตนได้เฉพาะ user ไม่ใช่ตัว client เอง ต้องพึ่ง PKCE เพื่อป้องกัน code interception |
| Confidential client + client secret | ยืนยันตัวตนได้ทั้ง client และ user เหมาะกับ backend ที่ควบคุม secret storage ได้ | ต้องมีที่เก็บ secret ที่ปลอดภัยและกลไก rotate หาก secret รั่วไหลจะกระทบทุก request ที่ใช้ client นั้น |
| Bearer-only (legacy) vs ตรวจสอบ JWT เอง | ไม่ต้องลงทะเบียน client พิเศษ ลด surface การตั้งค่า | Keycloak รุ่นใหม่แนะนำให้ API server ตรวจสอบ JWT ผ่าน JWKS โดยตรงแทน — bearer-only ถูกเลิกใช้ไปเป็นส่วนใหญ่แล้ว |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- ตั้งค่า SPA เป็น confidential client — SPA ไม่มีที่ปลอดภัยให้เก็บ secret ทำให้ secret รั่วไหลผ่าน browser devtools หรือ network tab ได้ทันที ควรใช้ public client ร่วมกับ PKCE เสมอ
- ปิด PKCE บน public client ด้วยมือ — Keycloak สมัยใหม่บังคับ PKCE ให้อยู่แล้ว แต่การตั้ง Code Challenge Method กลับไปเป็น none เปิดช่องให้เกิด authorization-code interception attack ได้อีกครั้ง
- ใช้ client secret เดียวกันข้ามหลาย environment — หาก secret รั่วไหลใน environment หนึ่ง (เช่น staging) จะกระทบทุก environment ที่ใช้ secret เดียวกัน ควรแยกและ rotate secret ต่อ environment เสมอ
💡 ตัวอย่างจากของจริง
Netflix และแอปมือถือ/smart TV ทั่วไป — ใช้ public client ร่วมกับ PKCE เพราะ binary ของแอปเหล่านี้สามารถถูก decompile หรือตรวจสอบได้ ไม่มีที่ใดปลอดภัยพอสำหรับ client secret
Backend-for-frontend (BFF) pattern — หลายทีมใช้ confidential client ฝั่ง server เพื่อแลก token แทน SPA โดยตรง แล้วส่งผลลัพธ์กลับผ่าน cookie ของตัวเอง ลดพื้นที่การโจมตีของ token ใน browser ลงไปอีกขั้น