JWT (JSON Web Token) เป็นรูปแบบของ token ที่ใช้สำหรับรับรองตัวตนและการเข้าถึงแอปพลิเคชัน ซึ่งประกอบด้วยสามส่วนหลักคือ Header, Payload และ Signature

1. Header ของ JWT เป็นอ็อบเจกต์ JSON ที่ประกอบด้วยสองสมาชิกคือ "alg" ซึ่งระบุวิธีการเข้ารหัสและ "typ" ซึ่งระบุประเภทของ token ซึ่งจะมีค่าคงที่เป็น "JWT" ตัวอย่าง:

{
  "alg": "HS256",
  "typ": "JWT"
}

2. Payload ของ JWT เป็นอ็อบเจกต์ JSON ที่ประกอบด้วยข้อมูลที่เราต้องการเก็บใน token อาทิเช่น ชื่อผู้ใช้ สิทธิ์การเข้าถึง หรือข้อมูลอื่นๆ ซึ่งจะถูกเข้ารหัสและเก็บไว้ใน JWT ตัวอย่าง:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

3. Signature ของ JWT เป็นส่วนที่ใช้สำหรับตรวจสอบว่า token ไม่ถูกแก้ไข โดยใช้คีย์ลับ (secret key) เพื่อเข้ารหัสข้อมูลใน Header และ Payload ด้วยวิธีการเข้ารหัสที่ระบุไว้ใน Header และคีย์ลับที่เป็นความลับเท่านั้นที่จะใช้ถอด Signature เพื่อตรวจสอบว่า token ไม่ถูกปลอมแปลง Signature จะถูกสร้างโดยนำ Header และ Payload ที่เข้ารหัสเป็น Base64 มาต่อกันด้วยจุด "." และนำไปเข้ารหัสอีกครั้งด้วยคีย์ลับเพื่อสร้าง Signature ตัวอย่าง:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

เมื่อนำสามส่วนทั้งหมดมาต่อกันจะได้ JWT ดังนี้:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

โดยตัวอักษร "eyJ" ที่มาก่อนจุด "." คือ Header, ตัวอักษรต่อมาที่มาก่อนจุด "." คือ Payload และตัวอักษรที่ตามมาคือ Signature ที่ถูกเข้ารหัสด้วย Base64Url และ HMAC-SHA256

ด้านล่างนี้เป็นตัวอย่างโค้ด Node.js ที่ใช้สำหรับสร้างและยืนยัน JWT ในแอปพลิเคชัน Node.js: ก่อนอื่นให้ติดตั้ง jsonwebtoken โดยใช้คำสั่ง npm install jsonwebtoken

const jwt = require('jsonwebtoken');

// สร้าง JWT
const createToken = (payload, secretKey, expiresIn) => {
  return jwt.sign(payload, secretKey, { expiresIn });
};

// ยืนยัน JWT
const verifyToken = (token, secretKey) => {
  try {
    return jwt.verify(token, secretKey);
  } catch (err) {
    return false;
  }
};

// ตัวอย่างการใช้งาน
const payload = { username: 'johndoe' };
const secretKey = 'mysecretkey';
const token = createToken(payload, secretKey, '1h');

console.log(token); // แสดงค่าของ JWT ที่สร้างขึ้น

const verifiedPayload = verifyToken(token, secretKey);

if (verifiedPayload) {
  console.log(verifiedPayload); // แสดงผลลัพธ์
} else {
  console.log('Token is invalid'); // แสดงข้อความเมื่อ Token ไม่ถูกต้อง
}

