Question: I need to make a connection to an API using a complicated authentication process that I don't understand. I know it involves multiple steps and I have tried to mimic it, but I find the documentation to be very confusing... The idea is that I make a request to an endpoint which will return a token to me that I need to use to make a websocket connection. I did get a code sample which is in Python that I don't know the syntax of, but I can use it as a guide to convert it to C#-syntax. This is the Python code sample: import time, base64, hashlib, hmac, urllib.request, json api_nonce = bytes(str(int(time.time()*1000)), "utf-8") api_request = urllib.request.Request("https://www.website.com/getToken", b"nonce=%s" % api_nonce) api_request.add_header("API-Key", "API_PUBLIC_KEY") api_request.add_header("API-Sign", base64.b64encode(hmac.new(base64.b64decode("API_PRIVATE_KEY"), b"/getToken" + hashlib.sha256(api_nonce + b"nonce=%s" % api_nonce).digest(), hashlib.sha512).digest())) print(json.loads(urllib.request.urlopen(api_request).read())['result']['token'])  So I have tried to convert this into C# and this is the code I got so far:  static string apiPublicKey = "API_PUBLIC_KEY"; static string apiPrivateKey = "API_PRIVATE_KEY"; static string endPoint = "https://www.website.com/getToken"; private void authenticate() { using (var client = new HttpClient()) { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; // CREATE THE URI string uri = "/getToken"; // CREATE THE NONCE /// NONCE = unique identifier which must increase in value with each API call /// in this case we will be using the epoch time DateTime baseTime = new DateTime(1970, 1, 1, 0, 0, 0); TimeSpan epoch = CurrentTime - baseTime; Int64 nonce = Convert.ToInt64(epoch.TotalMilliseconds); // CREATE THE DATA string data = string.Format("nonce={0}", nonce); // CALCULATE THE SHA256 OF THE NONCE string sha256 = SHA256_Hash(data); // DECODE THE PRIVATE KEY byte[] apiSecret = Convert.FromBase64String(apiPrivateKey); // HERE IS THE HMAC CALCULATION } } public static String SHA256_Hash(string value) { StringBuilder Sb = new StringBuilder(); using (var hash = SHA256.Create()) { Encoding enc = Encoding.UTF8; Byte[] result = hash.ComputeHash(enc.GetBytes(value)); foreach (Byte b in result) Sb.Append(b.ToString("x2")); } return Sb.ToString(); }  So the next part is where I'm really struggling. There needs to be some HMAC-calculation that needs to be done but I'm completely lost there.

Answer: The main task here is to reverse the API-Sign SHA-512 HMAC calculation. Use DateTimeOffset.Now.ToUnixTimeMilliseconds to get the API nonce, it will return a Unix timestamp milliseconds value. Then it all boils down concating byte arrays and generating the hashes. I'm using a hardcoded api_nonce time just to demonstrate the result; you'll have to uncomment string ApiNonce = DateTimeOffset.Now.ToUnixTimeMilliseconds to get the current Unix timestamp milliseconds each time the API-Sign key is calculated. Python API-Sign generation: import time, base64, hashlib, hmac, urllib.request, json # Hardcoce API_PRIVATE_KEY base 64 value API_PRIVATE_KEY = base64.encodebytes(b"some_api_key_1234") # time_use = time.time() # Hardcode the time so we can confirm the same result to C# time_use = 1586096626.919 api_nonce = bytes(str(int(time_use*1000)), "utf-8") print("API nonce: %s" % api_nonce) api_request = urllib.request.Request("https://www.website.com/getToken", b"nonce=%s" % api_nonce) api_request.add_header("API-Key", "API_PUBLIC_KEY_1234") print("API_PRIVATE_KEY: %s" % API_PRIVATE_KEY) h256Dig = hashlib.sha256(api_nonce + b"nonce=%s" % api_nonce).digest() api_sign = base64.b64encode(hmac.new(base64.b64decode(API_PRIVATE_KEY), b"/getToken" + h256Dig, hashlib.sha512).digest()) # api_request.add_header("API-Sign", api_sign) # print(json.loads(urllib.request.urlopen(api_request).read())['result']['token']) print("API-Sign: %s" % api_sign)  Will output: API nonce: b'1586096626919' API_PRIVATE_KEY: b'c29tZV9hcGlfa2V5XzEyMzQ=\n' API-Sign: b'wOsXlzd3jOP/+Xa3AJbfg/OM8wLvJgHATtXjycf5EA3tclU36hnKAMMIu0yifznGL7yhBCYEwIiEclzWvOgCgg=='  C# API-Sign generation: static string apiPublicKey = "API_PUBLIC_KEY"; // Hardcoce API_PRIVATE_KEY base 64 value static string apiPrivateKey = Base64EncodeString("some_api_key_1234"); static string endPoint = "https://www.website.com/getToken"; public static void Main() { Console.WriteLine("API-Sign: '{0}'", GenApiSign()); } static private string GenApiSign() { // string ApiNonce = DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString(); // Hardcode the time so we can confirm the same result with Python string ApiNonce = "1586096626919"; Console.WriteLine("API nonce: {0}", ApiNonce); Console.WriteLine("API_PRIVATE_KEY: '{0}'", apiPrivateKey); byte[] ApiNonceBytes = Encoding.Default.GetBytes(ApiNonce); byte[] h256Dig = GenerateSHA256(CombineBytes(ApiNonceBytes, Encoding.Default.GetBytes("nonce="), ApiNonceBytes)); byte[] h256Token = CombineBytes(Encoding.Default.GetBytes("/getToken"), h256Dig); string ApiSign = Base64Encode(GenerateSHA512(Base64Decode(apiPrivateKey), h256Token)); return ApiSign; } // Helper functions ___________________________________________________ public static byte[] CombineBytes(byte[] first, byte[] second) { byte[] ret = new byte[first.Length + second.Length]; Buffer.BlockCopy(first, 0, ret, 0, first.Length); Buffer.BlockCopy(second, 0, ret, first.Length, second.Length); return ret; } public static byte[] CombineBytes(byte[] first, byte[] second, byte[] third) { byte[] ret = new byte[first.Length + second.Length + third.Length]; Buffer.BlockCopy(first, 0, ret, 0, first.Length); Buffer.BlockCopy(second, 0, ret, first.Length, second.Length); Buffer.BlockCopy(third, 0, ret, first.Length + second.Length, third.Length); return ret; } public static byte[] GenerateSHA256(byte[] bytes) { SHA256 sha256 = SHA256Managed.Create(); return sha256.ComputeHash(bytes); } public static byte[] GenerateSHA512(byte[] key, byte[] bytes) { var hash = new HMACSHA512(key); var result = hash.ComputeHash(bytes); hash.Dispose(); return result; } public static string Base64EncodeString(string plainText) { var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText); return System.Convert.ToBase64String(plainTextBytes); } public static string Base64Encode(byte[] bytes) { return System.Convert.ToBase64String(bytes); } public static byte[] Base64Decode(string base64EncodedData) { var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData); return base64EncodedBytes; }  Will output: API nonce: 1586096626919 API_PRIVATE_KEY: 'c29tZV9hcGlfa2V5XzEyMzQ=' API-Sign: 'wOsXlzd3jOP/+Xa3AJbfg/OM8wLvJgHATtXjycf5EA3tclU36hnKAMMIu0yifznGL7yhBCYEwIiEclzWvOgCgg=='  You can see it working and the result in this .NET Fiddle.