fix: OAuth token introspection "context canceled" on concurrent MCP connections
Decouple fosite token introspection from the HTTP request context using context.WithoutCancel + 10s timeout. When claude.ai opens multiple concurrent MCP connections and one disconnects, the token validation for subsequent connections no longer fails with "context canceled". Fixes Bug #6 from #bugs-synapbus. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
18d8179061
commit
1dd332adf7
@@ -229,9 +229,13 @@ func RequiredAuthMiddlewareWithOAuth(service *AgentService, keyService *apikeys.
|
||||
|
||||
// resolveOAuthToken introspects an OAuth bearer token and extracts agent identity.
|
||||
func resolveOAuthToken(ctx context.Context, provider fosite.OAuth2Provider, token string, service *AgentService) (agentName string, ownerID string, ok bool) {
|
||||
// Use a fositeSession-compatible struct for introspection.
|
||||
// We import the type indirectly through the fosite interface.
|
||||
_, ar, err := provider.IntrospectToken(ctx, token, fosite.AccessToken, &oauthIntrospectSession{})
|
||||
// Decouple from the HTTP request context so token introspection completes
|
||||
// even if the client disconnects (fixes "context canceled" errors during
|
||||
// concurrent MCP connections from claude.ai).
|
||||
dbCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, ar, err := provider.IntrospectToken(dbCtx, token, fosite.AccessToken, &oauthIntrospectSession{})
|
||||
if err != nil {
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ory/fosite"
|
||||
)
|
||||
@@ -107,8 +108,11 @@ func RequireBearer(provider fosite.OAuth2Provider, userStore UserStore) func(htt
|
||||
token := parts[1]
|
||||
_ = token
|
||||
|
||||
// Use fosite introspection
|
||||
_, ar, err := provider.IntrospectToken(r.Context(), parts[1], fosite.AccessToken, new(fositeSession))
|
||||
// Use fosite introspection — decouple from HTTP request context so
|
||||
// token validation completes even if the client disconnects.
|
||||
dbCtx, cancel := context.WithTimeout(context.WithoutCancel(r.Context()), 10*time.Second)
|
||||
_, ar, err := provider.IntrospectToken(dbCtx, parts[1], fosite.AccessToken, new(fositeSession))
|
||||
cancel()
|
||||
if err != nil {
|
||||
slog.Debug("bearer token validation failed", "error", err)
|
||||
w.Header().Set("WWW-Authenticate", `Bearer error="invalid_token"`)
|
||||
|
||||
Reference in New Issue
Block a user