C# OAuth2 response: "StatusCode: 500, ReasonPhrase: 'Internal Server Error'"

As specified in the Authorization Code Flow tutorial at https://developer.blackbaud.com/skyapi/docs/authorization/auth-code-flow/tutorial, I make an authorization request by building out this URL with the correct parameters and then redirecting to that URL:

            var url = "https://oauth2.sky.blackbaud.com/authorization?" +
            "client_id=" + ConfigurationManager.AppSettings["AuthClientId"] +
            "&response_type=code" +
            "&redirect_uri=" + ConfigurationManager.AppSettings["AuthRedirectUri"] +
            "&state=" + ConfigurationManager.AppSettings["AuthState"];
            Response.Redirect(url);


That works, no problem. I'm redirected back to my application with a new "code" parameter. I then use that value to request an access token. Here is the function I use:

        void GetToken(string code)
        { 
            var client = new System.Net.Http.HttpClient();
            var queryString = HttpUtility.ParseQueryString(string.Empty);
            var auth = Base64Encode(ConfigurationManager.AppSettings["AuthClientId"]) + ":" + Base64Encode(ConfigurationManager.AppSettings["AuthClientSecret"]);
           
            // Request headers
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", auth);
            client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

            // Query string parameters
            queryString["grant_type"] = "authorization_code";
            queryString["code"] = code;
            queryString["redirect_uri"] = ConfigurationManager.AppSettings["AuthRedirectUri"];

            var uri = "https://oauth2.sky.blackbaud.com/token?" + queryString;

            var content = new FormUrlEncodedContent(new[]
            {
                new KeyValuePair<string, string>("","")
            });

            var response = client.PostAsync(new Uri(uri), content).Result;
            ConfigurationManager.AppSettings["AuthToken"] = response.ToString();
        }


The problem is, I get this response:

StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  X-Frame-Options: DENY
  Cache-Control: private
  Date: Wed, 12 Aug 2020 19:40:47 GMT
  Set-Cookie: visid_incap_855125=R7lFdEGuTI2H1S1GfQTzLL9FNF8AAAAAQUIPAAAAAACeEyJb6hFOtWK0u/dskR+5; expires=Thu, 12 Aug 2021 13:30:00 GMT; HttpOnly; path=/; Domain=.sky.blackbaud.com
  Set-Cookie: incap_ses_541_855125=dSJWTUF7C1XOXLcgzASCB79FNF8AAAAAcQzkcWKAMMyJUo0BaCXRNg==; path=/; Domain=.sky.blackbaud.com
  X-CDN: Incapsula
  X-Iinfo: 10-2995024-2995029 NNNN CT(58 140 0) RT(1597261247237 73) q(0 0 2 -1) r(2 3) U5
  Content-Length: 3420
  Content-Type: text/html; charset=utf-8
}


What am I doing wrong? Can anyone help?

Comments

  • Hey Bryce, double check the value of your authorization header - I believe the concatenation of your client ID and secret should be encoded, not each part separately:

    https://github.com/blackbaud/sky-api-tutorial-auth-code-c-sharp/blob/2a3e3455fb2205e974381b23219ad0bc2b243fea/Services/AuthenticationService.cs#L42
  • Michael,


    Thank you for your reply. I made the change to concatenate them before encoding, but that did not solve the problem (although it likely solved another problem I wasn't even aware of). I also changed the way I build the header slightly to match the example code.


    Before I had this:

               
                var auth = Base64Encode(ConfigurationManager.AppSettings["AuthClientId"]) + ":" + Base64Encode(ConfigurationManager.AppSettings["AuthClientSecret"]);
                client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", auth);
                client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));


    Now I have this:

                var auth = Base64Encode(ConfigurationManager.AppSettings["AuthClientId"].ToString() + ":" + ConfigurationManager.AppSettings["AuthClientSecret"].ToString());                 
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
                client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "Basic " + auth);


    Unfortunately, I'm still getting this response:

    StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
    {
      X-Frame-Options: DENY
      Cache-Control: private
      Date: Wed, 12 Aug 2020 21:09:17 GMT
      Set-Cookie: visid_incap_855125=UltPDFKDS4W/4vzxi+gUY3xaNF8AAAAAQUIPAAAAAACfnnSNvknZsr2rKWzNw139; expires=Thu, 12 Aug 2021 13:30:02 GMT; HttpOnly; path=/; Domain=.sky.blackbaud.com
      Set-Cookie: incap_ses_541_855125=G1P1efyqgniIb9EgzASCB3xaNF8AAAAAE38K8FvA6gce62hFhvq9Dw==; path=/; Domain=.sky.blackbaud.com
      X-CDN: Incapsula
      X-Iinfo: 5-5759767-5759775 NNNN CT(52 119 0) RT(1597266556587 42) q(0 0 2 -1) r(2 3) U5
      Content-Length: 3420
      Content-Type: text/html; charset=utf-8
    }


    Thanks for taking a crack at it though. I appreciate your help. Do you have any other ideas?


    Thanks again,


    Bryce

     
  • Chris Rodgers
    Chris Rodgers Blackbaud Employee
    Ninth Anniversary Kudos 3 Name Dropper Participant
    Hey Bryce,


    Thanks for pointing this out. While the 500 is in part due to how you are forming your request, we should be returning a better error message to help you resolve the issue. We'll look into that.


    As for fixing your /token request... Taking a cue from our Authorization Code sample (as Michael did), I altered how you are building your request body.


                var content = new FormUrlEncodedContent(new Dictionary<string, string>(){

                    { "code", code },

                    { "grant_type", "authorization_code" },

                    { "redirect_uri", ConfigurationManager.AppSettings["AuthRedirectUri"] }

                });


    The `grant_type`, `redirect_uri`, and `code` are to be included in the body of the request. We do not support these being passed as parameters of the query string. I obviously don't have access to the app setting values that your application has, so I can't verify that you could plug this in and you'd get a successful request, but this should avoid the 500.


    Let us know if that isn't the case. Thanks again.
  • Chris,


    That solved it! Thanks so much. I really appreciate it. Thanks to Michael also. You guys are great. So glad you guys are around to help.


    Thanks again,


    Bryce

Categories