Token และ JWT คืออะไร? + ทำ JWT Authentication ด้วย Hapi.js
เนื่องจากบทความนี้ ไม่ได้อัพเดทเนื้อหาที่เขียนไว้ตั้งแต่ปี 2016 แนะนำอ่านบทความล่าสุด ที่นี่แทนครับ
JWT คืออะไร? + ลองทำ JWT Authentication ด้วย Express.js
เนื่องจากปัจจุบันได้หันมาพัฒนาเว็บไซต์ในรูปแบบ RESTFul API ซึ่งเป็น Web Server ในรูปแบบ stateless สำหรับเป็น API ทั้ง Single Page Application และ Mobile คือไม่มีการจดจำ state ของผู้ใช้แต่ว่าใช้ token base แทน ซึ่งปกติก็ใช้แต่ตัว jwt.io ของ Node.js ในการ sign, verify token แต่ไม่รู้ว่าส่วนประกอบของ token นั้นมันประกอบด้วยอะไรบ้าง วันนี้ก็เลยไปนั่งอ่านแล้วสรุปมาเป็นบทความครับ
Token คืออะไร?
เป็นรหัสชุดนึงที่เอาไว้สำหรับทดแทน session ซึ่งเอาไว้ระบุว่าคนๆนั้นคือใคร ตัวอย่างเช่น Facebook เมื่อล็อคอินเสร็จแล้วจะมี accessToken
เพื่อระบุตัวตนว่าเป็นใคร ซึ่งตัว token เอามาใช้ในการทำ RESTFul API ทดแทนการทำ Web Server แบบเดิมๆ ที่เก็บในรูปแบบ session โดยตัว token จะถูกส่งไปทุกๆ request ผ่าน HTTP Headers
JWT คืออะไร?
JWT ย่อมาจาก JSON Web Token เป็นรูปแบบหนึ่งที่ใช้ในการสร้างรหัส token จากข้อมูล JSON Data แล้วทำการเข้ารหัสด้วย Base64Url Encoded ซึ่งมีหน้าตาลักษณะประมาณนี้
จะเห็นว่าตัวอย่าง JWT ด้านบน จะมีตัวจุด (.) ขั้นไว้ คือ
ซึ่งทั้ง 3 ส่วนประกอบไปด้วย
- Header : (คือข้อมูล metadata ของ token ซึ่งบอกว่า เป็น type และใช้ algorithm อะไร)
- Body หรือ Payload หรือ Claims : ข้อมูลทั้งหมดที่เราเอาไว้ sign token
- Signature : ส่วนสำคัญของข้อมูล เป็นการรวมกันของ Header และ Body ใช้ algorithm และ secret key ในการ sign
Header
Header ประกอบไปด้วย 2 ส่วนคือ type เป็น JWT
และ hash algorithm ที่ใช้ เช่น HMAC SHA256 ตัวอย่าง
เมื่อนำข้อมูล header มาเข้ารหัสด้วย Base64Url encoded ก็จะได้ข้อมูลประมาณ
Payload
Payload ประกอบไปด้วยข้อมูล information ของคนๆนั้น เช่น id, name มีทั้งที่เป็น Private หรือ Public Data ข้อมูล JSON ของ payload มีหน้าตาประมาณนี้
sub
: subject เอาไว้สำหรับ authenticate user (เช่น user Id)exp
: คือเวลาหมดอายุของ tokeniat
: Issued at timestamp บอกว่า token สร้างเมือไหร่
และเมื่อนำข้อมูล payload มาเข้ารหัสด้วย Base64Url encoded ก็จะได้ข้อมูลประมาณ
ไม่ควรเก็บข้อมูลที่เป็น Sensitive Data ไว้ใน token นะครับ เพราะสามารถดูข้อมูลข้างในได้ แม้จะไม่มี secret ก็ตาม
Signature
การจะสร้าง Signature ได้จำเป็นต้องใช้
- header ที่ได้จากการ encoded แล้ว
- payload ที่ได้จากการ encoded แล้ว
- secret key ที่จะใช้
- algorithm ที่จะใช้ เช่น
HMACSHA256
ตัวอย่างของการ gen signature คือ
เมื่อรวมทั้งสามส่วนมารวมกัน คั่นด้วยเครื่องหมายจุด(.) ก็จะได้ข้อมูลเป็น token นั่นเอง
สร้างโปรเจ็คด้วย Hapi.js
ทดลองทำระบบ Authentication API ง่ายๆด้วย
ไฟล์ package.json
สร้างไฟล์ server.js
ด้วย Hapijs แบบง่ายๆ โดยมีแค่ 2 routes คือ
/
: assume ว่าส่งPOST username, password
และได้ token กลับมา/me
: ต้องแนบ token ส่งไปด้วย เพื่อเรียกดูข้อมูลของ user นั้นๆ
สำหรับ hapi-auth-jwt2
เวลาใช้งาน เราต้องทำการ
- Register Plugin ด้วย
server.register()
- กำหนด auth strategy เป็น
jwt
- ทุก route กำหนด authenticated ผ่าน
config
ทำการ register plugin
อธิบายโค๊ดด้านบนคือ
- ตัว
hapi-auth-jwt2
จะมีvalidateFunc
เอาไว้สำหรับทำการ validate jwt ซึ่งค่าที่ได้จากการ validate จะอยู่ในตัวแปรdecoded
ในตัวอย่างคือเช็คว่าdecoded.name
นั้นเท่ากับChai Phonbopit
หรือไม่ ถ้าใช่ก็ returncallback(null, false)
กลับไป แสดงว่าtoken
ถูกต้อง
โดยปกติแล้ว ตรงส่วน
validate
จะเอาไว้เช็คว่า User นี้มีจริงหรือไม่ เช่น ใช้ mongooseUser.find({_id: decoded.id}).exec()
เป็นต้น
ต่อมาแก้ไขตรง route /
เพื่อเวลาเข้าหน้านี้จะให้มันทำการส่ง token ที่ sign ด้วย user
กลับมา เพื่อเอาไว้ใช้ในหน้า /me
นั่นเอง
โค๊ดด้านบน เราทำการเพิ่ม
เพราะว่า default เรากำหนดว่าให้ server.auth.default('jwt');
ทำให้ทุกๆ request จะเช็ค headers.authorization
ทุกครั้ง เมือเรากดหนด auth: false
path /
ก็จะไม่ต้อง require token นั่นเอง
ต่อมา
ทำการ generate token ด้วย JWT.sign(payload, secretKey, options)
และส่ง token กลับไปให้ User
สุดท้ายของเข้า /me
แบบไม่ได้แนบ token
และเข้า /me
โดยการแนบ token ก็จะสามารถ access หน้านั้นได้
เป็นอันเรียบร้อย
References:
- Authors
-
Chai Phonbopit
เป็น Web Dev ในบริษัทแห่งหนึ่ง ทำงานมา 10 ปีกว่าๆ ด้วยภาษาและเทคโนโลยี เช่น JavaScript, Node.js, React, Vue และปัจจุบันกำลังสนใจในเรื่องของ Blockchain และ Crypto กำลังหัดเรียนภาษา Rust