I am trying to implement the OAuth authentication for HERE REST API following this documentation: https://developer.here.com/documentation/identity-access-management/dev_guide/topics/sdk.html
My problem is that when I send the POST request with the OAuth Header and Body, the response I receive from the server is: Signature mismatch. Authorization signature or client credential is wrong.
I probed my credentials using the OAuth1.0 authorization in Postman and the HERE API responds with a valid access token. Hence my credentials values are correct.
In addition to the official documentation, I followed recommandations published in various Stack Overflow answers, especially the encoding of all parameters (encodeURI).
I suspect the CryptoJS npm package to be the source of my problem. The result of the HmacSHA256 cryptographic function is very different from various online HmaSHA256 that I tried with my baseString as parameter. However, the crypto-js library (+ @type/crypto-js for Typescript) seems to be the reference for React Typescript crypto functions. I couldn't figure out where I got it wrong :/
Following is my implementation of the OAuth method to get my access token. I am using :
"@types/crypto-js": "^4.1.1",
"crypto-js": "^4.1.1",
<node.version>v14.14.0</node.version>
<npm.version>v6.14.8</npm.version>
HERE_ACCESS_KEY = <here.access.key>;
HERE_ACCESS_SECRET = <here.access.key.secret>;
HERE_AUTH_URL = "https://account.api.here.com/oauth2/token";
My frontend code:
import CryptoJS from "crypto-js";
private buildOAuthSignatureBaseString(accessKey: string, nonce: string, hashMethod: string, timestamp: string) {
const baseStringParameters = `grant_type=client_credentials&oauth_consumer_key=${accessKey}&oauth_nonce=${nonce}&oauth_signature_method=${hashMethod}&oauth_timestamp=${timestamp}&oauth_version=1.0`;
return `POST&${encodeURIComponent(this.HERE_AUTH_URL)}&${encodeURIComponent(baseStringParameters)}`;
}
private buildHereOauthSignature(accessKey: string, nonce: string, hashMethod: string, timestamp: string) {
const baseString = this.buildOAuthSignatureBaseString(accessKey, nonce, hashMethod, timestamp);
const signingKey = `${encodeURIComponent(this.HERE_ACCESS_SECRET)}&`;
const hashedBaseString = CryptoJS.HmacSHA256(baseString, signingKey);
const base64hash = CryptoJS.enc.Base64.stringify(hashedBaseString);
return encodeURIComponent(base64hash);
}
public getHereMapsApiAccessToken() {
const hashMethod = encodeURIComponent("HMAC-SHA256");
const accessKey = encodeURIComponent(this.HERE_ACCESS_KEY);
const nonce = encodeURIComponent(new Buffer(random(8)).toString("base64"));
const timestamp = Math.floor(new Date().getTime() / 1000).toString(10);
const signature = this.buildHereOauthSignature(accessKey, nonce, hashMethod, timestamp);
const headers = new Headers({
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": `OAuth oauth_consumer_key="${accessKey}", oauth_nonce="${nonce}", oauth_signature_method="${hashMethod}", oauth_timestamp="${timestamp}", oauth_version="1.0", oauth_signature="${signature}"`
});
const method = HTTP_METHODS.POST;
const options = {headers, method, body: JSON.stringify({grant_type: "client_credentials"})};
return fetch("https://account.api.here.com/oauth2/token", options)
.then((response) => {
console.log(response);
return true;
}).catch((error) => {
console.log(error);
return false;
});
}
Thanks in advance !