Jonathan Applebaum
Jonathan Applebaum

Reputation: 5986

Invalid Client Authorization header when trying to get token from "Here" REST API

I am trying to get a Bearer token to start using HERE REST API,
using (OAuth 2.0 (JSON Web Tokens))
after a lot of struggles, I am stuck with 401202 error:

{"errorId":"ERROR-e0242f30-05da-4df0-9beb-b697062240ce","httpStatus":401,"errorCode":401202,"message":"Invalid Client Authorization header, expecting signed request format.","error":"invalid_request","error_description":"errorCode: '401202'. Invalid Client Authorization header, expecting signed request format."}

Here is my code:

private void GetToken()
{
   try
    {
        var here_client_id = "b1Ibl7XXXXXXXoZtNKb";
        var here_access_key_id = "8DKjlwXXXXXXXXXerGCXPA";
        var here_access_key_secret = "tuU-bGMa1ljancfoXXXXXXXXXXXXXXXK8cMlk4o0EGUpS2fmwkAtlltFPDhYQUgytJLL-X_YNIjmdWcOabQ";
        var url = "https://account.api.here.com/oauth2/token";

        var Parameters = "grant_type=client_credentials&client_id=" + here_client_id + "&oauth_consumer_key=" + here_access_key_secret;

        var hmac = new HMACSHA256();
        var key = Convert.ToBase64String(hmac.Key);
        Guid id = Guid.NewGuid();

        // Create a request for the URL.        
        WebRequest request = WebRequest.Create(url);

        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";
        var cred = @"OAuth oauth_consumer_key=" + here_access_key_id;

        request.Headers.Add("Authorization", cred);
        //request.Headers.Add("oauth_consumer_key", here_access_key_id);
        request.Headers.Add("oauth_nonce", id.ToString());
        request.Headers.Add("oauth_signature_method", "HMAC-SHA256");
        request.Headers.Add("oauth_signature", key);
        request.Headers.Add("oauth_timestamp", ConvertToUnixTimestamp(DateTime.Now).ToString());
        request.Headers.Add("oauth_version", "1.0");

        byte[] byteArray = Encoding.UTF8.GetBytes(Parameters);
        request.ContentLength = byteArray.Length;

        Stream postStream = request.GetRequestStream();
        // Add the post data to the web request
        postStream.Write(byteArray, 0, byteArray.Length);
        postStream.Close();

        // Get the response.
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        // Display the status.
        Console.WriteLine(response.StatusDescription);
        // Get the stream containing content returned by the server.
        Stream dataStream = response.GetResponseStream();
        // Open the stream using a StreamReader for easy access.
        StreamReader reader = new StreamReader(dataStream);
        // Read the content.
        string responseFromServer = reader.ReadToEnd();
        // Display the content.
        MessageBox.Show(responseFromServer);
        // Cleanup the streams and the response.
        reader.Close();
        dataStream.Close();
        response.Close();
    }
    catch (WebException ex)
    {
        using (var stream = ex.Response.GetResponseStream())
        using (var reader = new StreamReader(stream))
        {
           //MessageBox.Show(reader.ReadToEnd());
            textBox1.Text = reader.ReadToEnd();
        }
    }
}

Upvotes: 4

Views: 8765

Answers (3)

Yuriy Chernyshov
Yuriy Chernyshov

Reputation: 504

The Python version that does exactly what the title is about doesn't work with the same error message. Does someone have Python code operational with HERE APIs?

def create_nonce():
    return str(random.randint(0, 1000000000))


def url_encode_string(input_string):
    encoded_string = urllib.parse.quote(input_string)
    return encoded_string


def create_signature(signature_base_string, signing_key):
    # Create a HMAC-SHA256 hash object with the signing key
    hmac_obj = hmac.new(signing_key.encode(), 
    msg=signature_base_string.encode(), digestmod=hashlib.sha256)
    # Get the binary digest of the HMAC-SHA256 hash
    digest = hmac_obj.digest()
    # Convert the binary digest to a base64-encoded string
    return base64.b64encode(digest).decode()

access_key_id = "..."
access_key_secret = "..."

nonce = create_nonce()
single_string = "grant_type=client_credentials" \
                "&oauth_consumer_key={0}" \
                "&oauth_nonce={1}" \
                "&oauth_signature_method=HMAC-SHA256" \
                "&oauth_timestamp={2}" \
                "&oauth_version=1.0" \
    .format(access_key_id, nonce, epoch_time)
single_string = url_encode_string(single_string)
base_string = "POST&https%3A%2F%2Faccount.api.here.com%2Foauth2%2Ftoken&{0}".format(single_string)
signing_key = "{0}&".format(url_encode_string(access_key_secret))
signature = create_signature(base_string, signing_key)

