IT General
น้องๆ เคยสงสัยมั้ย เวลาเรา login เข้าเว็บหรือแอปต่างๆ ด้วย Google หรือ Facebook มันทำงานยังไง? นั่นแหละ OAuth2 กับ OpenID Connect (OIDC) คือพระเอกของงานนี้เลย สมัยผมทำร้านเน็ตฯ ใหม่ๆ เรื่องพวกนี้ยังไม่บูมขนาดนี้ แต่พอโลกมันหมุนเร็วขึ้น การยืนยันตัวตนแบบเดิมๆ มันเริ่มไม่ตอบโจทย์แล้ว
OAuth2 มันเหมือน "บัตรผ่าน" ที่ให้แอปเราเข้าถึงข้อมูลบางอย่างในบัญชี Google หรือ Facebook ของเราได้ โดยที่เราไม่ต้องบอกรหัสผ่านให้แอปนั้นรู้เลยนะ ปลอดภัยกว่าเยอะ ส่วน OpenID Connect มันต่อยอดจาก OAuth2 เพิ่มเติมเรื่อง "ข้อมูลประจำตัว" (Identity) เข้ามา ทำให้แอปสามารถรู้ได้ว่าเราเป็นใคร ชื่ออะไร อีเมลอะไร โดยที่เราอนุญาต
ทำไมมันถึงสำคัญ? ลองนึกภาพว่าถ้าทุกแอปต้องสร้างระบบ login เองหมด มันจะวุ่นวายขนาดไหน แถมข้อมูลส่วนตัวของเราก็จะกระจัดกระจายไปทั่ว การใช้ OAuth2/OIDC ช่วยให้เราควบคุมข้อมูลได้ดีขึ้น และสะดวกสบายกว่าเดิมเยอะเลย SiamCafe Blog เราก็มีบทความเรื่อง security เยอะนะ ลองไปอ่านดูได้
OAuth2 เป็น framework ที่เน้นเรื่องการ "ให้สิทธิ์" (Authorization) คือการอนุญาตให้แอปพลิเคชันหนึ่งเข้าถึง resource ของอีกแอปพลิเคชันหนึ่งได้ โดยที่ resource owner (เจ้าของข้อมูล) เป็นคนให้สิทธิ์เอง สมมติเราอยากให้แอปแต่งรูปดึงรูปจาก Google Photos มาใช้ OAuth2 จะเป็นตัวจัดการให้เราอนุญาตได้โดยไม่ต้องให้แอปแต่งรูปนั้นรู้ password Google account ของเรา
OpenID Connect สร้างอยู่บน OAuth2 เพิ่มเติมเรื่อง "Identity" คือข้อมูลประจำตัวของผู้ใช้ OIDC จะมีสิ่งที่เรียกว่า "ID Token" ซึ่งเป็น JSON Web Token (JWT) ที่เก็บข้อมูลเกี่ยวกับผู้ใช้ เช่น ชื่อ อีเมล รูปโปรไฟล์ ซึ่งแอปพลิเคชันสามารถนำไปใช้ยืนยันตัวตนของผู้ใช้ได้
JWT เป็นมาตรฐานสำหรับการแลกเปลี่ยนข้อมูลระหว่าง parties ในรูปแบบ JSON ที่มีการเข้ารหัส (signed) ทำให้มั่นใจได้ว่าข้อมูลนั้นมาจากแหล่งที่เชื่อถือได้ และไม่มีใครแก้ไขระหว่างทาง ID Token ของ OIDC ก็คือ JWT นี่แหละ
การใช้งาน OAuth2/OIDC อาจจะดูซับซ้อนในช่วงแรก แต่จริงๆ แล้วมันมี libraries และ services ต่างๆ ช่วยให้เราใช้งานได้ง่ายขึ้นเยอะ สมัยผมเริ่มทำเว็บใหม่ๆ ต้องเขียนทุกอย่างเองหมด ตอนนี้สบายขึ้นเยอะ
ขั้นแรกเราต้องไป register แอปพลิเคชันของเรากับ Identity Provider (IdP) เช่น Google, Facebook, หรือ Azure AD เราจะได้ Client ID และ Client Secret มา ซึ่ง Client ID คือเหมือนชื่อ username ของแอปเรา ส่วน Client Secret คือ password ของแอปเรา ห้ามให้ใครรู้นะ
เมื่อผู้ใช้ต้องการ login ผ่าน IdP แอปเราจะสร้าง Authorization Request ส่งไปยัง IdP ซึ่ง request นี้จะระบุข้อมูลต่างๆ เช่น Client ID, Redirect URI (URL ที่ IdP จะ redirect กลับมาหลังจาก login สำเร็จ), Scope (สิทธิ์ที่เราต้องการ เช่น อีเมล รูปโปรไฟล์)
GET /authorize?client_id={CLIENT_ID}
&response_type=code
&scope=openid profile email
&redirect_uri={REDIRECT_URI}
&state={STATE}
คำอธิบาย:
client_id: Client ID ที่ได้จากการ register แอปresponse_type: ระบุว่าเราต้องการ Authorization Codescope: สิทธิ์ที่เราต้องการ (openid จำเป็นสำหรับ OIDC)redirect_uri: URL ที่ IdP จะ redirect กลับมาstate: ค่าสุ่มที่เราสร้างขึ้นมา เพื่อป้องกัน CSRF attackหลังจากผู้ใช้ login สำเร็จ IdP จะ redirect กลับมาที่ Redirect URI ของเรา พร้อมกับ Authorization Code เราต้องเอา Authorization Code นี้ไปแลกเป็น Access Token และ ID Token กับ IdP อีกที
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code={AUTHORIZATION_CODE}
&redirect_uri={REDIRECT_URI}
&client_id={CLIENT_ID}
&client_secret={CLIENT_SECRET}
Response:
{
"access_token": "{ACCESS_TOKEN}",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "{REFRESH_TOKEN}",
"id_token": "{ID_TOKEN}"
}
access_token ใช้สำหรับเข้าถึง resource ที่เราขอสิทธิ์ไว้ ส่วน id_token เป็น JWT ที่เก็บข้อมูลประจำตัวของผู้ใช้ เราสามารถ decode JWT นี้เพื่อดึงข้อมูลออกมาใช้ได้ SiamCafe Blog มีเครื่องมือ decode JWT ให้ลองเล่นด้วยนะ
เมื่อก่อนตอนผมทำร้านเน็ตฯ เราก็ใช้วิธีเก็บ username/password เองหมด แต่ข้อเสียคือเราต้องดูแลเรื่อง security เองทั้งหมด แถมผู้ใช้ต้องจำ password หลายชุด ปวดหัวทั้งคนทำทั้งคนใช้
OAuth2/OIDC ช่วยแก้ปัญหาเหล่านี้ได้ โดยให้ IdP ที่น่าเชื่อถือจัดการเรื่องการยืนยันตัวตนให้เรา เราแค่รับข้อมูลประจำตัวของผู้ใช้มาใช้งาน
| คุณสมบัติ | OAuth2/OIDC | Username/Password |
|---|---|---|
| ความปลอดภัย | สูง (ใช้ IdP ที่น่าเชื่อถือ) | ขึ้นอยู่กับการ implement ของเรา |
| ความสะดวก | สูง (Single Sign-On) | ต่ำ (ต้องจำหลาย password) |
| การจัดการข้อมูล | ดี (ผู้ใช้ควบคุมสิทธิ์ได้) | แย่ (ข้อมูลกระจัดกระจาย) |
| ความซับซ้อนในการพัฒนา | ปานกลาง (มี libraries ช่วย) | ต่ำ (แต่ต้องดูแล security เอง) |
น้องๆ หลายคนถามพี่ว่า "พี่บอมครับ OAuth2 กับ OpenID Connect นี่มันยากจัง มีวิธีทำให้มันง่ายขึ้นไหม?" เอาจริงๆ นะ สมัยพี่ทำร้านเน็ต SiamCafe พี่ก็ต้องเรียนรู้ไปพร้อมๆ กับพัฒนาเว็บ พี่เลยเข้าใจว่ามันไม่ง่ายจริงๆ นั่นแหละ
แต่ไม่ต้องห่วง พี่มีเคล็ดลับที่สั่งสมมาตลอด 28+ ปีในวงการ IT มาฝากกัน รับรองว่าเอาไปใช้ได้จริงแน่นอน!
อย่าเพิ่งอยากได้ข้อมูล User ทุกอย่างตั้งแต่แรก! สมัยก่อนพี่เคยเจอเคสที่ขอ Scope เยอะเกินไป ทำให้ User กลัว ไม่กล้า Login เพราะรู้สึกว่าเราจะเอาข้อมูลเขาไปทำอะไรก็ไม่รู้
เริ่มจาก Scope ที่จำเป็นจริงๆ ก่อน เช่น `profile`, `email` แล้วค่อยๆ เพิ่มทีหลังตามความจำเป็น จะทำให้ User Trust มากกว่า
OAuth2 กับ OpenID Connect มันซับซ้อน การเขียนเองทั้งหมดตั้งแต่ศูนย์ (reinventing the wheel) ไม่คุ้มค่าแน่นอน เลือก Library ที่ Support ดีๆ มี Community คอยช่วยเหลือ จะช่วยประหยัดเวลาและลด Bug ได้เยอะ
ตัวอย่าง Library ที่พี่แนะนำ:
เรื่อง Authentication/Authorization นี่พลาดไม่ได้เลยนะน้อง! การ Test ให้ครอบคลุมทุก Case สำคัญมากๆ ไม่ว่าจะเป็น Login สำเร็จ, Login ไม่สำเร็จ, Permission ถูกต้อง, Permission ไม่ถูกต้อง
สมัยพี่ทำร้านเน็ต SiamCafe นี่เจอเคสลูกค้า Hack Account กันบ่อยมาก เพราะระบบ Authentication ไม่แข็งแรงพอ ดังนั้น Test ให้ละเอียดถี่ถ้วน จะช่วยป้องกันปัญหาได้เยอะ
อย่าปล่อยให้ Error หลุดออกมาแบบ User ไม่รู้เรื่อง! ทำ Error Handling ให้ดี แสดง Error Message ที่เข้าใจง่าย บอก User ว่าต้องทำยังไงต่อ
พี่เคยเจอเว็บที่ Error แบบ "Something went wrong" แล้ว User ก็งง ไม่รู้จะทำยังไงต่อ สุดท้ายก็เลิกใช้เว็บนั้นไปเลย เพราะฉะนั้น Error Handling สำคัญมากๆ
OAuth2 เป็น Protocol สำหรับ Authorization (การอนุญาตให้ Application เข้าถึง Resource ของ User) ส่วน OpenID Connect เป็น Layer ที่อยู่บน OAuth2 เพิ่มเติมเข้ามา เพื่อให้ Application สามารถ Verify Identity ของ User ได้
เปรียบเทียบง่ายๆ OAuth2 เหมือนกุญแจที่ให้ Application เข้าไปในบ้าน User ได้ ส่วน OpenID Connect เหมือนบัตรประชาชนที่ยืนยันว่าใครเป็นเจ้าของบ้าน
ถ้า Application ของน้องต้องการแค่เข้าถึง Resource ของ User (เช่น รูปภาพ, Contact) โดยที่ไม่จำเป็นต้องรู้ว่า User คือใคร ใช้แค่ OAuth2 ก็พอ
แต่ถ้า Application ของน้องต้องการ Verify Identity ของ User (เช่น Login) ต้องใช้ OpenID Connect
ง่ายๆ เลยคือ ต้องมี Authorization Server ที่คอย Verify Access Token ก่อนที่จะอนุญาตให้ Application เข้าถึง API ของน้องได้
ลองดู Code ตัวอย่างง่ายๆ:
// Middleware function to protect API
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization']
const token = authHeader && authHeader.split(' ')[1]
if (token == null) return res.sendStatus(401)
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403)
req.user = user
next()
})
}
OAuth2 และ OpenID Connect เป็น Technology ที่สำคัญมากๆ ในยุคปัจจุบัน ช่วยให้ Application สามารถ Integrate กับ Services ต่างๆ ได้อย่างปลอดภัยและสะดวกสบาย
ถึงแม้ว่ามันจะดูซับซ้อน แต่ถ้าเข้าใจ Concept และ Best Practices ที่พี่แนะนำไป น้องๆ ก็จะสามารถนำไปประยุกต์ใช้ได้อย่างมีประสิทธิภาพแน่นอน
อย่าลืมว่าการเรียนรู้ไม่มีที่สิ้นสุด พัฒนาตัวเองอยู่เสมอ แล้วน้องๆ จะเก่งขึ้นเรื่อยๆ iCafeForex เป็นกำลังใจให้ทุกคน!
ถ้าอยากอ่านบทความอื่นๆ ที่พี่เขียน ลองเข้าไปดูได้ที่ SiamCafe Blog นะครับ