Single sign-on
หน้านี้สอนอะไร
ให้คนเข้าสู่ระบบหน้า admin ด้วย Google, Microsoft, GitHub หรือผู้ให้บริการ OpenID Connect ใดก็ได้ ใครเข้าได้บ้าง และวิธีตั้งค่าแต่ละเจ้า
ควรอ่านก่อน: ผู้ใช้และการยืนยันตัวตน

ติดตั้ง package แล้วใส่ผู้ให้บริการใน config:
npm install @easy-cms/auth-oauthpnpm add @easy-cms/auth-oauthyarn add @easy-cms/auth-oauthbun add @easy-cms/auth-oauthimport { github, google, microsoft } from '@easy-cms/auth-oauth'
export default defineConfig({
serverURL: 'https://cms.example.com', // ต้องมีบน production ใช้สร้าง callback URL
auth: {
providers: [google()], // อ่าน GOOGLE_CLIENT_ID และ GOOGLE_CLIENT_SECRET
},
// …
})หน้า login จะมีปุ่ม เข้าสู่ระบบด้วย Google ผู้ให้บริการจะส่งคนกลับมาที่ <serverURL>/api/cms/auth/<id>/callback เช่น https://cms.example.com/api/cms/auth/google/callback ให้นำ URL นี้ไปกรอกฝั่งผู้ให้บริการ (หน้า ตั้งค่า → Single sign-on แสดงไว้พร้อมปุ่มคัดลอก) single sign-on ใช้กับหน้า admin เท่านั้น ไม่กระทบผู้เข้าชมเว็บของคุณ

