i am trying to verify the signature of a jwt im sending but it doesnt match, despite making sure that both payload and header are identical.
here is my client code, the one sending the jwt:
<?php
$ch = curl_init();
$handle = fopen("C:/xampp/htdocs/video/charmscene.mp4", "rb");
$contents = fread($handle, filesize("C:/xampp/htdocs/video/charmscene.mp4"));
fclose($handle);
//encode binary file to 64 because json doesnt support binary
$encoded_file = base64_encode($contents);
//serialize -> 64enc ->json enc
$header = ['typ' => 'JWT', 'alg' => 'HS256'];
$payload = ["filename"=>"charmscene","api"=>"VALIDAPIKEY"];
$secret = "thisisasecret";
$headerenc = base64_encode(serialize($header));
$payloadenc = base64_encode(serialize($payload));
$signature = hash_hmac("SHA256",$headerenc .".".$payloadenc, $secret,true);
$signature_enc = base64_encode($signature);
$jwt = $headerenc.".".$payloadenc.".".$signature_enc;
curl_setopt($ch, CURLOPT_URL, "http://localhost/app/webservice/api/index.php?clients=123");
$requestheaders = ['Accept: application/json', "WWW-Authenticate: Bearer ".$jwt];
curl_setopt($ch, CURLOPT_HTTPHEADER, $requestheaders);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Get the payload of the response:
$responsedata = curl_exec($ch);
echo $responsedata;
curl_close($ch);
?>
and heres the function that deciphers the jwt:
function decipherJwt($jwt)
{
//the secret is shared between client and server beforehand
$secret = "thisisasecret";
$type= strtok($jwt," ");//bearer
$token = substr($jwt,strpos($jwt," "));
$parts = explode(".",$token);
$headerenc = $parts[0];
$payloadenc= $parts[1];
$signatureenc= $parts[2];
$signature = $signatureenc;
$signature2 = base64_encode(hash_hmac("SHA256",$headerenc ."." .$payloadenc, $secret,true));
if($signature!=$signature2)
{
echo "signature doesn't match content";
echo $signature;
echo "</br>";
echo $signature2;
return;
}
return array(unserialize(base64_decode($headerenc)),unserialize(base64_decode($payloadenc)), $signature);
}
the signatures just dont match and i dont get why.
Related
I'm using coinbase pro API to fetch some data and to make some trades but API is returning
{"message":"IP does not match IP whitelist"}
I'm using Rest API with correct API keys. I'm sure API keys are authenticated correctly and while creating API keys, I've entered correct IP address of my server. I rechecked IP 5 times but it's correct. Below is my sample code
<?php
function signature($request_path='', $body='', $timestamp=false, $secret = '', $method='GET') {
$body = is_array($body) ? json_encode($body) : $body;
$timestamp = $timestamp ? $timestamp : time();
$what = $timestamp.$method.$request_path.$body;
return base64_encode(hash_hmac("sha256", $what, base64_decode($secret), true));
}
function make_request($url, $method, $headers, $body = ''){
$ch = curl_init();
// Disable SSL verification
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
// Will return the response, if false it print the response
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
// Set the url
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_VERBOSE, true);
if ($method == "POST") {
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}
// "accept" => "application/json"
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// Execute
$result_json = curl_exec($ch);
curl_close($ch);
return $result_json;
}
try {
$apiurl = "https://api.pro.coinbase.com";
$secret = "SUPER_SECRET";
$api_key = "API_KEY";
$passphrase = "PASSPHRASE";
$method = "GET";
$requestPath = "/accounts";
$body = "";
$url = $apiurl . $requestPath;
$data["name"] = "";
$body = json_encode($data);
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$list = explode(" ", $user_agent);
$user_agent = $list[0];
$timestamp = (string) time();
$string = $timestamp . $method . $requestPath;
$sig = signature($requestPath, '', $timestamp, $secret);
$headers = [
"CB-ACCESS-KEY: ".$api_key,
"CB-ACCESS-SIGN: ".$sig,
"CB-ACCESS-TIMESTAMP: ".$timestamp,
"CB-ACCESS-PASSPHRASE: ".$passphrase,
"User-Agent:". $user_agent,
"Content-Type: application/json",
];
$result_json = make_request($url, $method, $headers);
var_dump($result_json);
die;
}
catch(Exception $e){
var_dump($e->getMessage());
die;
}
I've searched a lot for this problem and been struggling with it since 2 days. If anyone can help or point me in right direction? That would be highly appreciated.
Thanks & Regards.
I get JSON from the Soundcloud API by using code in section【A】.
But I want to get it without using $type, like in code【B】.
In other words, I want to get that information by only giving $target.
What should I do?
$r = soundcloud_responce();
var_dump( $r );
function soundcloud_responce(){
$client_id = 'xxx';
$type = 'tracks';
$q = 'words';
// code【A】
// If I have $type, So this process ok.
$url = "https://api.soundcloud.com/";
$url .= $type;
$url .= "?client_id=$client_id";
$url .= "&q=$q";
// code【B】
// I want to do same process with $target but without $type
$target = "https://soundcloud.com/accountname/trackname";
$target = str_replace('https://soundcloud.com/', '', $target);
$url = "https://api.soundcloud.com/";
$url .= $target;
$url .= "?client_id=$client_id";
// curl
$ch = curl_init();
$headers = [
'Accept: application/json',
'Content-Type: application/json',
];
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$res = curl_exec($ch);
$json = json_decode($res);
curl_close($ch);
return $json;
}
(Add 2020-02-21-09:38 #Tokyo)
I tried this code【C】but this also failed.
// code【C】
// I tried with oembed but this also failed.
$target = "https://soundcloud.com/accountname/trackname";
$url = 'http://soundcloud.com/oembed?format=json&url='.$target;
(Add 2020-02-21-10:12 #Tokyo)
I tried this code【D】but this also failed.
// code【D】
// I tried with resolve but this also failed.
$target = "https://soundcloud.com/accountname/trackname";
$url = "https://api.soundcloud.com/resolve?url=$target&client_id=$client_id";
I tried this code【E】this is successful!
Thank you for giving me good advice, #showdev.
// code【E】
// this is successful!
$target = "https://soundcloud.com/accountname/trackname";
$target = urlencode($target);
$url = "https://api.soundcloud.com/resolve.json?url=$target&client_id=$client_id";
This is what I have tried so far:
$t=time()+60;
$to_sign = "DELETE\n\n\n$t\n/myimage.jpg";
$signature = base64_encode( hash_hmac('sha1', utf8_encode( $to_sign ) , $auth['secretKey'], true) );
$url = "https://mybucket.s3-us-west-1.amazonaws.com/myimage.jpg?AWSAccessKeyId=MYKEYNUMBERXXX&Signature=$signature&Expires=$t";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST,'DELETE');
$result = curl_exec($ch);
Return error: SignatureDoesNotMatch
I'm trying to implement a simple function to delete images in AWS, without having to load the entire SDK.
The Canonicalized Resource in Signature Version 2 Query String authentication is /${bucket}/${key}.
$to_sign = "DELETE\n\n\n$t\n/myimage.jpg"; # incorrect
$to_sign = "DELETE\n\n\n$t\n/mybucket/myimage.jpg"; # correct
Note also that you may need to make some url-escaped substitutions in your signature:
+ becomes %2B
/ becomes %2F
= becomes %3D
Note also that because you are using Signature V2, this code will only work in regions where S3 was deployed before Signature V4 became standard in 2014.
deleteAWS4( "myBucket", "myimage.jpg");
function deleteAWS4( $bucket, $fileName ){
$auth['AccessKeyId'] = "XXXXXXXXXXXXXXXXXXXX";
$auth['secretKey'] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$region = "us-west-1";
$date = gmdate("D, d M Y H:i:s")." +0000";
$params = array();
$params['AWSAccessKeyId'] = $auth['AccessKeyId'];
$params['SignatureMethod'] = 'hmac-sha1';
$params['SignatureVersion'] = '2';
$params['Timestamp'] = $date;
uksort($params, 'strcmp'); $params_str = '';
foreach ($params as $key => $val){
$params_str .= rawurlencode($key).'='.rawurlencode($val).'&';
}
$params_str = str_replace('%7E', '~',$params_str); $params_str = substr($params_str, 0, -1);
$t=time()+60;
$to_sign = "DELETE\n\n\n$t\n/$fileName";
$signature = base64_encode( hash_hmac('sha1', utf8_encode( $to_sign ) , $auth['secretKey'], true) );
$url = "https://$bucket.s3-us-west-1.amazonaws.com/$fileName?AWSAccessKeyId={$params['AWSAccessKeyId']}&Signature=$signature&Expires=$t";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//curl_setopt($ch, CURLOPT_HTTPHEADER, false);
//curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $to_sign);
//curl_setopt($ch, CURLINFO_HEADER_OUT, true);
// get the result
$result = curl_exec($ch); // raw result
$info = curl_getinfo($ch);
// turn the xml response into an array
$result = json_decode(json_encode(simplexml_load_string($result)),true);
echo $url.'<br>';
echo "<pre>"; print_r($result); echo "</pre>";
echo "<pre>"; print_r($info['request_header']); echo "</pre>";
}
I'm trying to access the PayPal ButtonManager API. I'm getting error 10002, Authentication failed. I've double/triple checked all the credentials, and regenerated them too. I don't think the AppID should be necessary; it doesn't work with or without it anyway.
Exact error message text:
L_ERRORCODE0=10002&L_SHORTMESSAGE0=Authentication/Authorization Failed&L_LONGMESSAGE0=You do not have permissions to make this API call&L_SEVERITYCODE0=Error
//ButtonManager API
$ret = ch_post();
error_log($ret);
echo urldecode($ret);
function ch_post(){
//API Credentials
$accID = urlencode("accID");
$username = urlencode("username_api1.website");
$password = urlencode("password");
$signature = urlencode("signature");
$appID = urlencode("APP-ID");
$endpoint = "https://api-3t.sandbox.paypal.com/nvp";
$certpath = "C:\certpath.pem";
$ch_headers = array(
"USER"=>$username,
"PWD"=>$password,
"SIGNATURE"=>$signature,
"APPID"=>$appID,
"VERSION"=>"51.0"
);
$ch_params = array(
"METHOD"=>urlencode("BMCreateButton"),
"OTHERPARAMS"=>urlencode("OTHER")
);
$ch = curl_init($endpoint);
curl_setopt($ch,CURLOPT_HTTPHEADER,http_build_query($ch_headers));
curl_setopt($ch,CURLOPT_CAINFO,$certpath);
curl_setopt($ch,CURLOPT_POSTFIELDS,http_build_query($ch_params));
curl_setopt($ch,CURLOPT_POST,TRUE);
curl_setopt($ch,CURLOPT_HEADER,TRUE);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch,CURLOPT_SSLVERSION, 6);
$cexec = curl_exec($ch);
if(!$cexec) {
$response = "Failed: ".curl_error($ch)."(".curl_errno($ch).")";
curl_close($ch);
return $response;
}
curl_close($ch);
return $cexec;
}
I have the script below written in Ruby. I was wondering is anyone can help me convert it to PHP. I know this is a big ask. I am looking to convert the ruby script to a PHP curl request.
See the link to the documentation https://www.sinch.com/docs/rest-apis/api-documentation/#applicationsignedrequest
The first code is the SAMPLE ruby script. While the second below it is what i have attempted to write in PHP on my own. Without success because i get "Invalid signature error".
require "base64"
require "openssl"
require "time"
require "net/http"
require "uri"
require "json"
to = "+4412345678"
message = "Test sms message"
key = "wwwwwwwwwxxxxxxxx" //Key as supplied by sinch.com
secret = "zzzzzzzyyyyyyyyy" // Secret as supplied by sinch.com
body = "{\"message\":\"" + message + "\"}"
timestamp = Time.now.iso8601
http_verb = "POST"
path = "/v1/sms/" + to
scheme = "Application"
content_type = "application/json"
digest = OpenSSL::Digest.new('sha256')
canonicalized_headers = "x-timestamp:" + timestamp
content_md5 = Base64.encode64(Digest::MD5.digest(body.encode("UTF-8"))).strip
string_to_sign = http_verb + "\n" + content_md5 + "\n" + content_type + "\n" + canonicalized_headers + "\n" + path
signature = Base64.encode64(OpenSSL::HMAC.digest(digest, Base64.decode64(secret), string_to_sign.encode("UTF-8"))).strip
authorization = "Application " + key + ":" + signature
uri = URI.parse("https://messagingApi.sinch.com" + path)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
headers = {"content-type" => "application/json", "x-timestamp" => timestamp, "authorization" => authorization}
request = Net::HTTP::Post.new(uri.request_uri)
request.initialize_http_header(headers)
request.body = body
puts JSON.parse(http.request(request).body)
Below is my script and i have no problem accepting an entirely new script. I am a super ruby rookie. Please help.
$to="+4412345678";
$text="Hello there test message";
$curl_post_data = array(
'Message' => $text
);
$curl_post_data=json_encode($curl_post_data);
$timestamp=date("c");
$key = "wwwwwwwwwwwxxxxxxxxxxx";
$secret = "zzzzzzzzzzzzyyyyyyyyyyy";
$http_verb="POST";
$path = "/v1/sms/".$to."";
$scheme = "Application ";
$content_type = "application/json";
$canonicalized_headers = "x-timestamp:".$timestamp."";
$content_md5=base64_encode( md5($curl_post_data,true) );
$string_to_sign = array(
'http_verb' => $http_verb,
'content_md5' => $content_md5,
'content_type' => $content_type,
'canonicalized_headers' =>$canonicalized_headers
);
$signature = hash_hmac("sha256", $secret,json_encode($string_to_sign));
$authorization = "".$scheme."".$key.":".$signature."";
$service_url = 'https://messagingapi.sinch.com/v1/sms/'.$to.'';
$curl = curl_init($service_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json; charset=UTF-8', 'x-timestamp: '.$timestamp.'','authorization: '.$authorization.''));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post_data);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$curl_response = curl_exec($curl);
$response = json_decode($curl_response);
curl_close($curl);
var_dump($response);
?>
Any help will do please, Stackoverflow has been a useful resource whenever am stuck with something, i hope my question helps others too.
I got it to work, had to rewrite a few things. Anyway, here's a working code for anyone that might need it.
<?php
$to="+4412345678";
$text2="Test sms message from PHP";
$curl_post_data = array(
'message' => $text2
);
$timestamp=date("c");
$key = "wwwwwwwwwwwwwxxxxxxxxxxxxxxx";
$secret ="zzzzzzzzzzzzyyyyyyyyyyyyyy";
$http_verb="POST";
$path = "/v1/sms/".$to."";
$scheme = "Application";
$content_type = "application/json";
$canonicalized_headers = "x-timestamp:".$timestamp."";
$content_md5=md5(json_encode($curl_post_data),true);
$string_to_sign ="".$http_verb."\n".$content_md5."\n".$content_type."\n".$canonicalized_headers."\n".$path."\n";
$signature = hash_hmac("sha256", base64_encode($secret),utf8_encode($string_to_sign) true);
$signature=base64_encode($signature);
$authorization = "".$scheme."".$key.":".$signature."";
$curl_post_data=json_encode($curl_post_data);
$service_url = 'https://messagingapi.sinch.com/v1/sms/'.$to.'';
$curl = curl_init($service_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json; charset=UTF-8','x-timestamp:'.$timestamp.'','authorization:'.$authorization.''));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post_data);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$curl_response = curl_exec($curl);
$response = json_decode($curl_response);
curl_close($curl);
var_dump($response);
?>
Completely working code. Also, thanks to 'Stephen' for basical porting from Ruby to PHP. It saves me a lot of time.
Some notes:
Key should be copied from apps menu of sinch account as is (without any conversion)
String to sign shouldn't contain new line at the end. Also, please check every changes by setting default values from commented code.
In the PHP hash_hmac function cody should be defined before secret (in Ruby arguments should be defined in other order)
If actual headers will contain charset definition - string_to_sign should contain it too. I have deleted them at all.
$key = 'key';
$secret = 'secret';
$message = 'your message';
$phone = '+000000000000';
$body = json_encode(array('message'=>$message));
$timestamp = date("c");
// {{{ test values for checking code (from docs)
/*
$phone="+46700000000";
$key = "5F5C418A0F914BBC8234A9BF5EDDAD97";
$secret ="JViE5vDor0Sw3WllZka15Q==";
$timestamp='2014-06-04T13:41:58Z';
$body = '{"message":"Hello world"}';
*/
// result:
// content-md5 should be 'jANzQ+rgAHyf1MWQFSwvYw=='
// signature should be 'qDXMwzfaxCRS849c/2R0hg0nphgdHciTo7OdM6MsdnM='
// }}}
$path = "/v1/sms/" . $phone;
$content_type = "application/json";
$canonicalized_headers = "x-timestamp:" . $timestamp;
$content_md5 = base64_encode( md5( utf8_encode($body), true ));
$string_to_sign =
"POST\n".
$content_md5."\n".
$content_type."\n".
$canonicalized_headers."\n".
$path;
$signature = base64_encode(hash_hmac("sha256", utf8_encode($string_to_sign), base64_decode($secret), true));
$authorization = "Application " . $key . ":" . $signature;
$curl_post_data=json_encode($curl_post_data);
$service_url = 'https://messagingapi.sinch.com'.$path;
$curl = curl_init($service_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'content-type: '.$content_type,
'x-timestamp:' . $timestamp,
'authorization:' . $authorization
));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post_data);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$curl_response = curl_exec($curl);
// #todo: checking response / working with results
curl_close($curl);