Paolo A.
Paolo A.

Reputation: 11

Large-Scale Matrix Routing -- Missing Token/API Key Error

I'm trying to use the Large-Scale Matrix API to run some queries using Python 3.7.7. I believe I've successfully created an access token, yet my requests to the API state that my token is missing.

My code to generate the tokens is drawn entirely from the documentation here (a few print statements added), while querying the API uses the syntax shown on this page.

import time #To generate the OAuth timestamp
import urllib.parse #To URLencode the parameter string
import hmac #To implement HMAC algorithm
import hashlib #To generate SHA256 digest
from base64 import b64encode #To encode binary data into Base64
import binascii #To convert data into ASCII
import requests #To make HTTP requests


grant_type = 'client_credentials'
oauth_consumer_key = 
oauth_nonce = str(int(time.time()*1000))
oauth_signature_method = 'HMAC-SHA256'
oauth_timestamp = str(int(time.time()))
oauth_version = '1.0'

def create_parameter_string(grant_type, oauth_consumer_key,oauth_nonce,oauth_signature_method,oauth_timestamp,oauth_version):
    parameter_string = ''
    parameter_string = parameter_string + 'grant_type=' + grant_type
    parameter_string = parameter_string + '&oauth_consumer_key=' + oauth_consumer_key
    parameter_string = parameter_string + '&oauth_nonce=' + oauth_nonce
    parameter_string = parameter_string + '&oauth_signature_method=' + oauth_signature_method
    parameter_string = parameter_string + '&oauth_timestamp=' + oauth_timestamp
    parameter_string = parameter_string + '&oauth_version=' + oauth_version
    return parameter_string

parameter_string = create_parameter_string(grant_type, oauth_consumer_key,oauth_nonce,oauth_signature_method,oauth_timestamp,oauth_version)
encoded_parameter_string = urllib.parse.quote(parameter_string, safe='')


url = 'https://account.api.here.com/oauth2/token'
encoded_base_string = 'POST' + '&' + urllib.parse.quote(url, safe='')
encoded_base_string = encoded_base_string + '&' + encoded_parameter_string


access_key_secret = 
signing_key = access_key_secret + '&'

def create_signature(secret_key, signature_base_string):
    encoded_string = signature_base_string.encode()
    encoded_key = secret_key.encode()
    temp = hmac.new(encoded_key, encoded_string, hashlib.sha256).hexdigest()
    byte_array = b64encode(binascii.unhexlify(temp))
    return byte_array.decode()

oauth_signature = create_signature(signing_key, encoded_base_string)
encoded_oauth_signature = urllib.parse.quote(oauth_signature, safe='')

body = {'grant_type' : '{}'.format(grant_type)}

headers = {
            'Content-Type' : 'application/x-www-form-urlencoded',
            'Authorization' : 'OAuth oauth_consumer_key="{0}",oauth_nonce="{1}",oauth_signature="{2}",oauth_signature_method="HMAC-SHA256",oauth_timestamp="{3}",oauth_version="1.0"'.format(oauth_consumer_key,oauth_nonce,encoded_oauth_signature,oauth_timestamp)
          }

response = requests.post(url, data=body, headers=headers)

print(eval(response.text))

access_token = eval(response.text)['access_token']

url = 'https://largescalematrix.router.hereapi.com/v1/matrix'
body = {
    "origins": [{"lat": 0.0, "lng": 0.0}, {"lat": 0.1, "lng": 0.1}],
    # "destinations": [...],  // if omitted same as origins
    "regionDefinition": {
        "type": "circle",
        "center": {"lat": 0.0, "lng": 0.0},
        "radius": 10000
    }
}

headers = {
            'Authorization' : 'Bearer="{0}"'.format(access_token),
            'Content-Type' : 'application/json'
          }

response = requests.post(url, data=body, headers=headers)
print(eval(response.text))

In the above code, the (unfilled) fields of oauth_consumer_key and access_key_secret are filled with the key and secret key, respectively, generated from Projects>REST>OAuth 2.0 (JSON Web Tokens).

When I run this code, the token successfully generates -- I get a response of the form

{'access_token': [long string], 'token_type': 'bearer', 'expires_in': 86399}

However, when I then attempt to query the API, I get a 401 error with the following message:

{'error': 'Unauthorized', 'error_description': 'Token or apiKey is missing.'}

I think my error's of one of the two forms:

  1. I'm generating a token correctly, but not the correct token for querying the Large-Scale Matrix Routing. If this is the case, then what inputs should I be using to create my token?
  2. My syntax for querying the Large-Scale Matrix API is incorrect. My request follows the syntax shown on this page, so I'm not sure what I'm missing then. Do I need to include an APIKEY from Projects>REST>API Keys?

Upvotes: 1

Views: 208

Answers (2)

Morgo
Morgo

Reputation: 11

Thanks Paolo for your post, it really helped me. I followed the links to the page you posted for the python example to get the token, and by copy pasting that code I could also get the token. However I also failed in the same way you did, I was getting 401: Unauthorized.

The key for me was this page, under "Authentication Token".

curl https://weather.ls.hereapi.com/weather/1.0/report.json
?product=observation
&name=Berlin
-H "Authorization: Bearer {YOUR_TOKEN}"

This last bit, "Bearer (TOKEN)" was the missing bit I needed to make it work. Finally, here is my code:

