{"record":{"id":"3825bd6d369104b0","repo":"git-ecosystem/git-credential-manager","slug":"missing-oauth2constants-authorizationgrantrespon-3825bd","errorCode":null,"errorMessage":"Missing '{OAuth2Constants.AuthorizationGrantResponse.AuthorizationCodeParameter}' in response.","messagePattern":"Missing '(.+?)' in response\\.","errorType":"exception","errorClass":"Trace2OAuth2Exception","httpStatus":null,"severity":"error","filePath":"src/Core/Authentication/OAuth/OAuth2Client.cs","lineNumber":193,"sourceCode":"\r\n            // Check for errors serious enough we should terminate the flow, such as if the state value returned does\r\n            // not match the one we passed. This indicates a badly implemented Authorization Server, or worse, some\r\n            // form of failed MITM or replay attack.\r\n            if (!responseParams.TryGetValue(OAuth2Constants.AuthorizationGrantResponse.StateParameter, out string replyState))\r\n            {\r\n                throw new Trace2OAuth2Exception(_trace2,\r\n                    $\"Missing '{OAuth2Constants.AuthorizationGrantResponse.StateParameter}' in response.\");\r\n            }\r\n            if (!StringComparer.Ordinal.Equals(state, replyState))\r\n            {\r\n                throw new Trace2OAuth2Exception(_trace2,\r\n                    $\"Invalid '{OAuth2Constants.AuthorizationGrantResponse.StateParameter}' in response; does not match the request.\");\r\n            }\r\n\r\n            // We expect to have the auth code in the response otherwise terminate the flow (we failed authentication for some reason)\r\n            if (!responseParams.TryGetValue(OAuth2Constants.AuthorizationGrantResponse.AuthorizationCodeParameter, out string authCode))\r\n            {\r\n                throw new Trace2OAuth2Exception(_trace2,\r\n                    $\"Missing '{OAuth2Constants.AuthorizationGrantResponse.AuthorizationCodeParameter}' in response.\");\r\n            }\r\n\r\n            return new OAuth2AuthorizationCodeResult(authCode, redirectUri, codeVerifier);\r\n        }\r\n\r\n        public async Task<OAuth2DeviceCodeResult> GetDeviceCodeAsync(IEnumerable<string> scopes, CancellationToken ct)\r\n        {\r\n            var label = \"get device code\";\r\n            using IDisposable region = _trace2.CreateRegion(OAuth2Constants.Trace2Category, label);\r\n\r\n            if (_endpoints.DeviceAuthorizationEndpoint is null)\r\n            {\r\n                throw new Trace2InvalidOperationException(_trace2,\r\n                    \"No device authorization endpoint has been configured for this client.\");\r\n            }\r\n\r\n            string scopesStr = string.Join(\" \", scopes);\r","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/git-ecosystem/git-credential-manager/blob/e8ce762cd04b4100ae637b5fbf39ef9d0a96561e/src/Core/Authentication/OAuth/OAuth2Client.cs#L175-L211","documentation":"After validating state, GetAuthorizationCodeAsync requires the authorization 'code' parameter in the response. If the response parameters contain no authorization code the flow is terminated with this Trace2OAuth2Exception — the authorization server did not issue (or did not echo back) a code, so no token exchange is possible.","triggerScenarios":"Calling GetAuthorizationCodeAsync with a response URL/parameters that lack the 'code' parameter — e.g. the user denied consent at the IdP and the redirect carried only an error, or the response URL was truncated/mangled before parsing.","commonSituations":"User cancelled the consent screen or login failed and the IdP redirected back with an error instead of a code; a local redirect listener dropped query parameters; proxy or URL-encoding issues stripped the code.","solutions":["Check the response parameters for OAuth error fields (error, error_description) and surface them to the user before retrying.","Ensure the complete redirect URL (query string intact) is captured and passed to GetAuthorizationCodeAsync.","Prompt the user to retry the sign-in — a missing code often means the login/consent was not completed.","Verify the redirect URI is registered correctly with the authorization server so it actually issues a code to your client."],"exampleFix":"// before\nvar result = await client.GetAuthorizationCodeAsync(endpoints, clientId, redirectUri, scopes, state, verifier,\n    new Uri(\"https://client/callback?error=access_denied\")); // no code\n// after\nif (responseParams.ContainsKey(\"error\"))\n    throw new Exception($\"Auth failed: {responseParams[\"error\"]}\");\nvar result = await client.GetAuthorizationCodeAsync(endpoints, clientId, redirectUri, scopes, state, verifier, successCallbackUrl);","handlingStrategy":"try-catch","validationCode":"var responseParams = ParseResponseParams(callbackUrl);\nif (responseParams.TryGetValue(\"error\", out var err))\n    throw new InvalidOperationException($\"Authorization failed: {err}\");\nif (!responseParams.ContainsKey(\"code\"))\n    throw new InvalidOperationException(\"Authorization response is missing 'code'.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    result = await client.GetAuthorizationCodeAsync(endpoints, clientId, redirectUri, scopes, state, verifier, callbackUrl);\n}\ncatch (Trace2OAuth2Exception ex) when (ex.Message.Contains(\"AuthorizationCodeParameter\"))\n{\n    // no auth code: user likely denied consent or login failed; surface error and allow retry\n    return AuthFailure.NoAuthorizationCode;\n}","preventionTips":["Check for and display 'error'/'error_description' from the authorization response before treating it as a success response.","Ensure the redirect URI is correctly registered so the server issues a code.","Make sure the local listener captures the complete URL including query parameters.","Design the UX to let users retry after a cancelled consent screen."],"tags":["oauth2","authorization-code","missing-parameter","authentication"],"backgroundTag":"oauth-token-exchange-failed","analyzedSha":"e8ce762cd04b4100ae637b5fbf39ef9d0a96561e","analyzedAt":"2026-09-11T17:15:08.753Z","contentChangedAt":"2026-09-11T17:15:08.753Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}