oath = "oauth_consumer_key: \"{0}\", " \
       "oauth_nonce: \"{1}\", " \
       "oauth_signature: \"{2}\", " \
       "oauth_signature_method: \"HMAC-SHA256\", " \
       "oauth_timestamp: \"{3}\", " \
       "oauth_version: \"1.0\"".format(access_key_id, nonce, signature, epoch_time)

headers = {
    "Content-Type": "application/json",
    "Cache-Control": "no-cache",
    "Authorization": "OAuth {0}".format(oath),
}

data = {
    "grantType": "client_credentials"
}
json_data = json.dumps(data)

parsed_url = urllib.parse.urlparse(token_url)
hostname = parsed_url.hostname
path = parsed_url.path
conn = http.client.HTTPSConnection(hostname)
conn.request("POST", path, json_data, headers)
response = conn.getresponse()
print("Response:", response.read().decode())

And the response is:

"message":"Invalid Client Authorization header, expecting signed request format."

Upvotes: 0

P6345uk
P6345uk

Reputation: 723

This is my first cut and is rough but.

var accessKey = "";
    var secret = "";
    var url = "https://account.api.here.com/oauth2/token";
    var nonce = GetNonce();
    var timestamp = GetTimeStamp();
    var baseString = @"grant_type=client_credentials&oauth_consumer_key=" + accessKey + "&oauth_nonce=" + nonce + "&oauth_signature_method=HMAC-SHA256&oauth_timestamp=" + timestamp + "&oauth_version=1.0";

    var workingString = new List<string>();
    foreach (var parameter in baseString.Split('&').ToList())
    {
        workingString.Add(Uri.EscapeDataString(parameter.Split('=')[0] + "=" + parameter.Split('=')[1].Trim()));
    }
    var urlEncodeParamaterString = String.Join(Uri.EscapeDataString("&"), workingString.ToArray());
    var fullBaseString = $"POST&{Uri.EscapeDataString(url)}&{urlEncodeParamaterString}";

    var signature = CreateToken(fullBaseString, (Uri.EscapeDataString(secret) + "&"));

    var authHeader = "OAuth oauth_consumer_key=\"" + accessKey + "\",oauth_signature_method=\"HMAC-SHA256\",oauth_timestamp=\"" + timestamp + "\",oauth_nonce=\"" + nonce + "\",oauth_version=\"1.0\",oauth_signature=\"" + Uri.EscapeDataString(signature) + "\"";



    using (HttpClient httpClient = new HttpClient())
    {
        httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);
        var response = await httpClient.PostAsync(url, new StringContent($"grant_type={Uri.EscapeDataString("client_credentials")}",
                                                        Encoding.UTF8,
                                                        "application/x-www-form-urlencoded"));
        var responseContent = response.Content.ReadAsStringAsync();
    }

The other Methods are

 private string GetNonce()
    {
        var rand = new Random();
        var nonce = rand.Next(1000000000);
        return nonce.ToString();
    }
    private string CreateToken(string message, string secret)
    {
        secret = secret ?? "";
        var encoding = new System.Text.ASCIIEncoding();
        byte[] keyByte = encoding.GetBytes(secret);
        byte[] messageBytes = encoding.GetBytes(message);
        using (var hmacsha256 = new HMACSHA256(keyByte))
        {
            byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
            return Convert.ToBase64String(hashmessage);
        }
    }
    private string GetTimeStamp()
    {
        var ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
        return Convert.ToInt64(ts.TotalSeconds).ToString();
    }

Upvotes: 3

Jonathan Applebaum
Jonathan Applebaum

Reputation: 5986

At the end I did it without web JSON WEB TOKENS.
According to this API documentation the call was made only with API KEY.

public static string ConvertAddressToCoordinate(string address)
{
    try
    {
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

        var apikey = "xxxxxxxxxxxxxxxxxxxxx_xxxxxxxxx";
        var url = "https://geocoder.ls.hereapi.com/6.2/geocode.json?apiKey=";
        var fullurl = url + apikey + "&searchtext=" + address;
        // Create a request for the URL.        
        WebRequest request = WebRequest.Create(fullurl);
        request.Method = "GET";
        request.ContentType = "application/json";
        // Get the response.
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        // Display the status.
        Console.WriteLine(response.StatusDescription);
        // Get the stream containing content returned by the server.
        Stream dataStream = response.GetResponseStream();
        // Open the stream using a StreamReader for easy access.
        StreamReader reader = new StreamReader(dataStream);
        // Read the content.
        string responseFromServer = reader.ReadToEnd();
        // Display the content.
        return responseFromServer;
    }
    catch (WebException ex)
    {
        return "ERROR " + ex.Message;
    }
    catch (Exception ex)
    {
        return "ERROR " + ex.Message;
    }
}

Upvotes: 1

Related Questions