ในตัวอย่างนี้ ฟังก์ชัน createToken() ใช้สำหรับสร้าง JWT โดยรับพารามิเตอร์ payload ซึ่งเป็นข้อมูลที่จะถูกเข้ารหัสลงใน JWT, secretKey ซึ่งเป็นคีย์สำหรับเข้ารหัส JWT และ expiresIn ซึ่งระบุระยะเวลาการใช้งานของ JWT. สำหรับฟังก์ชัน verifyToken() จะใช้สำหรับตรวจสอบว่า JWT ที่รับเข้ามาถูกต้องหรือไม่ โดยการใช้ jwt.verify() ของ jsonwebtoken. ในตัวอย่างนี้เราสามารถใช้ JWT เพื่อทำการรับรองตัวตนในแอปพลิเคชันของเราได้ โดยใช้ JWT เป็นตัวบอกตนแทนการส่งข้อมูลสมบูรณ์ของผู้ใช้ทุกครั้งที่มีการเข้าถึงแอปพลิเคชัน.

jwt, jwe, jws, jwk ต่างกันอย่างไร

JWT, JWE, JWS, และ JWK เป็นมาตรฐานของเทคโนโลยีความปลอดภัยและการรับส่งข้อมูลอย่างปลอดภัยผ่านเครือข่ายต่าง ๆ ซึ่งมีลักษณะแตกต่างกันดังนี้

1. JWT (JSON Web Token) คือมาตรฐานสำหรับสร้างและตรวจสอบ token ในรูปแบบ JSON โดย JWT มีส่วนประกอบ 3 ส่วน ได้แก่ header, payload และ signature

2. JWE (JSON Web Encryption) คือมาตรฐานสำหรับเข้ารหัสข้อมูลในรูปแบบ JSON โดยใช้ส่วนประกอบต่าง ๆ เช่น header, payload, encryption algorithm, key encryption algorithm และ key management algorithm

3. JWS (JSON Web Signature) คือมาตรฐานสำหรับตรวจสอบลายเซ็น digital signature บนข้อมูลในรูปแบบ JSON โดยใช้ส่วนประกอบต่าง ๆ เช่น header, payload และ signature

4. JWK (JSON Web Key) คือมาตรฐานสำหรับการส่งข้อมูลเกี่ยวกับ public key และ private key ในรูปแบบ JSON โดย JWK มีลักษณะเหมือนกับ X.509 แต่ใช้ JSON แทน ASN.1 และ base64url แทน Base64

โดยทั่วไปแล้ว การใช้งาน JWT นั้นเป็นที่นิยมมากที่สุดเนื่องจากมีความง่ายในการใช้งานและมีระบบสิทธิ์แบบ stateless ซึ่งทำให้การตรวจสอบสิทธิ์ไม่ต้องอาศัยการ query ฐานข้อมูลหรือการเก็บ state แบบ session อย่างชัดเจน

สามารถทำได้โดยใช้ library ชื่อว่า jose ซึ่งเป็น library ที่รองรับการใช้งานของ JSON Web Token (JWT), JSON Web Encryption (JWE), และ JSON Web Signature (JWS) ใน Node.js ก่อนอื่นเราต้องติดตั้ง jose library โดยใช้คำสั่ง npm ดังนี้

npm install jose

ตัวอย่าง JWE (JSON Web Encryption) จากนั้น เราสามารถใช้ jose library เพื่อสร้าง JWE ได้โดยใช้ JWE.createEncrypt() method ดังนี้

const { JWE } = require('jose');

// สร้าง JWE object
const jwe = JWE.createEncrypt(
  // ข้อมูลที่จะเข้ารหัส
  Buffer.from('Hello, World!', 'utf8'),

  // กำหนด encryption algorithm ที่จะใช้
  { alg: 'A128KW', enc: 'A128CBC-HS256' },

  // กำหนด key ในการเข้ารหัส
  { key: '01234567890123456789012345678901' }
);

console.log(jwe);

ในตัวอย่างข้างต้น เราสร้าง JWE object โดยกำหนดข้อมูลที่จะเข้ารหัสเป็น "Hello, World!" และกำหนด encryption algorithm ในการเข้ารหัสเป็น A128KW และ A128CBC-HS256 และกำหนด key ในการเข้ารหัสเป็น "01234567890123456789012345678901" เมื่อรันโค้ดข้างต้นจะได้ JWE object ออกมาดังนี้

