温嘉琪的博客 / BUILDING SOMETHING FUN

三天修三个 P1 Bug:Supabase MCP OAuth 踩坑实录

三天修三个 P1 Bug:Supabase MCP OAuth 踩坑实录

日期: 2026-05-04 场景: 为 manitodo(习惯追踪 iOS App)搭建 MCP Server,让 Claude Code / Claude Desktop 可以通过 OAuth 认证读写用户数据。

背景

manitodo 用 Supabase 做后端(PostgreSQL + Auth + Edge Functions)。搭建了完整的 MCP Server + OAuth 2.1 + PKCE 认证流程。整个 OAuth 流程涉及 6 个 Edge Function。

三个 Bug

Bug 1: Stale JWT

oauth-token 用 refresh_token 重新获取 JWT,但 Supabase GoTrue 的 refresh token 是单次使用的。PKCE exchange 已经消费了它。修复:直接返回新鲜 JWT,不需要 refresh。

Bug 2: Lost Refresh Token

按 user_id 删 token 误杀其他 MCP client 的 token。修复:按 user_id + client_id 删除,加跨 client 校验。

Bug 3: Auto-Refresh

JWT 过期后 MCP tool 调用返回 401。修复:在 verifyUser 里加 auto-refresh 兜底,用存储的 refresh token 透明刷新。

总结

Bug 根因 修复 耗时
Stale JWT PKCE exchange 的 refresh token 是单次使用 直接返回新鲜 JWT ~4h
Lost refresh token 按 user_id 删 token 误杀其他 client 按 user_id + client_id 删除 ~3h
No auto-refresh JWT 过期后必须重新认证 verifyUser 自动用 refresh token 兜底 ~3h

三个 bug 的共同特点:OAuth 规范和 Supabase 实现之间的差异。OAuth 规范说 refresh token 可以反复用,但 Supabase GoTrue 的 refresh token 是单次的。理解这个差异是解决所有问题的关键。