Reputation: 5986
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
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
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
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