eyJhbGciOiAiQTEyOEtXIiwgImVuYyI6ICJBMjg1Q0JDLUhTMjU2In0.K-W2MAV7JLkzHzuV7diHO5DXkf66oO9N_fKtUDpNGvB8hCskrFzrAEB1lJLzEYrmQW0s9Xe2CfFyv_k8_q1WbA.nCw-YaemLs3A0ZJW.j6UxJ6U9B6yN3qOxtSYQxA

ทั้งนี้ JWE object ที่ได้รับค่าคือ encrypted data และสามารถถอดรหัสเป็นข้อมูลปกติได้โดยใช้ JWE.createDecrypt() method

ตัวอย่าง JWS (JSON Web Signature) จากนั้น เราสามารถใช้ jose library เพื่อสร้าง JWS ได้โดยใช้ JWS.createSign() method ดังนี้

const { JWS } = require('jose');

// สร้าง JWS object
const jws = JWS.createSign(
  // ข้อมูลที่จะเซ็นต์
  { hello: 'world' },

  // กำหนด algorithm ที่จะใช้ในการเซ็นต์
  { alg: 'HS256', typ: 'JWT' },

  // กำหนด key ในการเซ็นต์
  { key: '01234567890123456789012345678901' }
);

console.log(jws);

ในตัวอย่างข้างต้น เราสร้าง JWS object โดยกำหนดข้อมูลที่จะเซ็นต์เป็น { hello: 'world' } และกำหนด algorithm ในการเซ็นต์เป็น HS256 และกำหนด key ในการเซ็นต์เป็น "01234567890123456789012345678901" เมื่อรันโค้ดข้างต้นจะได้ JWS object ออกมาดังนี้

eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJIZWxsbyI6ICJ3b3JsZCJ9.nrx6P20oJ3B8hPfvKuaQxg9fT9kubjJcFvkWLgP4w4s

ทั้งนี้ JWS object ที่ได้รับค่าคือข้อมูลที่ถูกเซ็นต์และสามารถตรวจสอบได้โดยใช้ JWS.verify() method การตรวจสอบจะคืนค่า true หากข้อมูลถูกต้องและเซ็นต์ถูกต้อง และคืนค่า false หากข้อมูลไม่ถูกต้องหรือเซ็นต์

ตัวอย่าง JWK (JSON Web Key) จากนั้น เราสามารถใช้ jose library เพื่อสร้าง JWK ได้โดยใช้ JWK.generateSync() method ดังนี้

const { JWK } = require('jose');

// สร้าง JWK object
const jwk = JWK.generateSync('oct', 256);

console.log(jwk);

ในตัวอย่างข้างต้น เราสร้าง JWK object โดยกำหนด algorithm เป็น "oct" และกำหนดขนาด key เป็น 256 bits เมื่อรันโค้ดข้างต้นจะได้ JWK object ออกมาดังนี้

{
  kty: 'oct',
  kid: 'sG9Z9nTyq3ZZg6i-LS33pV52n84',
  use: 'sig',
  alg: 'HS256',
  k: '95kNzZeIwCxNlC0HdF0q3I8Wg5ynbKzhH_v0zIgHWV8'
}

ทั้งนี้ JWK object ที่ได้รับค่าจะประกอบไปด้วยค่าต่างๆ ซึ่งแทนคำนิยามต่างๆ ดังนี้

  • kty: ชนิดของ key ที่ใช้ (ในตัวอย่างคือ oct - หมายถึง symmetric key)
  • kid: รหัส ID ของ key
  • use: ใช้สำหรับตัวนำเข้าหรือใช้งาน (ในตัวอย่างคือ sig - หมายถึง signature)
  • alg: ชื่อของ algorithm ที่ใช้
  • k: ค่า key จริงๆ ซึ่งถูกเข้ารหัสแล้วถูกเก็บใน JWK object