import time #To generate the OAuth timestamp
import urllib.parse #To URLencode the parameter string
import hmac #To implement HMAC algorithm
import hashlib #To generate SHA256 digest
from base64 import b64encode #To encode binary data into Base64
import binascii #To convert data into ASCII
import requests #To make HTTP requests

import json

grant_type = 'client_credentials'
oauth_consumer_key = 'HERE.ACCESS.KEY.ID' #From credentials.properties file
oauth_nonce = str(int(time.time()*1000))
oauth_signature_method = 'HMAC-SHA256'
oauth_timestamp = str(int(time.time()))
oauth_version = '1.0'

def create_parameter_string(grant_type, oauth_consumer_key,oauth_nonce,oauth_signature_method,oauth_timestamp,oauth_version):
    parameter_string = ''
    parameter_string = parameter_string + 'grant_type=' + grant_type
    parameter_string = parameter_string + '&oauth_consumer_key=' + oauth_consumer_key
    parameter_string = parameter_string + '&oauth_nonce=' + oauth_nonce
    parameter_string = parameter_string + '&oauth_signature_method=' + oauth_signature_method
    parameter_string = parameter_string + '&oauth_timestamp=' + oauth_timestamp
    parameter_string = parameter_string + '&oauth_version=' + oauth_version
    return parameter_string

parameter_string = create_parameter_string(grant_type, oauth_consumer_key,oauth_nonce,oauth_signature_method,oauth_timestamp,oauth_version)
encoded_parameter_string = urllib.parse.quote(parameter_string, safe='')

url = 'https://account.api.here.com/oauth2/token'
encoded_base_string = 'POST' + '&' + urllib.parse.quote(url, safe='')
encoded_base_string = encoded_base_string + '&' + encoded_parameter_string

access_key_secret = 'HERE.ACCESS.KEY.SECRET'#From credentials.properties file
signing_key = access_key_secret + '&'

def create_signature(secret_key, signature_base_string):
    encoded_string = signature_base_string.encode()
    encoded_key = secret_key.encode()
    temp = hmac.new(encoded_key, encoded_string, hashlib.sha256).hexdigest()
    byte_array = b64encode(binascii.unhexlify(temp))
    return byte_array.decode()

oauth_signature = create_signature(signing_key, encoded_base_string)
encoded_oauth_signature = urllib.parse.quote(oauth_signature, safe='')

body = {'grant_type' : '{}'.format(grant_type)}

headers = {
            'Content-Type' : 'application/x-www-form-urlencoded',
            'Authorization' : 'OAuth oauth_consumer_key="{0}",oauth_nonce="{1}",oauth_signature="{2}",oauth_signature_method="HMAC-SHA256",oauth_timestamp="{3}",oauth_version="1.0"'.format(oauth_consumer_key,oauth_nonce,encoded_oauth_signature,oauth_timestamp)
          }
    
response = requests.post(url, data=body, headers=headers)

r_obj = json.loads(response.text)

token = r_obj['access_token']

print(response.text)

payload = {'name': 'Chicago', 'product': 'forecast_7days_simple'}
r = requests.get('https://weather.ls.hereapi.com/weather/1.0/report.json', params=payload, headers={'Authorization': 'Bearer '+token})
print(r.status_code)
r.encoding = r.apparent_encoding
obj = json.loads(r.text)
print(obj['dailyForecasts'])

Upvotes: 1

user3505695
user3505695

Reputation:

Try using following code snippet to generate the token.

import CryptoJS from 'crypto-js';
import axios from 'axios';

export const getToken = (app_key, app_secret) => {
    let url = "https://account.api.here.com/oauth2/token";
    let key = app_key;
    console.log(key);
    let secret = app_secret;
    console.log(secret);
    let nonce = btoa(Math.random().toString(36)).substring(2, 13);
    let timestamp = Math.floor(Date.now()/1000);
    let normalizedUrl = encodeURIComponent(url);
    console.log(normalizedUrl);
    let signing_method = "HMAC-SHA256";
    let sig_string = "oauth_consumer_key="
    .concat(key)
    .concat("&oauth_nonce=")
    .concat(nonce)
    .concat("&oauth_signature_method=")
    .concat(signing_method)
    .concat("&oauth_timestamp=")
    .concat(timestamp)
    .concat("&").concat("oauth_version=").concat("1.0");

    console.log(sig_string)

    let normalised_string = "POST&".concat(normalizedUrl).concat("&").concat(encodeURIComponent(sig_string));

    console.log(normalised_string);
    let signingKey = secret.concat("&");
    console.log(signingKey);

    let digest = CryptoJS.HmacSHA256(normalised_string, signingKey);
    console.log(">>>>>>>>>>>>>");
    console.log(digest);
    let signature = CryptoJS.enc.Base64.stringify(digest);



    let auth = 'OAuth oauth_consumer_key="'
    .concat(key)
    .concat('",oauth_signature_method="')
    .concat(signing_method)
    .concat('",oauth_signature="')
    .concat(encodeURIComponent(signature))
    .concat('",oauth_timestamp="')
    .concat(timestamp)
    .concat('",oauth_nonce="')
    .concat(nonce)
    .concat('",oauth_version="1.0"')

    console.log(auth)

    return axios({
        method: 'post',
        url: url,
        data: JSON.stringify({grantType: "client_credentials"}),
        headers: {
            'Content-Type': "application/json",
            'Authorization': auth
        }
    });
}

Upvotes: 0

Related Questions