ข้ามไปยังเนื้อหา

ประเภทของ Token

Keycloak ออก token สามประเภทในขั้นตอน OIDC flow แต่ละประเภทมีวัตถุประสงค์ต่างกัน

ใช้อนุญาต API call — เป็น JWT อายุสั้นที่ API ของคุณตรวจสอบในทุก request Bearer token นี้คือสิ่งที่คุณส่งไปใน Authorization header เมื่อเรียก backend service

บอก client ว่าผู้ใช้คือใคร — ใช้ได้เฉพาะใน client เท่านั้น เช่น เพื่อแสดงชื่อผู้ใช้ใน UI ห้ามส่ง ID token ไปยัง backend API เด็ดขาด

อายุยาวกว่า access token — ใช้ขอ access token ใหม่โดยไม่ต้อง login ซ้ำ ส่งได้เฉพาะไปยัง Keycloak token endpoint เท่านั้น

ด้านล่างนี้คือ access token ที่ถูก decode แล้ว แสดง header, payload และ claim ต่างๆ ที่ Keycloak ใส่ไว้:

{
  "header": {
    "alg": "RS256",
    "typ": "JWT",
    "kid": "abc123"
  },
  "payload": {
    "exp": 1719878400,
    "iat": 1719874800,
    "jti": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "iss": "https://auth.example.com/realms/my-app",
    "aud": "account",
    "sub": "user-uuid-here",
    "typ": "Bearer",
    "azp": "my-app-frontend",
    "scope": "openid profile email roles",
    "realm_access": {
      "roles": ["offline_access", "uma_authorization", "user"]
    },
    "resource_access": {
      "my-app-frontend": {
        "roles": ["app-user"]
      }
    },
    "email_verified": true,
    "name": "Alice Example",
    "preferred_username": "alice",
    "email": "[email protected]"
  }
}
Claimความหมาย
subUnique ID ของผู้ใช้
issURL ของ realm ที่ออก token
audผู้รับ token ที่ตั้งใจ
expเวลาที่ token หมดอายุ (Unix timestamp)
azpClient ที่ขอ token
scopeScope ที่ถูก grant
realm_access.rolesRealm roles ของผู้ใช้
ตัวเลือกBenefitCost
ขอ ID token พร้อม access token (scope=openid)Client รู้ตัวตนผู้ใช้ทันทีโดยไม่ต้องเรียก userinfo endpoint เพิ่มResponse ใหญ่ขึ้น และมี token อีกใบที่ต้อง handle ให้ถูก — ห้ามส่งไป backend เด็ดขาด
ใช้ refresh token เพื่อขอ access token ใหม่ผู้ใช้ไม่ต้อง login ซ้ำ แม้ access token จะหมดอายุเร็วต้องเก็บ refresh token อย่างปลอดภัย เพราะมีอายุยาวกว่าและมีสิทธิ์สูงกว่า access token
Public client (SPA) ใช้ PKCE แทน client secretไม่ต้อง embed secret ไว้ในโค้ด frontend ที่ใครก็ inspect ได้ต้องพึ่ง redirect URI ที่ตั้งไว้อย่างเข้มงวด เพื่อป้องกัน authorization code ถูกขโมยระหว่าง redirect
  • ส่ง ID token ไปยัง backend API — ID token มีไว้ให้ client อ่านเพื่อแสดงข้อมูลผู้ใช้ใน UI เท่านั้น ไม่ได้ออกแบบมาให้ API ตรวจสอบ ให้ส่ง access token เป็น Bearer token เสมอ
  • เก็บ token (โดยเฉพาะ refresh token) ไว้ใน localStorage — JavaScript ใดๆ บนหน้าเว็บอ่าน localStorage ได้ ถ้าแอปมีช่องโหว่ XSS แม้เล็กน้อย token ก็หลุดไปกับผู้โจมตีทันที ควรเก็บใน memory หรือ httpOnly cookie แทน
  • ใช้ access token เป็นตัวระบุ session ระยะยาว — access token หมดอายุและเปลี่ยนค่าไปเรื่อยๆ ตาม lifespan อย่าผูก logic ที่ต้องคงอยู่นานกับค่า token ตรงๆ ให้ผูกกับ sub claim หรือ session ฝั่ง server แทน

💡 ตัวอย่างจากของจริง

Auth0 SPA SDK / Google Identity Services — เก็บ access token และ refresh token ไว้ใน memory ของ JavaScript runtime เท่านั้น (ไม่แตะ localStorage) แล้วให้ session กลับมาผ่าน silent refresh หรือ refresh token rotation เมื่อ reload หน้า

แอปธนาคารบนมือถือ — แยกการใช้งาน ID token ชัดเจนว่าใช้แสดงชื่อ/รูปโปรไฟล์ในแอปเท่านั้น ส่วนทุก call ไปยัง core banking API จะแนบเฉพาะ access token ผ่าน Authorization: Bearer header

REST API ของคุณตรวจสอบ token ใด?
claim `sub` บรรจุข้อมูลอะไร?
Refresh token ใช้ทำอะไร?
claim ใดแสดง realm-level roles ของผู้ใช้?