OAuth สำหรับ MCP client ของคุณเอง
หากคุณกำลังสร้าง MCP client ของตัวเอง (CLI, SDK, ปลั๊กอิน IDE) หน้านี้จะอธิบายการ implement OAuth ของเรา: มาตรฐานที่เรารองรับ, endpoint, กฎของ redirect_uri และวิธี debug ข้อผิดพลาดที่พบบ่อย ผู้ใช้ Claude.ai และ ChatGPT ไม่จำเป็นต้องอ่านหน้านี้ — ใช้ Quickstart แทน
มาตรฐานที่เรา implement
mcp-telegram.com ปฏิบัติตามข้อกำหนด OAuth ที่ระบบนิเวศ MCP พึ่งพาอย่างครบถ้วน — ไม่มีส่วนขยายแบบ proprietary และไม่มี shared secret ที่ฝังอยู่ใน client
- RFC 6749 — OAuth 2.0 Authorization Framework — authorization code grant พื้นฐานพร้อม refresh token
- RFC 7591 — Dynamic Client Registration — client ใดก็ตามสามารถลงทะเบียนตัวเองที่ /oauth/register ได้โดยไม่ต้องประสานล่วงหน้า
- RFC 7636 — PKCE (Proof Key for Code Exchange) — challenge แบบ S256 จำเป็นสำหรับ public client
- RFC 8252 — OAuth 2.0 for Native Apps — redirect URI แบบ loopback IP พร้อมความยืดหยุ่นของ ephemeral port
- RFC 8414 — OAuth 2.0 Authorization Server Metadata — เอกสาร discovery ที่ /.well-known/oauth-authorization-server
- RFC 9728 — OAuth 2.0 Protected Resource Metadata — discovery ขอบเขตของ MCP resource
Endpoint
Authorization code flow ด้วย PKCE
Flow มาตรฐาน RFC 6749 §4.1 + RFC 7636 ไม่มีอะไรซับซ้อน — หากไลบรารี OAuth ของคุณรองรับ "authorization code + PKCE" ก็จะใช้งานได้ทันที
ลงทะเบียน client ของคุณ
POST /oauth/register ด้วย { redirect_uris: ["http://127.0.0.1:<port>/callback"], client_name: "ชื่อ-client-ของคุณ" } เซิร์ฟเวอร์จะคืน client_id + client_secret (secret เป็นทางเลือกสำหรับ public PKCE client แต่การได้รับมาก็ไม่เสียหาย)
สร้างคู่ PKCE
สร้าง code_verifier แบบสุ่มขนาด 43–128 ตัวอักษร จากนั้นคำนวณ code_challenge = BASE64URL(SHA256(code_verifier)) เก็บ verifier ไว้ใน local เพื่อใช้ในขั้นตอนที่ 4
เปิด /oauth/authorize ในเบราว์เซอร์
Redirect ผู้ใช้ไปที่ /oauth/authorize?response_type=code&client_id=...&redirect_uri=...&state=...&code_challenge=...&code_challenge_method=S256 เซิร์ฟเวอร์จะแสดง QR code; ผู้ใช้สแกนใน Telegram เพื่อยืนยันตัวตน
รับ authorization code
หลังจากสแกน QR แล้ว เซิร์ฟเวอร์จะ redirect ไปยัง redirect_uri ของคุณพร้อม ?code=...&state=.... ตรวจสอบว่าพารามิเตอร์ state ตรงกับที่คุณส่งไป
แลก code เป็น token
POST /oauth/token ด้วย grant_type=authorization_code, code, redirect_uri, code_verifier, client_id คุณจะได้รับ access_token (TTL 10 ปี — ดู Token Lifetime ด้านล่าง) และ refresh_token ใช้ access_token เป็น Authorization: Bearer ... ในการเรียกใช้ /mcp
กฎการ matching ของ redirect_uri
เราปฏิบัติตาม RFC 8252 §7.3 และ §8.4 อย่างเคร่งครัด อัลกอริทึม matching ขึ้นอยู่กับว่า URI ที่ลงทะเบียนเป็น literal IP แบบ loopback หรือไม่
Loopback (http://127.0.0.1 หรือ http://[::1])
หากคุณลงทะเบียน URI แบบ loopback ไว้ redirect_uri ขณะ authorize ต้องตรงกันทุกประการในส่วนของ scheme, host, path และ query — แต่ port สามารถต่างกันได้ RFC 8252 §7.3 กำหนดเช่นนี้เพราะ native client จะ bind กับ ephemeral port ที่ OS กำหนดให้ ซึ่งอาจเปลี่ยนแปลงไปในแต่ละครั้งที่รัน
- ที่ลงทะเบียน http://127.0.0.1:36201/callback ตรงกับ authorize-time http://127.0.0.1:50000/callback ✅
- ที่ลงทะเบียน http://127.0.0.1:36201/callback ไม่ตรงกับ http://127.0.0.1:50000/different-path — path ต้องตรงกันทุกประการ
- ที่ลงทะเบียน http://[::1]:36201/cb ไม่ตรงกับ http://127.0.0.1:36201/cb — loopback แบบ IPv4 และ IPv6 ถือเป็นตัวระบุที่แยกกัน
HTTPS (https://your-domain.example/...)
ต้องตรงกันทุก byte รวมถึง path, query และ port (RFC 6749 §3.1.2) ไม่มีความยืดหยุ่น
localhost (ไม่แนะนำ)
เราถือว่า http://localhost เป็น hostname ปกติ — ต้องตรงกันทุกประการ ไม่มีความยืดหยุ่นของ port RFC 8252 §8.3 แนะนำให้ใช้ literal IP (127.0.0.1 / [::1]) แทน localhost เพราะการ resolve DNS ขึ้นอยู่กับการ implement
PKCE เป็นข้อบังคับ
code_challenge_method=S256 ต้องระบุในทุก authorize request หากใช้ method แบบ plain จะถูกปฏิเสธ หากคุณไม่ใส่ code_challenge เลย การแลกเปลี่ยน /token จะล้มเหลวที่ขั้นตอนการตรวจสอบ code_verifier
อายุของ token
TTL ของ access_token ถูกตั้งให้ยาวโดยตั้งใจ (10 ปี) เพราะ MCP client บางตัวไม่สามารถเก็บ refresh_token ได้อย่างน่าเชื่อถือ แต่ refresh_token ก็ยังถูกออกให้และหมุนใหม่ทุกครั้งที่ refresh (RFC 6819 §5.2.2.3) ผู้ใช้สามารถเพิกถอน token ทั้งหมดได้ตลอดเวลาที่ /my/sessions หรือโดยการ logout ออกจาก Telegram และผู้ใช้ยังสามารถ POST ไปที่ /oauth/revoke (RFC 7009) อย่างชัดเจนเพื่อสิ้นสุด session ได้
ข้อผิดพลาดที่พบบ่อย
HTTP 400 "Invalid redirect_uri" ที่ /oauth/authorize
พารามิเตอร์ query redirect_uri ไม่ตรงกับ URI ใด ๆ ที่ลงทะเบียนไว้สำหรับ client_id นี้ สำหรับ loopback client: ตรวจสอบให้แน่ใจว่า scheme + host + path + query ตรงกันทุกประการ (มีแต่ port ที่ยืดหยุ่นได้) สำหรับ HTTPS client: ต้องเท่ากันทุก byte — ระวังเครื่องหมาย slash ท้าย URL และความแตกต่างของ URL-encoding
HTTP 400 "Unknown client"
client_id ไม่มีอยู่ในฐานข้อมูลของเรา อาจเป็นเพราะคุณข้ามขั้นตอน /oauth/register, response ของการลงทะเบียนสูญหายก่อนที่คุณจะบันทึก client_id หรือ client ถูกผู้ใช้เพิกถอนผ่าน /my/clients
Client แสดง "Needs Auth" ซ้ำ ๆ
หาก client ของคุณเก็บ access_token แต่ไม่เก็บ refresh_token คุณจะเจอปัญหานี้เมื่อ access_token หมดอายุ Access token ของเรามี TTL 10 ปีก็เพื่อบรรเทาปัญหานี้โดยเฉพาะ แต่หาก client ของคุณทำให้ token หมดอายุที่ฝั่ง client หลังช่วงเวลาที่สั้นกว่านี้ คุณจะต้องเก็บ refresh_token หรือเรียก /oauth/revoke แล้ว re-auth ตามที่ต้องการ
Client ที่ได้รับการทดสอบแล้ว
ยืนยันว่าใช้งานร่วมกับเซิร์ฟเวอร์ของเราได้ หากคุณสร้างอะไรใหม่ขึ้นมาแล้วใช้งานได้ ส่ง PR มาเพื่อเพิ่มในรายการนี้ได้เลย
- Claude.ai web — ผ่าน MCP connector ในตัว
- ChatGPT Apps — ผ่าน MCP connector ในตัว
- Hermes Agent — CLI MCP client แบบโอเพนซอร์ส (RFC 8252 loopback flow)
- Cursor MCP — ปลั๊กอิน IDE (RFC 8252 loopback flow)
- Client ใดก็ตามที่ปฏิบัติตาม RFC 6749 + RFC 7591 + RFC 7636 + RFC 8252 จะทำงานได้โดยไม่ต้องเปลี่ยนแปลงโค้ดในฝั่งของเรา
หลายบัญชี Telegram บนการเชื่อมต่อ OAuth เดียว
ตั้งแต่ v2.32.0 เป็นต้นมา การเชื่อมต่อ OAuth เดียวสามารถเก็บหลายตัวตน Telegram และสลับระหว่างกันได้ด้วยการเรียก tool เพียงครั้งเดียว — ไม่ต้องวนรอบ Disconnect/Connect ไม่ต้องลงทะเบียน client ใหม่
ดูบัญชีที่ผูกอยู่
เรียก telegram-accounts-list คุณจะเห็นบัญชี primary (ที่ผูกกับ OAuth) ของคุณถูกทำเครื่องหมายด้วย ⭐ หากกำลังใช้งานอยู่ พร้อมด้วยบัญชีรองทุกบัญชีที่คุณเพิ่มเข้ามา
ผูกบัญชีอื่นเพิ่ม
เรียก telegram-accounts-add พร้อม label ที่เลือกได้ (เช่น "testing") Tool จะคืน URL แบบใช้ครั้งเดียว (TTL 10 นาที) — เปิด URL นั้นบนอุปกรณ์ใดก็ได้และสแกน QR ด้วยบัญชี Telegram ที่คุณต้องการเพิ่ม
สลับบัญชีที่กำลังใช้งาน
เรียก telegram-accounts-switch ด้วย identifier=label, @username, account_id, หรือ 'primary' การเรียก tool telegram-* ครั้งถัดไปจะใช้บัญชีนั้นทันที ไม่ต้อง reconnect
ถอดบัญชีรองออก
เรียก telegram-accounts-remove identifier=… บนบัญชีรอง ตัวบัญชี Telegram เองจะ ไม่ ถูก log out — มีเพียงการผูกที่นี่เท่านั้นที่ถูกลบ ไม่สามารถลบบัญชี primary ด้วยวิธีนี้ได้ ให้ใช้ขั้นตอน Disconnect ของ client เพื่อออกจากระบบโดยสมบูรณ์
การเชื่อมต่อ OAuth แต่ละครั้งถูกแยกออกจากกัน: บัญชีที่คุณผูกผ่าน Hermes จะมองไม่เห็นจาก Claude.ai หรือ ChatGPT แม้ว่าจะเป็นตัวตน Telegram เดียวกันก็ตาม หากต้องการเชื่อมต่อบัญชีที่ต่างกันกับ MCP client ที่ต่างกัน ให้ลงทะเบียน client แต่ละตัวแยกกัน และใช้ telegram-accounts-add ภายใน session ของตัวเอง