ESI SSO Access Token Request (Receiving "400 Bad Request" Response)

I am attempting to write some crude C# code to get an ESI Access Token, but it’s returning a “400 Bad Request” message.
If anyone has thoughts on what I may be doing wrong, I’d appreciate the feedback.

Link to formatted code:
Code is also below.


using System;

using System.Net;

using System.Collections.Specialized;

using System.Web;

using System.Security.Cryptography;

using System.Diagnostics;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace GetWalletTransactions


    class Program


        static void Main(string[] args)


            // Based on "OAuth 2.0 for Mobile or Desktop Applications" from

            const string clientId = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // Dummy Client ID

            string authorizeUrl = @"";

            const string callback = @"";

            // Prepare Code Challenge

            Random random = new Random();

            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

            string codeChallenge = new String(Enumerable.Repeat(chars, 32).Select(s => s[random.Next(s.Length)]).ToArray());

            string origEncodedCodeChallenge = urlSafeBase64Encode(codeChallenge);

            string encodedCodeChallenge = ComputeSha256Hash(origEncodedCodeChallenge);

            encodedCodeChallenge = urlSafeBase64Encode(encodedCodeChallenge);

            // Prepare Request for Authorization Code

            string[] queryStringParameters =



                "redirect_uri=" + HttpUtility.UrlEncode(callback),

                "client_id=" + clientId,

                "scope=" + HttpUtility.UrlEncode("esi-wallet.read_character_wallet.v1"),

                "code_challenge=" + encodedCodeChallenge,


                "state=" + HttpUtility.UrlEncode("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") // Dummy Secret


            string queryParameters = String.Join("&", queryStringParameters);

            authorizeUrl += "?" + queryParameters;

            // Setup Listener for Authorization Code Response

            HttpListener listener = new HttpListener();




            // Send Request for Authorization Code

            Process.Start("chrome.exe", authorizeUrl);


            HttpListenerContext context = listener.GetContext();

            HttpListenerRequest request = context.Request;

            Uri uri = new Uri(request.Url.AbsoluteUri);

            NameValueCollection parameters = HttpUtility.ParseQueryString(uri.Query);

            Console.WriteLine("Returned string: {0}", uri.Query);

            string authCode = parameters["code"];

            Console.WriteLine("Auth code: {0}", authCode);

            // Prepare Request for Access Token

            const string authBaseUrl = "";

            NameValueCollection post_params = new NameValueCollection();

            post_params.Add("grant_type", "authorization_code");

            post_params.Add("code", authCode);

            post_params.Add("client_id", clientId);

            post_params.Add("code_verifier", origEncodedCodeChallenge);


            using (WebClient client = new WebClient())


                client.Encoding = Encoding.UTF8;


                client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");

                client.Headers.Add("Host", "");


                Console.WriteLine($"Authorization URL: {authBaseUrl}");



                    byte[] response = client.UploadValues(authBaseUrl, "POST", post_params);



                catch (Exception ex)







        public static string urlSafeBase64Encode(string input)


            byte[] byteArray = Encoding.UTF8.GetBytes(input);

            string working = Convert.ToBase64String(byteArray).TrimEnd('=');

            return working;


        // This function was taken from:

        public static string ComputeSha256Hash(string rawData)


            using (SHA256 sha256Hash = SHA256.Create())


                // ComputeHash - returns byte array

                byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));

                // Convert byte array to a string

                StringBuilder builder = new StringBuilder();

                for (int i = 0; i < bytes.Length; i++)




                return builder.ToString();





Whats the full error?

Right, but what’s in the response body? I.e. the information that tells you what’s actually wrong.

Guess that I had it in my head that there wouldn’t be a Response for a Bad Request.

The Response was:
{“error”:“invalid_grant”,“error_description”:“Failed code verification challenge.”}

Looks like it’s saying that the problem is with the way that I’m encoding the Code Challenge.
I had thought that there was a good chance that that’s where the problem is, but I guess I’m not familiar with it enough for it jump out at me.

I’m not super familiar with this SSO method, nor C#. However if I had to guess, my vote would be your 32 byte string isn’t correct.

const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; doesn’t seem like it should be required for you to just generate 32 random bytes.

Try something like The other issue might have been your Base64 encoding not being URL safe.

I appreciate the feedback. I will have a look at it.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.