การมอบหมายสิทธิ์ระหว่างบริการ (Service-to-service delegation)
ในสถาปัตยกรรม API บางแบบ บริการ backend จะได้รับคำขอจากผู้ใช้ที่ลงชื่อเข้าใช้แล้ว และจำเป็นต้องเรียกบริการ backend อื่น โดยยังคงรักษาเอกลักษณ์ของผู้ใช้เดิมไว้
ตัวอย่างเช่น:
User -> API A -> API B
API B จำเป็นต้องรู้สองสิ่ง:
- ผู้เรียกเป็นบริการที่เชื่อถือได้ เช่น API A
- การดำเนินการนี้ถูกกระทำในนามของผู้ใช้เดิม
ใช้ grant การแลกเปลี่ยนโทเค็นของ Logto เพื่อแลกเปลี่ยนโทเค็นการเข้าถึงของผู้ใช้เป็นโทเค็นการเข้าถึงใหม่ที่มีผู้รับ (audience) เป็นทรัพยากร API ปลายทาง วิธีนี้เป็นไปตามรูปแบบการแลกเปลี่ยนโทเค็นของ OAuth 2.0 และหลีกเลี่ยงการส่งต่อโทเค็นผู้ใช้เดิมไปยังบริการปลายทาง
เมื่อใดควรใช้ flow นี้
ใช้การมอบหมายสิทธิ์ระหว่างบริการเมื่อ:
- API A เป็นบริการ backend ที่สามารถยืนยันตัวตนกับ token endpoint ของ Logto ได้อย่างปลอดภัย
- API A ได้รับโทเค็นการเข้าถึงผู้ใช้ที่ออกโดย Logto
- API A จำเป็นต้องเรียก API B ในนามของผู้ใช้เดียวกัน
- API B ควรตรวจสอบโทเค็นการเข้าถึงหนึ่งรายการ โดยมีทรัพยากร API ของตนเองเป็นผู้รับ
อย่าใช้ flow นี้สำหรับการเข้าถึงแบบเครื่องต่อเครื่อง (machine-to-machine) ที่ไม่มีผู้ใช้ ในกรณีนั้นให้ใช้ client credentials flow สำหรับกรณีสนับสนุน, แอดมิน หรือเอเจนต์ที่ผู้ใช้หนึ่งสวมรอยเป็นผู้ใช้อีกคน ให้ใช้ การสวมรอยผู้ใช้ (User impersonation)
วิธีการทำงาน
โทเค็นการเข้าถึงที่แลกเปลี่ยนแล้วจะแทนผู้ใช้เดิม (sub) และผูกกับทรัพยากร API ปลายทาง (aud) API ปลายทางยังสามารถตรวจสอบการอ้างสิทธิ์ client_id เพื่อระบุแอปพลิเคชันที่เริ่มต้นการแลกเปลี่ยนได้
ข้อกำหนดเบื้องต้น
- สร้างทรัพยากร API สำหรับบริการที่เกี่ยวข้อง ดู ปกป้องทรัพยากร API ระดับโกลบอล
- กำหนดสิทธิ์ของ API B และมอบหมายให้ผู้ใช้ผ่านบทบาทหรือบทบาทขององค์กร
- ใช้แอปพลิเคชันฝั่งเซิร์ฟเวอร์สำหรับ API A เช่นแอป machine-to-machine หรือเว็บแอปแบบดั้งเดิม เพื่อให้สามารถยืนยันตัวตนด้วย app secret ได้อย่างปลอดภัย
- เปิดใช้งาน token exchange สำหรับแอปพลิเคชันของ API A
ก่อนใช้งาน token exchange grant คุณต้องเปิดใช้งานสำหรับแอปพลิเคชันของคุณก่อน:
- ไปที่ Console > Applications และเลือกแอปพลิเคชันของคุณ
- ในหน้าการตั้งค่าแอปพลิเคชัน ให้ค้นหาส่วน "Token exchange"
- เปิดสวิตช์ "Allow token exchange"
Token exchange ถูกปิดใช้งานโดยค่าเริ่มต้นเพื่อเหตุผลด้านความปลอดภัย หากคุณไม่เปิดใช้งาน คุณจะได้รับข้อผิดพลาดว่า "token exchange is not allowed for this application"
ขอรับโทเค็นการเข้าถึงสำหรับ API ปลายทาง
เมื่อ API A ต้องเรียก API B ให้ส่งคำขอแลกเปลี่ยนโทเค็นไปยัง token endpoint ของ Logto
สำหรับเว็บแอปแบบดั้งเดิมหรือแอป machine-to-machine ที่มี app secret ให้ใส่ข้อมูลรับรองใน header Authorization:
POST /oidc/token HTTP/1.1
Host: tenant.logto.app
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <base64(api-a-app-id:api-a-app-secret)>
grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=<user_access_token_received_by_api_a>
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&resource=https://api-b.example.com
&scope=read:orders
พารามิเตอร์:
grant_type: ใช้urn:ietf:params:oauth:grant-type:token-exchangesubject_token: โทเค็นการเข้าถึงผู้ใช้ที่ออกโดย Logto ซึ่ง API A ได้รับมาsubject_token_type: ใช้urn:ietf:params:oauth:token-type:access_tokenresource: ตัวบ่งชี้ทรัพยากร API ของ API Bscope: ขอบเขต downstream ที่ API A ขอสำหรับการเรียกแบบมอบหมายนี้ Logto จะออกเฉพาะขอบเขตที่ผู้ใช้เดิมมีสิทธิ์สำหรับทรัพยากรนี้ตามการตั้งค่า RBAC
Logto จะส่งคืนโทเค็นการเข้าถึงสำหรับ API B:
{
"access_token": "eyJhbGci...<truncated>",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read:orders"
}
เมื่อถอดรหัสแล้ว โทเค็นการเข้าถึงจะมีการอ้างสิทธิ์คล้ายกับ:
{
"sub": "user_id",
"client_id": "api_a_app_id",
"iss": "https://tenant.logto.app/oidc",
"aud": "https://api-b.example.com",
"scope": "read:orders",
"exp": 1760000000
}
จากนั้น API A จะเรียก API B พร้อมโทเค็นที่แลกเปลี่ยนแล้ว:
GET /orders HTTP/1.1
Host: api-b.example.com
Authorization: Bearer <exchanged_access_token>
ตรวจสอบโทเค็นใน API B
API B ควรตรวจสอบโทเค็นที่แลกเปลี่ยนแล้วเช่นเดียวกับโทเค็นการเข้าถึงทรัพยากร API ที่ออกโดย Logto:
- ตรวจสอบลายเซ็นด้วย JWKs ของ Logto
- ตรวจสอบผู้ออก (
iss) - ตรวจสอบว่าผู้รับ (
aud) ตรงกับตัวบ่งชี้ทรัพยากรของ API B - ตรวจสอบวันหมดอายุ (
exp) - ตรวจสอบขอบเขตที่ต้องการ
- ใช้
subเป็น user ID เดิม - ตรวจสอบ
client_idเพิ่มเติมหากอนุญาตเฉพาะ upstream service บางตัวให้เรียกแบบมอบหมาย
ดู ตรวจสอบโทเค็นการเข้าถึงใน API สำหรับแนวทางการใช้งาน