{"record":{"id":"662c77e0960ff2cc","repo":"siyuan-note/siyuan","slug":"oauth-callback-did-not-include-an-authorization-co","errorCode":null,"errorMessage":"OAuth callback did not include an authorization code","messagePattern":"OAuth callback did not include an authorization code","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/client/oauth.go","lineNumber":392,"sourceCode":"\n\tvar callback oauthCallbackResult\n\ttimer := time.NewTimer(oauthAuthorizationTimeout)\n\tdefer timer.Stop()\n\tselect {\n\tcase callback = <-flow.Result:\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase <-timer.C:\n\t\treturn fmt.Errorf(\"OAuth authorization timed out\")\n\t}\n\tif callback.Error != \"\" {\n\t\treturn fmt.Errorf(\"OAuth authorization failed: %s\", callback.Error)\n\t}\n\tif callback.State != state {\n\t\treturn fmt.Errorf(\"OAuth state mismatch\")\n\t}\n\tif callback.Code == \"\" {\n\t\treturn fmt.Errorf(\"OAuth callback did not include an authorization code\")\n\t}\n\n\texchangeCtx := context.WithValue(ctx, oauth2.HTTPClient, h.client)\n\ttoken, err := config.Exchange(exchangeCtx, callback.Code,\n\t\toauth2.VerifierOption(verifier),\n\t\toauth2.SetAuthURLParam(\"resource\", prm.Resource))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"exchange OAuth authorization code: %w\", err)\n\t}\n\tif token.TokenType != \"\" && !strings.EqualFold(token.TokenType, \"Bearer\") {\n\t\treturn fmt.Errorf(\"OAuth token endpoint returned unsupported token type %q\", token.TokenType)\n\t}\n\tcredential = registrationCredential\n\tcredential.TokenAuthMethod = authMethod\n\tcredential.AccessToken = token.AccessToken\n\tcredential.RefreshToken = token.RefreshToken\n\tcredential.TokenType = token.TokenType\n\tcredential.Expiry = token.Expiry","sourceCodeStart":374,"sourceCodeEnd":410,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/mcp/client/oauth.go#L374-L410","documentation":"The authorization-code flow requires the redirect to include a code query parameter. The callback handler passes the parsed result to Authorize; if the state matched but no code is present, there is nothing to exchange and the library aborts with this error.","triggerScenarios":"The browser callback reached the local endpoint with the correct state but an empty/missing code parameter — e.g. the IdP redirected without issuing a code, or the code was stripped in transit.","commonSituations":"IdP misconfiguration where the redirect is performed without the authorization code; a proxy or middleware dropping query parameters; user landing on a redirect URL variant that omits code (e.g. error path handled only via state).","solutions":["Retry the authorization; transient IdP redirects without a code usually succeed on a second attempt","Verify the authorization server issues response_type=code redirects correctly (test with another OAuth client)","Check any local proxy/AV software that may strip query strings from 127.0.0.1 callbacks","If it persists, inspect the callback URL the IdP produced (browser dev tools network log) and compare with the expected format"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := h.Authorize(ctx, true); err != nil {\n    if strings.Contains(err.Error(), \"did not include an authorization code\") {\n        // retry the flow; inspect the IdP redirect if it recurs\n    }\n}","preventionTips":["Verify the authorization server is standards-compliant (response_type=code redirect includes code)","Check the browser network log for the exact redirect URL when diagnosing","Rule out proxies/AV software stripping query parameters"],"tags":["oauth","mcp","authorization-code","callback"],"backgroundTag":"empty-required-field","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}