การเปิดใช้ผู้ให้บริการจะเพิ่มตาราง user-identities จึงต้องสร้าง migration (npx easy-cms migrate:create sso)
ใครเข้าได้บ้าง
คนที่มีบัญชีอยู่แล้ว ต้องเชื่อมผู้ให้บริการก่อน: เข้าสู่ระบบด้วยรหัสผ่านแล้วกด เชื่อม Google (หรือผู้ให้บริการอื่น) ที่หน้า บัญชีของฉัน ปุ่มของผู้ให้บริการที่หน้า login ใช้เชื่อมไม่ได้ หลังจากนั้นจะใช้ id ของบัญชีจากผู้ให้บริการ ถ้าอีเมลฝั่งผู้ให้บริการเปลี่ยนก็ยังเข้าได้ ถ้าลองเข้าด้วยผู้ให้บริการก่อนเชื่อม ระบบจะบอกให้เชื่อมก่อน
จับคู่ด้วยอีเมลแทน สำหรับผู้ให้บริการที่องค์กรของคุณควบคุมอีเมลเอง (Google Workspace หรือ Entra ID ขององค์กร):
google({ linkByEmail: true })นับเฉพาะอีเมลที่ผู้ให้บริการยืนยันแล้ว ส่วนสมาชิกเว็บ (auth.members) จับคู่ด้วยอีเมลเสมอคนจากโดเมนของคุณ เมื่อเปิดให้ จะได้บัญชีตอนเข้าสู่ระบบครั้งแรก
tsauth: { providers: [google()], providerSignUp: { domains: ['example.com'], role: 'editor' }, // ห้ามเป็น 'admin' },คนอื่นเข้าไม่ได้ อีเมลที่ไม่รู้จักจะถูกส่งกลับไปหน้า login พร้อมข้อความให้ติดต่อผู้ดูแลระบบ
ผู้ใช้ที่ถูกปิดใช้งานเข้าไม่ได้ ไม่ว่าผู้ให้บริการจะว่าอย่างไร
การเพิ่มคน ให้สร้างผู้ใช้ใน ตั้งค่า → ผู้ใช้ (ด้วยอีเมลที่ทำงาน) แล้วส่งคำเชิญ ผู้ใช้เชื่อมผู้ให้บริการที่หน้าบัญชีของตัวเอง หรือเข้าด้วยผู้ให้บริการได้ทันทีเมื่อตั้ง linkByEmail
รหัสผ่าน
ค่าเริ่มต้นเข้าสู่ระบบได้ทั้งสองแบบ ถ้าต้องการให้ทุกคนใช้ผู้ให้บริการ:
auth: { providers: [google()], password: false },แบบนี้จะมีแต่ ผู้ดูแลระบบ ที่ยังใช้รหัสผ่านได้ เป็นทางเข้าสำรองเมื่อผู้ให้บริการล่ม หน้า login พับฟอร์มรหัสผ่านไว้ให้ คำเชิญจะบอกให้เข้าสู่ระบบด้วยผู้ให้บริการแทนการตั้งรหัสผ่าน และ "ลืมรหัสผ่าน" ใช้ได้เฉพาะผู้ดูแลระบบ
เชื่อมบัญชี
ในหน้า Account แต่ละคนเห็นบัญชีภายนอกที่ใช้เข้าสู่ระบบ เชื่อมผู้ให้บริการเพิ่มได้ (เชื่อม GitHub) และยกเลิกการ เชื่อมได้ แต่ยกเลิกทางเข้าสุดท้ายของบัญชีไม่ได้ ผู้ดูแลระบบเห็นและยกเลิกบัญชีของผู้ใช้ได้ในหน้าของผู้ใช้คนนั้น การลบผู้ใช้ จะลบบัญชีที่เชื่อมไว้ด้วย
ตั้งค่าผู้ให้บริการ
Google
- ใน Google Cloud console สร้าง OAuth client ID แบบ Web application ถ้าถูกถามให้ตั้ง consent screen ก่อน: สำหรับ Google Workspace เลือก Internal ถ้าไม่ใช่ให้เลือก External และระหว่างที่อยู่ในสถานะ Testing ให้เพิ่มบัญชี Google ที่จะ sign in ไว้ใน Test users (บัญชีอื่นจะถูกปฏิเสธ และ Google จะเตือนว่าแอปยังไม่ได้รับการยืนยันจนกว่าจะ publish)
- ใส่ callback URL ใน Authorized redirect URIs เช่น
https://cms.example.com/api/cms/auth/google/callback(และhttp://localhost:3000/api/cms/auth/google/callbackสำหรับตอนพัฒนา) - ตั้ง
GOOGLE_CLIENT_IDและGOOGLE_CLIENT_SECRETแล้วใช้google()สำหรับ Workspacegoogle({ hd: 'example.com' })จะเปิดหน้าเลือกบัญชีที่โดเมนของคุณ
Microsoft (Entra ID)
- ใน Entra admin center ไปที่ App registrations → New registration เลือกเฉพาะบัญชีในองค์กรนี้ และใส่ redirect URI แบบ Web:
https://cms.example.com/api/cms/auth/microsoft/callback - ใน Certificates & secrets สร้าง client secret
- ตั้ง
MICROSOFT_TENANT_ID(Directory (tenant) ID),MICROSOFT_CLIENT_ID(Application (client) ID) และMICROSOFT_CLIENT_SECRETแล้วใช้microsoft()
Entra ID ไม่ระบุว่าอีเมลยืนยันแล้วหรือยัง แต่องค์กรของคุณเป็นผู้จัดการอีเมลเหล่านั้นเอง จึงนับว่ายืนยันแล้ว ใช้เฉพาะ claim email เท่านั้น ไม่ใช้ user principal name
GitHub
- ใน GitHub ไปที่ Settings → Developer settings → OAuth Apps → New OAuth App ใส่ callback URL
https://cms.example.com/api/cms/auth/github/callback - สร้าง client secret ตั้ง
GITHUB_CLIENT_IDและGITHUB_CLIENT_SECRETแล้วใช้github()
จับคู่ด้วยอีเมลหลักที่ยืนยันแล้วของบัญชี GitHub สำหรับ GitHub Enterprise Server: github({ server: { web: 'https://github.example.com', api: 'https://github.example.com/api/v3' } })
ผู้ให้บริการ OpenID Connect อื่นๆ
Okta, Keycloak, Auth0, Authentik, Zitadel และอื่นๆ:
import { oidc } from '@easy-cms/auth-oauth'
oidc({
id: 'okta', // อยู่ใน callback URL: <api>/auth/okta/callback
name: 'Okta', // บนปุ่ม
issuer: 'https://example.okta.com',
clientId: process.env.OKTA_CLIENT_ID ?? '',
clientSecret: process.env.OKTA_CLIENT_SECRET,
})ระบบอ่าน /.well-known/openid-configuration ของผู้ให้บริการเพื่อหา endpoint และ ID token ต้องมี email กับ email_verified (scope email)
id ห้ามซ้ำกับ action ของการเข้าสู่ระบบใต้ /auth/ (login, logout, me, init, signup, verify-email, forgot-password, reset-password, first-register) หรือ identities
ความปลอดภัย
- ใช้ Authorization Code flow แบบ PKCE พร้อม
stateและnonce(OpenID Connect) เก็บไว้ใน cookie ที่ลงลายเซ็น อายุสั้น และตรวจ ID token ด้วย key ของผู้ให้บริการ (oauth4webapi) - หลังเข้าสู่ระบบ ระบบพากลับได้เฉพาะหน้าใน admin
- การเชื่อมบัญชีต้องใช้ session และ CSRF token และบัญชีที่ผูกกับคนอื่นอยู่แล้วจะผูกซ้ำไม่ได้
- client secret อยู่ใน environment variable ไม่ถูกเก็บในฐานข้อมูลหรือไฟล์ backup
ขั้นต่อไป
- บทบาทและสิทธิ์จากหน้า admin: กำหนดว่าแต่ละคนทำอะไรได้หลังเข้ามาแล้ว
- ความปลอดภัย: สิ่งที่ระบบป้องกันให้เพิ่มเติม