หลากหลายหน้าตาของ OAuth 2.0 Token Exchange
(auth0.com)- กลไกแบบ อิงมาตรฐาน สำหรับแปลงโทเคนความปลอดภัยหนึ่งเป็นอีกโทเคนหนึ่ง โดยกำหนดไว้ใน RFC 8693 ซึ่งเป็นสเปกส่วนขยายของ OAuth 2.0
- เปลี่ยน authorization server ให้ทำหน้าที่เป็น Security Token Service (STS) เพื่อตรวจสอบโทเคนที่ไคลเอนต์ส่งมา และออกโทเคนใหม่ให้เหมาะกับคอนเท็กซ์, เป้าหมาย (audience) และวัตถุประสงค์ที่ต่างออกไป
- รูปแบบการทำงานหลักแบ่งได้เป็น 2 โหมดใหญ่คือ Impersonation และ Delegation
- กรณีใช้งานที่แตกต่างกัน เช่น การ impersonation ของผู้ดูแลระบบ, การแปลงโปรโตคอล, การเชื่อมต่อการเรียกใช้บริการเป็นทอด ๆ และ federation ID ล้วนมี trade-off และผลกระทบด้านความปลอดภัยของตัวเอง
- เมื่อ AI agent แพร่หลายมากขึ้น งานที่ต้องข้ามหลายบริการและหลายผู้ให้บริการจึงกลายเป็น delegation chain โดยธรรมชาติ ทำให้ token exchange มีความสำคัญยิ่งขึ้น
Token Exchange คืออะไร
- ไคลเอนต์ส่ง
subject_token(โทเคนที่แสดงถึงผู้ใช้/เอนทิตีที่เป็นเจ้าของคำขอ) และอาจส่งactor_token(ฝ่ายที่ทำการแลกเปลี่ยน) มาด้วย จากนั้นจะได้รับโทเคนใหม่ที่เหมาะกับคอนเท็กซ์ปลายทาง - วิธีอย่างการส่งต่อโทเคนเดิมไปตรง ๆ หรือสร้างโทเคนใหม่ขึ้นมาเองอาจดูเข้าใจง่าย แต่ทั้งสองแบบก่อให้เกิดปัญหาร้ายแรง จึงเกิดสเปกนี้ขึ้นมาเพื่อแก้ไข
-
โหมดการทำงานพื้นฐาน 2 แบบ
- Impersonation: ฝ่ายที่ร้องขอจะได้รับโทเคนที่แยกไม่ออกจากตัวเจ้าของตัวจริง บริการ downstream จึงไม่สามารถแยกได้ว่าเป็นผู้ใช้จริงหรือเป็นผู้ที่กำลังสวมสิทธิ์
- Delegation: รักษาอัตลักษณ์ของทั้งสองฝ่ายไว้ โดยบริการ downstream จะรับรู้ทั้งผู้ใช้และผู้ปฏิบัติการแทน ผ่าน
act(actor) claim ที่บรรจุในโทเคนใหม่ - impersonation ทรงพลังแต่ไม่โปร่งใส ส่วน delegation มีข้อจำกัดมากกว่าแต่ตรวจสอบย้อนหลัง (audit) ได้ — การเลือกนี้เป็นตัวกำหนดทั้ง security posture และความสามารถในการติดตาม
การ impersonation ของผู้ดูแลระบบ (Administrative Impersonation)
- เช่นกรณีที่ต้องวินิจฉัยปัญหาว่าหน้าแดชบอร์ดของลูกค้าแสดงข้อมูลผิดพลาด โดยวิศวกรฝ่ายซัพพอร์ตจำเป็นต้องเห็นหน้าจอแบบเดียวกับลูกค้า ภายใต้สิทธิ์และการเข้าถึงข้อมูลแบบเดียวกัน
- ผู้ดูแลระบบแลกโทเคนของตนเป็นโทเคนที่แสดงตัวตนของลูกค้า โทเคนผลลัพธ์จะมี
subclaim, scope และ audience ของลูกค้า ดังนั้นจากมุมมองของแอปพลิเคชัน คำขอนี้จะถูกมองว่าเป็นคำขอจากลูกค้าเอง - ในกรณีนี้จะใช้แค่
subject_token(ผู้ใช้ที่จะถูกสวมสิทธิ์) โดยไม่ส่งactor_token— เพราะเป้าหมายคือการทำ impersonation แบบสมบูรณ์ -
ปัญหาการสูญเสีย audit trail
- เนื่องจากเป็น impersonation จริง ๆ จึงทำให้ audit trail ว่าใครเป็นผู้กระทำการจริงหายไป
- เพราะฉะนั้นต้องมีระบบบันทึก log ภายนอกควบคู่กันเสมอ เพื่อบันทึกว่า ใคร, เมื่อไร, และด้วยเหตุผลอะไร ที่เริ่มต้นการแลกเปลี่ยน มิฉะนั้นการแก้ปัญหาอาจกลายเป็นช่องโหว่ด้านความปลอดภัยได้
การจัดการการแปลงโปรโตคอล (Managing Protocol Transition)
- ในสภาพแวดล้อมที่ยังมีระบบ legacy และโปรโตคอลรุ่นเก่าคงอยู่ อาจมีสถานการณ์ที่ต้องย้ายจาก SAML authentication ไปเป็น OpenID Connect (OIDC) พร้อมกับเดินระบบทั้งสองฝั่งไปพร้อมกัน
- บริการที่ยืนยันตัวตนผู้ใช้ด้วย SAML สามารถแลก SAML assertion เป็น OAuth 2.0 access token โดย authorization server จะตรวจสอบ SAML artifact ที่เข้ามา แล้วออก access token มาตรฐานที่บริการ downstream เข้าใจได้
-
พารามิเตอร์ subject_token_type
- ใช้ระบุรูปแบบของโทเคนที่รับเข้ามา โดย RFC 8693 กำหนดตัวระบุ token type หลายแบบไว้
- SAML 2.0 assertion:
urn:ietf:params:oauth:token-type:saml2 - JWT token:
urn:ietf:params:oauth:token-type:jwt
- SAML 2.0 assertion:
- ทำให้ authorization server รับโทเคนจากโปรโตคอลคนละตระกูลกัน แล้วปรับให้เป็นรูปแบบเดียวกันสำหรับบริการสมัยใหม่ได้
- ใช้ระบุรูปแบบของโทเคนที่รับเข้ามา โดย RFC 8693 กำหนดตัวระบุ token type หลายแบบไว้
- นี่เป็นแพตเทิร์นที่มักพบเมื่อเกิดการควบรวมกิจการขององค์กรที่มี ID stack ต่างกัน และยังต้องทำงานร่วมกันได้ก่อนจะย้ายระบบเสร็จสมบูรณ์ ผู้ใช้ยังยืนยันตัวตนด้วยวิธีเดิม ส่วนระบบจะแปลง credential ให้อยู่ในรูปแบบที่บริการปลายทางต้องการ
การเชื่อมต่อการเรียกใช้บริการเป็นทอด ๆ (Chaining Service Calls)
- ในสถาปัตยกรรมแบบ microservices เมื่อ Service A ประมวลผลคำขอของผู้ใช้แล้วต้องเรียก Service B ในนามของผู้ใช้ และ Service B ก็ต้องเรียก Service C ต่อ คำถามสำคัญคือ แต่ละบริการควรใช้ credential แบบไหนในการเรียกครั้งถัดไป
-
ตัวเลือก 1 — ใช้ credential ของบริการเอง
- Service A ไม่สนใจ user context แล้วเรียก Service B ด้วย client credential ของตัวเอง เหมาะกับการเรียกระหว่างบริการที่ไม่ต้องใช้ user context เช่น งานประมวลผลแบบ batch, การตรวจสอบสถานะระบบ หรือการซิงก์ข้อมูล
- แต่ถ้ามีผู้ใช้เกี่ยวข้อง Service B จะบังคับใช้ authorization ระดับผู้ใช้ไม่ได้ — เพราะไม่รู้ว่าผู้ใช้คนไหนเป็นผู้ร้องขอ จึงตรวจสอบสิทธิ์เข้าถึงไม่ได้ ส่งผลให้ security context สูญหาย
-
ตัวเลือก 2 — บริการ impersonation ผู้ใช้
- Service A ส่งต่อโทเคนต้นฉบับของผู้ใช้ไปยัง Service B โดยตรง หรือแลกเป็นโทเคนที่แยกไม่ออกจากผู้ใช้ ทำให้ Service B มองว่าเป็นคำขอที่มาจากผู้ใช้ และใช้ authorization ระดับผู้ใช้ได้
- แต่ Service B จะแยกไม่ออกว่าเป็นการกระทำโดยตรงของผู้ใช้หรือเป็นการกระทำแทนโดย Service A หาก Service A ถูกเจาะ ก็สามารถเรียกทุกอย่างภายใต้สิทธิ์ของผู้ใช้ได้ และไม่สามารถใช้ระดับความเชื่อถือที่ต่างกันกับคำขอตรงและคำขอผ่านพร็อกซีได้ — รักษา user context ไว้ได้ แต่สูญเสีย service context
-
ตัวเลือก 3 — กระทำการแทนผู้ใช้ (Delegation)
- Service A แลกโทเคนของผู้ใช้เป็น โทเคนใหม่ที่ระบุทั้งผู้ใช้ (subject) และ Service A (actor) โดย
actclaim ในโทเคนผลลัพธ์จะสื่อว่า "คำขอนี้เกี่ยวกับผู้ใช้ X และดำเนินการโดย Service A" - นี่คือโมเดล delegation ที่ RFC 8693 ถูกออกแบบมาเพื่อรองรับเป็นหลัก ทำให้ Service B ตัดสินใจเรื่อง authorization ได้ละเอียดขึ้น — หาก Service A พยายามทำสิ่งที่ผู้ใช้ไม่ได้อนุญาต คำขอจะล้มเหลว
actclaim สามารถซ้อนกันได้ (nestable) ดังนั้นหาก Service B เรียก Service C ต่อ delegation chain ก็จะขยายต่อไปและสร้าง audit trail แบบสมบูรณ์- trade-off คือความซับซ้อน — ทุก hop ต้องมีการแลกโทเคน ทำให้ latency เพิ่มขึ้น และแต่ละบริการต้องลงทะเบียนเป็นไคลเอนต์กับ authorization server แต่สำหรับสถาปัตยกรรมที่ให้ความสำคัญกับความปลอดภัยและการตรวจสอบ นี่คือทางเลือกที่มีหลักการมากกว่า
- Service A แลกโทเคนของผู้ใช้เป็น โทเคนใหม่ที่ระบุทั้งผู้ใช้ (subject) และ Service A (actor) โดย
Token Exchange กับ federation ID
- เมื่อบริการต้องข้าม security domain (เช่น บริการที่มาจากองค์กรภายนอก) สถานการณ์แบบ chain จะซับซ้อนขึ้นมาก
- Service A มีโทเคนสำหรับเข้าถึง Service B ในนามของผู้ใช้ภายใน security domain ของ MyCompany
- Service B ต้องเรียก Service C ที่ถูกป้องกันอยู่ในโดเมนของ External Provider และต้องมี access token สำหรับสิ่งนั้น
- โทเคนที่ออกโดย authorization server ของ MyCompany ไม่มีความหมายในโดเมนของ External Provider — โทเคนที่ออกโดย authorization server หนึ่งจะไม่ได้ถูกรับโดยอัตโนมัติจากอีกฝั่ง เพราะ trust boundary มีไว้เพื่อจำกัด blast radius
-
ข้อจำกัดของการตั้งค่า federation
- authorization server ของ External Provider ต้องถูกตั้งค่าให้ยอมรับโทเคนจากโดเมน MyCompany เป็น subject token ที่ถูกต้อง ซึ่งต้องอาศัยความเชื่อใจกันล่วงหน้าผ่านการแลกเปลี่ยน metadata, การตรวจสอบ certificate, หรือการตั้งค่าโดยตรง รวมถึงการแมปอัตลักษณ์ข้ามโดเมน
- ยิ่งมีหลายโดเมนมากขึ้น (enterprise integration, SaaS ecosystem, multi-cloud) เมทริกซ์ของความสัมพันธ์แบบคู่ต่อคู่ก็จะจัดการไม่ได้ในที่สุด
-
Cross App Access และ Identity Chaining
- เพื่อลดปัญหาการขยายตัวนี้จึงมี Cross App Access (XAA) ซึ่งอิมพลีเมนต์ Identity Assertion JWT Authorization Grant และนำ enterprise IdP เข้ามาเป็นตัวกลางในการแลกเปลี่ยนข้ามโดเมน
- แนวคิดคือ IdP รู้ความสัมพันธ์ของทั้งสองแอปและผู้ใช้อยู่แล้ว ดังนั้นแทนที่ทุกคู่โดเมนจะต้องสร้างความเชื่อใจกันโดยตรง ก็รวมการตัดสินใจเรื่องการเข้าถึงไว้ที่ IdP
-
ผู้เกี่ยวข้อง 4 ฝ่ายใน flow ของ XAA
- Requesting App: แอปพลิเคชันในโดเมน MyCompany (หรือ AI agent) ที่ต้องเข้าถึงทรัพยากรในอีกโดเมนหนึ่ง
- Enterprise IdP: ผู้ให้บริการ ID ในโดเมน MyCompany ที่ยืนยันตัวตนพนักงานและจัดการนโยบาย cross-app
- Resource App: แอปพลิเคชันที่เป็นเจ้าของ API ที่ได้รับการป้องกันในโดเมนของ External Provider
- Resource Authorization Server: authorization server ที่ออก access token สำหรับ API ที่ได้รับการป้องกันของ Resource App
-
ลำดับขั้นของ XAA
- พนักงานล็อกอินเข้า Requesting App ผ่าน SSO และได้รับ ID token จาก IdP
- Requesting App ส่ง ID token นั้นกลับไปยัง IdP เพื่อขอ identity assertion ข้ามโดเมน (ID-JAG, JWT พิเศษที่จำกัด scope สำหรับการเข้าถึงข้ามแอป)
- IdP ตรวจสอบนโยบาย XAA — พิจารณาว่าผู้ใช้รายนี้ได้รับอนุญาตให้เข้าถึง Resource App ในนามนี้หรือไม่ ถ้าอนุญาตจึงส่ง ID-JAG กลับมา
- Requesting App นำ ID-JAG ไปแสดงต่อ authorization server ของ Resource App
- authorization server ของ Resource App ตรวจสอบ ID-JAG ด้วย public key ของ IdP ผ่าน OIDC discovery แล้วออก access token
- Requesting App ใช้ access token นั้นเรียก API ของ Resource App
- ความแตกต่างสำคัญจาก token exchange แบบทั่วไปคือในขั้นตอนที่ 3 IdP จะเป็นผู้บังคับใช้นโยบายการตัดสินใจ — ผู้ดูแลระบบสามารถกำหนดอย่างชัดเจนได้ว่าแอปใดเข้าถึงทรัพยากรใดได้บ้าง ทำให้ฝ่าย IT มีทั้ง visibility และ control โดยผู้ใช้ไม่ต้องเจอ flow การขอ consent ซ้ำ ๆ
- Identity Chaining คือแพตเทิร์นที่กว้างกว่า ซึ่ง identity assertion ของผู้ใช้จะไหลจากการยืนยันตัวตนครั้งแรกไปยังทุกบริการ downstream ในรูปแบบมาตรฐาน และ XAA ก็เป็นหนึ่งในการอิมพลีเมนต์แนวคิดนี้บน primitive ของ OAuth
- โดยเฉพาะอย่างยิ่งมีความเกี่ยวข้องกับสถานการณ์ของ AI agent ที่คำขอเดียวจากผู้ใช้อาจทำให้เกิดการเรียกใช้บริการจากผู้ให้บริการภายนอกหลายราย
Token Exchange กับ Auth0
- Auth0 อิมพลีเมนต์ token exchange ผ่านกลไกหลายแบบ เพื่อรองรับจุดต่าง ๆ บนสเปกตรัมที่กล่าวถึงข้างต้น
-
Custom Token Exchange
- อิมพลีเมนต์ RFC 8693 บน endpoint
/oauth/tokenของ Auth0 และให้ผู้พัฒนาควบคุม logic การตรวจสอบได้เต็มที่ - กำหนด Token Exchange Profile ที่แมป
subject_token_typeURI ไปยัง custom Action เมื่อมีคำขอเข้ามา Auth0 จะเรียกโค้ด Action เพื่อตรวจสอบโทเคน, บังคับใช้กฎ authorization และเชื่อมโยงผู้ใช้ภายใน tenant - เนื่องจาก Auth0 มอง
subject_tokenเป็นเพียง opaque string จึงรับได้แทบทุกรูปแบบ ไม่ว่าจะเป็น JWT จาก IdP อื่น, SAML assertion แบบ legacy หรือโทเคนเฉพาะของ partner API — จึงเหมาะเป็นกลไกสำหรับการแปลงโปรโตคอลและ federation แบบกำหนดเอง
- อิมพลีเมนต์ RFC 8693 บน endpoint
-
Token Vault
- ออกแบบมาสำหรับสถานการณ์ AI agent ที่ต้องเรียก third-party API ในนามผู้ใช้ข้ามหลายผู้ให้บริการ โดยเพิ่มการจัดเก็บอย่างปลอดภัยและการจัดการวงจรชีวิตอัตโนมัติเข้ามาควบคู่กับ token exchange
- หลังผู้ใช้ยืนยันตัวตนแล้วก็เชื่อมบัญชีต่าง ๆ ได้ (Google, GitHub, Slack, Microsoft ฯลฯ) จากนั้น Token Vault จะเก็บโทเคนไว้อย่างปลอดภัยและจัดการ refresh ให้อัตโนมัติ ส่วน AI agent จะใช้ token exchange เพื่อดึง access token ที่ยังใช้งานได้จาก vault
- โทเคนผลลัพธ์จะมี
actclaim ที่ระบุ AI agent ทำให้สร้าง audit trail ได้ว่าเอเจนต์ใดเข้าถึงบริการใดแทนผู้ใช้คนใด ซึ่งเป็นสิ่งจำเป็นต่อ enterprise compliance ที่ต้องรู้ว่าอะไรเป็นตัวกระตุ้นให้เกิดการทำงานอัตโนมัติ
-
On-Behalf-Of (OBO) Token Exchange
- อิมพลีเมนต์แพตเทิร์น delegation โดยตรงสำหรับสถานการณ์ service chain โดยบริการชั้นกลางจะแลกโทเคนผู้ใช้ที่รับเข้ามาเป็นโทเคนใหม่ที่มี scope สำหรับ downstream API และเพิ่มตัวเองเข้า delegation chain ผ่าน
actclaim - รองรับการซ้อน delegation chain ได้สูงสุด 5 ระดับ โดยแต่ละโทเคนจะมี claim คือ
sub(คงอัตลักษณ์ผู้ใช้),aud(กำหนดขอบเขตบริการเป้าหมาย) และactแบบซ้อน (บันทึก chain ของบริการที่เกี่ยวข้อง)
- อิมพลีเมนต์แพตเทิร์น delegation โดยตรงสำหรับสถานการณ์ service chain โดยบริการชั้นกลางจะแลกโทเคนผู้ใช้ที่รับเข้ามาเป็นโทเคนใหม่ที่มี scope สำหรับ downstream API และเพิ่มตัวเองเข้า delegation chain ผ่าน
-
Cross App Access (XAA)
- สำหรับสถานการณ์ federation ID ที่แอปต้นทางต้องเรียก resource API ที่ถูกป้องกันโดย authorization server อีกตัวหนึ่ง โดยอิมพลีเมนต์ส่วนขยาย OAuth แบบ Identity Assertion Authorization Grant
- Auth0 ทำหน้าที่เป็น Resource Authorization Server — Requesting App ส่ง ID token ของผู้ใช้ไปยัง IdP เช่น Okta เพื่อรับ ID-JAG และ IdP จะออก assertion ให้ก็ต่อเมื่อผู้ดูแลระบบได้ตั้งค่าการเชื่อมต่อข้ามแอปไว้ใน Admin Console แล้วเท่านั้น
- เมื่อ Requesting App นำ ID-JAG มาแสดงต่อ Auth0 ระบบจะตรวจสอบผ่าน OIDC discovery แล้วออก access token ที่มี scope ตามต้องการ ช่วยให้ฝ่าย IT มองเห็นการแชร์ข้อมูลข้ามแอปได้แบบรวมศูนย์
การเลือกแนวทางที่เหมาะสม
- token exchange ไม่ใช่โซลูชันเดียวจบ แต่เป็นชุดของแพตเทิร์นที่ต้องเลือกตามคอนเท็กซ์ที่ต้องการรักษาไว้และ trust boundary ที่ต้องข้าม
- การ impersonation ของผู้ดูแลระบบ: เมื่อจำเป็นต้องเห็นหน้าจอแบบเดียวกับที่ผู้ใช้เห็นเพื่อแก้ปัญหา
- การแปลงโปรโตคอล: เมื่อต้องมีสะพานเชื่อมระหว่างระบบ ID แบบ legacy และสมัยใหม่ในช่วง migration
- Delegation: เมื่อ service chain ต้องการ user context พร้อมความสามารถในการ audit อย่างครบถ้วน
- Cross App Access / Identity Chaining: เมื่อ delegation ต้องข้ามหลาย security domain
- Token Vault: เมื่อ AI agent ต้องการการเข้าถึง third-party API ในนามผู้ใช้แบบมีการจัดการ
- AI agent ที่ทำ orchestration งานแทนผู้ใช้ข้ามหลายบริการและหลายผู้ให้บริการนั้น โดยธรรมชาติคือ delegation chain และกลไก token exchange ก็คือรากฐานด้านความปลอดภัยที่ทำให้ chain นี้ตรวจสอบย้อนหลังได้, ได้รับอนุญาตอย่างถูกต้อง และถูกจำกัดขอบเขตตามเจตนาของผู้ใช้
ยังไม่มีความคิดเห็น