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

Framework Adapters

การผสาน framework ทุกตัวเป็นไปตาม two-role model เดียวกัน:

  • Frontend / OIDC client: ไลบรารีใดก็ตามที่ implement Authorization Code + PKCE flow (keycloak-js สำหรับ browser, AppAuth สำหรับมือถือ, MSAL สำหรับ Microsoft stack เป็นต้น)
  • Backend / resource server: ไลบรารีใดก็ตามที่ตรวจสอบ Bearer JWT กับ JWKS endpoint ของ realm

ประเด็นสำคัญคือ backend ไม่ต้องการไลบรารีเฉพาะของ Keycloak — ต้องการเพียงไลบรารีที่ตรวจสอบ JWT กับ JWKS URL ได้ ที่เป็นฟีเจอร์มาตรฐานของ ecosystem OAuth2/OIDC ที่โตแล้วทุกตัว

เพิ่ม dependency Spring Security OAuth2 Resource Server ใน pom.xml:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

จากนั้นชี้ Spring ไปยัง issuer URI ของ realm Spring จะดึง JWKS โดยอัตโนมัติ ตรวจสอบ JWT ที่เข้ามา และเติมข้อมูลใน SecurityContextHolder ด้วย claims ที่ถอดรหัสแล้ว:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://localhost:8080/realms/my-app

Spring Security หา JWKS URL โดยอัตโนมัติจาก issuer URI โดยดึงข้อมูลจาก OIDC discovery document ไม่ต้องการโค้ดเฉพาะของ Keycloak

การตั้งค่า security แบบ minimal เพื่อป้องกัน endpoint ทั้งหมด:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));
return http.build();
}
}

express-oauth2-jwt-bearer คือ middleware ที่ Auth0 สร้างขึ้นภายใต้ MIT license ห่อหุ้ม jose สำหรับ Express ติดตั้ง:

Terminal window
npm install express-oauth2-jwt-bearer
import { auth } from 'express-oauth2-jwt-bearer';
import express from 'express';
const checkJwt = auth({
audience: 'my-app-backend',
issuerBaseURL: 'http://localhost:8080/realms/my-app',
});
const app = express();
app.get('/profile', checkJwt, (req, res) => {
res.json({ sub: req.auth?.payload.sub });
});

Keycloak เคยมี adapter เฉพาะสำหรับแต่ละ framework: keycloak-connect สำหรับ Node, Keycloak Spring Boot adapter และอื่น ๆ adapter เหล่านี้ ถูก deprecated ตั้งแต่ Keycloak 19 และอาจถูกลบออกในที่สุด project ใหม่ควรใช้:

Frameworkไลบรารีที่แนะนำ
Browser SPAkeycloak-js (official ยังคงได้รับการดูแล)
Spring Boot backendSpring Security OAuth2 Resource Server
Node/Express backendjose หรือ express-oauth2-jwt-bearer
Backend อื่น ๆJWT library ใดก็ได้ที่รองรับ JWKS
ตัวเลือกBenefitCost
ใช้ official Keycloak adapter (เช่น keycloak-js, keycloak-connect รุ่นเก่า)Setup เร็ว มี API เฉพาะทางที่ครอบคลุม use case ของ Keycloak โดยตรงผูกกับ Keycloak เจาะจง — adapter ฝั่ง backend อย่าง keycloak-connect ถูก deprecated แล้ว และย้าย identity provider ภายหลังทำได้ยาก
implement OIDC resource-server middleware มาตรฐานเอง (jose, express-oauth2-jwt-bearer, Spring Security oauth2ResourceServer)Portable ข้าม identity provider ใด ๆ ที่รองรับ OIDC/JWKS ได้รับการดูแลต่อเนื่องจาก community ที่กว้างกว่าต้องเข้าใจ OIDC spec เอง (issuer, audience, JWKS) แทนที่จะพึ่ง abstraction ของ adapter เฉพาะทาง
  • เชื่อ client-side auth state แทนการ verify ที่ backend — การเช็คว่า frontend มี token อยู่หรือ UI แสดงว่า “login แล้ว” ไม่ใช่ authentication ที่ backend ยอมรับได้ ทุก endpoint ที่ต้องการการป้องกันต้องผ่าน middleware ที่ verify JWT จริงเสมอ ไม่ใช่แค่เชื่อ header ที่ frontend ส่งมาว่า user login แล้ว
  • ยังใช้ Keycloak adapter รุ่นเก่าที่ถูก deprecated — keycloak-connect และ Keycloak Spring Boot adapter รุ่นเก่าไม่ได้รับฟีเจอร์ใหม่แล้ว โปรเจกต์ใหม่ควรย้ายไปใช้ OAuth2/OIDC resource server support มาตรฐานของ framework แทน
  • ผสม responsibility ระหว่าง authentication กับ authorization ใน middleware เดียว — การตรวจสอบว่า token ถูกต้อง (authentication) กับการเช็คว่า user มีสิทธิ์เข้าถึง resource นั้นหรือไม่ (authorization) ควรแยกเป็นคนละ layer หากผูกรวมกันในที่เดียวจะทดสอบและ debug ยากขึ้นมากเมื่อ role/policy เปลี่ยน

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

Spring Security oauth2ResourceServer — เป็นตัวอย่าง production-grade ของการใช้ middleware มาตรฐานแทน Keycloak adapter เฉพาะทาง เพียงกำหนด issuer-uri ก็ทำงานได้กับ identity provider ใด ๆ ที่รองรับ OIDC ไม่ใช่แค่ Keycloak

express-oauth2-jwt-bearer (Auth0) — แม้สร้างโดย Auth0 แต่ใช้ verify JWT ของ Keycloak ได้เช่นกัน เพราะยึดตาม OIDC/JWKS มาตรฐาน สะท้อนว่า resource-server middleware ที่ดีไม่ควรผูกกับ vendor ใด vendor หนึ่ง

property issuer-uri ของ Spring Security บอกอะไรกับ Spring Boot?
Spring Security ค้นหา JWKS URL จาก issuer-uri ได้อย่างไร?
เหตุใด Keycloak adapter เฉพาะ framework รุ่นเก่า (keycloak-connect เป็นต้น) จึงไม่แนะนำให้ใช้?
ฟีเจอร์ keycloak-js ตัวใดที่ยังคงเป็นตัวเลือกที่แนะนำสำหรับ browser SPA?