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: https://pastebin.com/72qjGsbA
Code is also below.
Thanks.
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 https://docs.esi.evetech.net/docs/sso/native_sso_flow.html
const string clientId = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // Dummy Client ID
string authorizeUrl = @"https://login.eveonline.com/v2/oauth/authorize/";
const string callback = @"http://127.0.0.1:12500/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 =
{
"response_type=code",
"redirect_uri=" + HttpUtility.UrlEncode(callback),
"client_id=" + clientId,
"scope=" + HttpUtility.UrlEncode("esi-wallet.read_character_wallet.v1"),
"code_challenge=" + encodedCodeChallenge,
"code_challenge_method=S256",
"state=" + HttpUtility.UrlEncode("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") // Dummy Secret
};
string queryParameters = String.Join("&", queryStringParameters);
authorizeUrl += "?" + queryParameters;
// Setup Listener for Authorization Code Response
HttpListener listener = new HttpListener();
listener.Prefixes.Add(callback);
listener.Start();
Console.Write("Listening...");
// Send Request for Authorization Code
Process.Start("chrome.exe", authorizeUrl);
Console.WriteLine(listener.IsListening);
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 = "https://login.eveonline.com/v2/oauth/token/";
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.Clear();
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
client.Headers.Add("Host", "login.eveonline.com");
Console.WriteLine();
Console.WriteLine($"Authorization URL: {authBaseUrl}");
try
{
byte[] response = client.UploadValues(authBaseUrl, "POST", post_params);
Console.WriteLine(Encoding.UTF8.GetString(response));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Console.ReadKey();
}
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: https://www.c-sharpcorner.com/article/compute-sha256-hash-in-c-sharp/
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++)
{
builder.Append(bytes[i].ToString("x2"));
}
return builder.ToString();
}
}
}
}