I'm calling the API to get a list of shipments but I can't seem to page through the results.
The API call is successful with only one query parameter but when I call it with two query parameters, I get the error "The signature is invalid. Verify and try again". I'm including my test code below.
<?php
function sign($method, $url, $data, $consumerSecret, $tokenSecret)
{
$url = urlEncodeAsZend($url);
$data = urlEncodeAsZend(http_build_query($data, '', '&'));
$data = implode('&', [$method, $url, $data]);
$secret = implode('&', [$consumerSecret, $tokenSecret]);
return base64_encode(hash_hmac('sha1', $data, $secret, true));
}
function urlEncodeAsZend($value)
{
$encoded = rawurlencode($value);
$encoded = str_replace('%7E', '~', $encoded);
return $encoded;
}
// REPLACE WITH YOUR ACTUAL DATA OBTAINED WHILE CREATING NEW INTEGRATION
$consumerKey = 'htj8ze6ntr0mz1s4hjxrqeicia8rxgt4';
$consumerSecret = 'djjzdwfgbbr7ganlkv01qr6p3l7ptvfe';
$accessToken = '60o0mfrvqnjvin7tjuqsv37arijrqe9e';
$accessTokenSecret = 'caq9wfdx99zaygwgbhw91i9imj89p4zb';
$method = 'GET';
/* test 1 PASS */
//$url = 'http://localhost/rest/V1/shipments/';
//$qs = ['searchCriteria'=>'all'];
/* test 2 PASS */
//$url = 'http://localhost/rest/V1/shipments/';
//$qs = ['searchCriteria[pageSize]'=>'10'];
/* test 3 FAIL "The signature is invalid. Verify and try again" */
$url = 'http://localhost/rest/V1/shipments/';
$qs = ['searchCriteria[pageSize]'=>'10', 'searchCriteria[currentPage]'=>'1'];
$data = [
'oauth_consumer_key' => $consumerKey,
'oauth_nonce' => md5(uniqid(rand(), true)),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_token' => $accessToken,
'oauth_version' => '1.0',
];
$data = array_merge($data, $qs);
$data['oauth_signature'] = sign($method, $url, $data, $consumerSecret, $accessTokenSecret);
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $url .'?' .http_build_query($qs),
CURLOPT_HTTPHEADER => [
'Authorization: OAuth ' . http_build_query($data, '', ',')
]
]);
$result = curl_exec($curl);
curl_close($curl);
echo($result);
The code includes three tests.
If I uncomment test 1 and comment test 2 and 3, the code works properly and I get a list of shipments.
If I uncomment test 2 and comment test 1 and 3, the code works properly and I get a list of shipments.
If I run the code as is, I get the the message "The signature is invalid. Verify and try again."
I'm running Magento ver. 2.3.2
The trick is to sort the parameters. I have some client code anyone is interested.
<?php
function sign($method, $url, $data, $consumerSecret, $tokenSecret)
{
$url = urlEncodeAsZend($url);
$data = urlEncodeAsZend(http_build_query($data, '', '&'));
$data = implode('&', [$method, $url, $data]);
$secret = implode('&', [$consumerSecret, $tokenSecret]);
return base64_encode(hash_hmac('sha1', $data, $secret, true));
}
function urlEncodeAsZend($value)
{
$encoded = rawurlencode($value);
$encoded = str_replace('%7E', '~', $encoded);
return $encoded;
}
function recursive_sort(&$array) {
foreach ($array as &$value) {
if (is_array($value)) recursive_sort($value);
}
return ksort($array);
}
// REPLACE WITH YOUR ACTUAL DATA OBTAINED WHILE CREATING NEW INTEGRATION
$consumerKey = 'htj8ze6ntr0mz1s4hjxrqeicia8rxgt4';
$consumerSecret = 'djjzdwfgbbr7ganlkv01qr6p3l7ptvfe';
$accessToken = '60o0mfrvqnjvin7tjuqsv37arijrqe9e';
$accessTokenSecret = 'caq9wfdx99zaygwgbhw91i9imj89p4zb';
$method = 'GET';
/* test 1 PASS */
//$url = 'http://localhost/rest/V1/shipments/';
//$qs = ['searchCriteria'=>'all'];
/* test 2 PASS */
//$url = 'http://localhost/rest/V1/shipments/';
//$qs = ['searchCriteria[pageSize]'=>'10'];
/* test 3 FAIL "The signature is invalid. Verify and try again" */
$url = 'http://localhost/rest/V1/shipments/';
$qs = ['searchCriteria'=>['pageSize'=>10,'currentPage'=>1]];
$data = [
'oauth_consumer_key' => $consumerKey,
'oauth_nonce' => md5(uniqid(rand(), true)),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_token' => $accessToken,
'oauth_version' => '1.0',
];
$data = array_merge($data, $qs);
recursive_sort($data);
$data['oauth_signature'] = sign($method, $url, $data, $consumerSecret, $accessTokenSecret);
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $url .'?' .http_build_query($qs),
CURLOPT_HTTPHEADER => [
'Authorization: OAuth ' . http_build_query($data, '', ',')
]
]);
$result = curl_exec($curl);
curl_close($curl);
echo($result);
Though this question is old, I want to post the answer for future cases.
The code in the question is good, and it helped me a lot.
It is needed to sort parameters by key. Also, please consider that the searchCriteria is a multidimensional array. So, the array must be sorted by key recursively.
Related
I'm not an expert in API development or using signed messages in PHP.
I have however tried to get the GATE.IO v4 API working in my PHP implementation but keep getting "Signature mismatch". I have followed the API documentation for CREATE ORDER available at Gate.io's website here: https://www.gate.tv/docs/developers/apiv4/#create-an-order
I have managed to get the /spot/accounts working, so I know that the key and secret are correct.
Based on the code below I seem to missing something. Probably a tiny error but those are the hardest, right?
Does anyone have any idea what could be the cause of this issue? Would really appreciate your help after having spent 8+ hours trying to get this to work.
<?php
$accessToken = ''; // Access token for OAuth/Bearer authentication
$key = "XXXXXXXXXXXXXXXXXXXXXXX";
$secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$username = ''; // Username for HTTP basic authentication
$password = ''; // Password for HTTP basic authentication
$host = 'https://api.gateio.ws/api/v4'; // The host
$userAgent = 'OpenAPI-Generator/5.26.0/PHP'; // User agent of the HTTP request, set to "OpenAPI-Generator/{version}/PHP" by default
$sResourcePath = "/spot/orders";
$sMethod = "POST"; // POST or GET
$aPayload['currency_pair'] = "DOT_USDT";
$aPayload['price'] = "6.330033";
$aPayload['account'] = "spot";
$aPayload['side'] = "buy";
$aPayload['amount'] = "1";
$aPayload['time_in_force'] = "gtc";
$sBody = json_encode($aPayload);
$aQueryParams = $aPayload;
$aFullPath = parse_url($host . $sResourcePath);
$fullPath = $aFullPath['path'];
$timestamp = time();
$hashedPayload = hash("sha512", ($payload !== null) ? $payload : "");
$fmt = "%s\n%s\n%s\n%s\n%s";
$sQuery = http_build_query($aQueryParams, false);
$signatureString = sprintf($fmt, $sMethod, $fullPath, $sQuery, $hashedPayload, $timestamp);
$signature = hash_hmac("sha512", $signatureString, $secret);
$aSignHeaders = array(
"KEY" => $key,
"SIGN" => $signature,
"Timestamp" => $timestamp);
$aHeaders[] = "KEY: " . $aSignHeaders['KEY'];
$aHeaders[] = "SIGN: " . $aSignHeaders['SIGN'];
$aHeaders[] = "Timestamp: " . $aSignHeaders['Timestamp'];
$aExtraParams['sHttpHeaders'] = $aHeaders;
if ($sMethod == "POST")
{
$sParams = "?" . http_build_query($aQueryParams, false);
}
else
{
$sQuery = "";
}
$sSubmitUrl = $host . $sResourcePath . $sParams;
$sPage = CURL::doRequest($sMethod, $sSubmitUrl, $sParams, $aExtraParams);
$aPage = json_decode($sPage, true);
if ($aPage)
{
$iPage = count($aPage);
}
echo "<pre>";
print_r($aPage);
echo "</pre>";
?>
based on that example request, you should be doing something like this
//path & urls
$host = 'https://api.gateio.ws';
$prefix = '/api/v4';
$path = '/spot/orders';
$fullPath = "$prefix$path";
$method = 'POST';
//your API keys
$api = [
'secret' => 'xxxx'
];
// Your actual data you can easily modify
$payload = [
'currency_pair' => 'DOT_USDT',
'price' => '6.330033',
'account' => 'spot',
'side' => 'buy',
'amount' => '1',
'time_in_force' => 'gtc'
];
//Convert your data to JSON FORMAT
$jsonPayload = json_encode( $payload );
//Hash your JSON DATA
$hashJsonPayload = hash('sha512', $jsonPayload);
$timeStamp = time();
// dunno if this is required
$queryParam = '';
//Create your signature string
$signString="$method\n$fullPath\n$queryParam\n$hashJsonPayload\n$timeStamp";
//Generate the signature
$signHash = hash_hmac('sha512', $signString, $api['secret']);
// Your Actual headers
$headers = [
'Content-Type: application/json',
'Timestamp: '.$timeStamp,
'Key: '.$api['secret'],
'SIGN: '.$signHash
];
Example request using php curl
$ch = curl_init( "$host$fullPath" ); // URL to POST https://api.gateio.ws/api/v4/spot/orders
curl_setopt( $ch, CURLOPT_POSTFIELDS, $jsonPayload ); // set json payload as body here
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers ); //define header here
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
$result = curl_exec($ch);
curl_close($ch)
echo '<pre>', print_r($result, 1), '</pre>';
I got this error when i try to check using postman... u can see the error below
i got this massage
"code":400,"response":"Failed","message":"Your username is not registered. Please register a new user now!","data":null
public function loginAction()
{
$this->view->disable();
$credentials = $this->request->getJsonRawBody();
$response = new Response();
$username = $credentials->username;
$password = $credentials->password;
// $user = User::findFirst("user_username = '$username'");
$user = User::findFirst([
'conditions' => 'username = :username:',
'bind' => [
'username' => $username
]
]);
if($user !== NULL) {
$checkPassword = $this->security->checkHash($password, $user->password);
if($checkPassword === true) {
$this->session->set('username', [
'id' => $username->id,
'username' => $user->username,
]);
I am using Mirakl api. I faced an issue with the file upload with form-peram in Laravel 8 external api with guzzle or HTTP client.I got 400 Bad Request.The api expects file with from-param like this
{
"order_documents": [{
"file_name": String,
"type_code": String
}]
}
The documentation of my endpoint can be found from this link (http://185.29.149.41/eci/mir/doc/api/OR74.html) and here is my codes --
public function upload_order(Request $request)
{
$order_id = $request->order_id;
if ($files = $request->file('files')) {
$name = $files->getClientOriginalName();
Storage::disk('invoice')->put($name, file_get_contents($files->getRealPath()));
$path = Storage::disk('invoice')->path($name);
}
$file['order_documents'][] = [
'file_name' => $name,
'type_code' => $request->type_code,
];
$json = json_encode($file);
$data = [
['name' => 'order_documents','contents' => $json],
];
$data[] = [
'name' => 'files',
'contents' => mb_convert_encoding($path, 'UTF-8', 'UTF-8'),
'filename' => $name,
];
$body['multipart'] = $data;
$configApi = $this->configApi($this->getMarketplaceID($request->marketplace), auth()->user()->id);
$url = $configApi['url'].'/api/orders/'.$order_id.'/documents';
$client = new Client(['verify' => false]);
$response = $client->request(
'POST',
$url,
[
'multipart' => $data,
'headers' => $configApi['headers']
]);
return json_decode($response->getBody(), true);
}
I am attempting implement Oauth 2.0 for login, but the following code isn't producing a consistent response. why? Email is present "sometimes" but I cannot find anything here that would explain the varied response. The goal here is that I could use the email to locate users in my system.
<?php
// http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06
require_once 'sites/all/modules/schoology_core/s_support/JWT.php';
// app info (see google api console for creds)
$google_client_id = '';
$google_secret = '';
$google_redirect_uri = '';
$google_is_auth_response = (isset($_GET['code']) || isset($_GET['error']));
// construct auth url used to redirect user to google login form
$auth_url = 'https://accounts.google.com/o/oauth2/auth?';
$auth_url .= 'client_id=' . $google_client_id . '&';
$auth_url .= 'response_type=code&';
$auth_url .= 'scope=openid%20email&';
$auth_url .= 'redirect_uri=' . $google_redirect_uri . '&';
$auth_url .= 'state=' . uniqid();
$auth_link = '<br>'. $auth_url .'';
// send user to google login form
if(!$google_is_auth_response) {
print $auth_link;
exit;
}
// handle response
if($_GET['error']) {
print 'Oauth2 response error=' . $_GET['error'];
}
else {
// exchange one-time authorization code for access token and ID token
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://accounts.google.com/o/oauth2/token',
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_POST => TRUE,
CURLOPT_POSTFIELDS => array(
'code' => $_GET['code'],
'client_id' => $google_client_id,
'client_secret' => $google_secret,
'redirect_uri' => $google_redirect_uri,
'grant_type' => 'authorization_code',
)
));
$response = curl_exec($curl);
$responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
// decode response and id token to retrieve user's email
$response = json_decode($response);
$jwt_id_token = JWT::decode($response->id_token, NULL, FALSE);
$response_info = print_r(array(
'auth_code' => $_GET['code'],
'response_code' => $responseCode,
'response_decoded' => $response,
'id_token' => $jwt_id_token,
'email_is_not_preset' => $jwt_id_token->email ? 'Y' : 'N'
), TRUE);
print '<pre>' . $response_info . '</pre>';
}
After the update from API 1 to 1.1 my code doesn't show any results anymore.
On this forum I found a new code (below) for user_timeline results.
Change te link to https://api.twitter.com/1.1/search/tweets.json?q=test, results in the message: Could not authenticate you. What do I wrong?
function buildBaseString($baseURI, $method, $params) {
$r = array();
ksort($params);
foreach($params as $key=>$value){
$r[] = "$key=" . rawurlencode($value);
}
return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r));
}
function buildAuthorizationHeader($oauth) {
$r = 'Authorization: OAuth ';
$values = array();
foreach($oauth as $key=>$value)
$values[] = "$key=\"" . rawurlencode($value) . "\"";
$r .= implode(', ', $values);
return $r;
}
$url = "https://api.twitter.com/1.1/statuses/user_timeline.json";
$oauth_access_token = "YOURVALUE";
$oauth_access_token_secret = "YOURVALUE";
$consumer_key = "YOURVALUE";
$consumer_secret = "YOURVALUE";
$oauth = array( 'oauth_consumer_key' => $consumer_key,
'oauth_nonce' => time(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_token' => $oauth_access_token,
'oauth_timestamp' => time(),
'oauth_version' => '1.0');
$base_info = buildBaseString($url, 'GET', $oauth);
$composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$oauth['oauth_signature'] = $oauth_signature;
// Make Requests
$header = array(buildAuthorizationHeader($oauth), 'Expect:');
$options = array( CURLOPT_HTTPHEADER => $header,
//CURLOPT_POSTFIELDS => $postfields,
CURLOPT_HEADER => false,
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false);
$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);
$twitter_data = json_decode($json);
You need to provide auth data. look at this page page. it says Authentication required. Using the OAuth tool, select your app and generate signature to properly call the resource.