{"record":{"id":"2a42248f6d75d872","repo":"Tencent/WeKnora","slug":"mcp-service-s-does-not-use-oauth","errorCode":null,"errorMessage":"MCP service %s does not use OAuth","messagePattern":"MCP service (.+?) does not use OAuth","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/mcp/oauth_manager.go","lineNumber":90,"sourceCode":"\t}\n\th := transport.NewOAuthHandler(cfg)\n\th.SetBaseURL(*service.URL)\n\treturn h, nil\n}\n\n// StartAuthorization performs discovery + (one-time) dynamic client\n// registration, then returns the authorization URL and an opaque attempt ID.\n// redirectURI is the backend callback URL registered with the auth server;\n// frontendRedirect is where the callback bounces the browser when finished.\nfunc (m *OAuthManager) StartAuthorization(\n\tctx context.Context,\n\tservice *types.MCPService,\n\ttenantID uint64,\n\tprincipal types.Principal,\n\tredirectURI, frontendRedirect string,\n) (authorizationURL, attemptID string, err error) {\n\tif !service.AuthConfig.IsOAuth() {\n\t\treturn \"\", \"\", fmt.Errorf(\"MCP service %s does not use OAuth\", service.ID)\n\t}\n\tprincipal = principal.Normalize()\n\tif !principal.Valid() {\n\t\treturn \"\", \"\", fmt.Errorf(\"principal context is required to authorize OAuth MCP service %s\", service.ID)\n\t}\n\n\th, err := m.newHandler(ctx, service, tenantID, principal, redirectURI)\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\n\t// Register a client dynamically if we don't have one yet for this service.\n\texisting, _ := m.repo.GetClient(ctx, tenantID, service.ID)\n\tif existing == nil {\n\t\tif err := h.RegisterClient(ctx, clientRegistrationName); err != nil {\n\t\t\treturn \"\", \"\", fmt.Errorf(\"dynamic client registration failed: %w\", err)\n\t\t}\n\t\tclientID := h.GetClientID()","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/mcp/oauth_manager.go#L72-L108","documentation":"Returned by StartAuthorization when the service's AuthConfig is not OAuth-based. Only services configured with OAuth auth can run the authorization-code flow; attempting to start one for a service using another auth type (API key, none, etc.) is rejected with the service ID in the message.","triggerScenarios":"Calling AuthorizeURL or StartAuthorizationForService on a service whose AuthConfig.IsOAuth() returns false (e.g. auth type is api_key, bearer, or none).","commonSituations":"Frontend shows the 'Connect with OAuth' button for all services regardless of auth type; service auth type changed after deployment but cached client state still treats it as OAuth; copy/paste of OAuth setup code applied to an API-key service.","solutions":["Switch the service's AuthConfig to OAuth before calling StartAuthorization","Update the client to only render/start OAuth flows when the service auth type is oauth","Check whether a stale service record was fetched; reload the service before the call","Route API-key/bearer services through their own credential flow instead"],"exampleFix":"// before\nurl, id, err := manager.StartAuthorizationForService(ctx, svc, tenantID, principal, redirect, \"\")\n// after\nif !svc.AuthConfig.IsOAuth() {\n    return fmt.Errorf(\"service %s uses %s auth; use the non-OAuth flow\", svc.ID, svc.AuthConfig.Type)\n}\nurl, id, err := manager.StartAuthorizationForService(ctx, svc, tenantID, principal, redirect, \"\")","handlingStrategy":"validation","validationCode":"if !svc.AuthConfig.IsOAuth() {\n    return fmt.Errorf(\"service %s uses non-OAuth auth; choose the matching flow\", svc.ID)\n}","typeGuard":"func isOAuthService(svc *types.MCPService) bool { return svc != nil && svc.AuthConfig.IsOAuth() }","tryCatchPattern":"if !isOAuthService(svc) { return useAlternativeAuthFlow(svc) }\nif _, _, err := mgr.StartAuthorizationForService(ctx, svc, tenantID, principal, redirect, \"\"); err != nil {\n    if strings.Contains(err.Error(), \"does not use OAuth\") { return useAlternativeAuthFlow(svc) }\n    return err\n}","preventionTips":["Branch on svc.AuthConfig.IsOAuth() before offering any OAuth entry point","Keep the service's auth type in sync between DB, cache, and frontend metadata","Add UI gating so only OAuth services show OAuth connect buttons","Cover both OAuth and non-OAuth services in flow-selection tests"],"tags":["oauth","configuration","validation"],"backgroundTag":"oauth-flow-not-applicable","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}