I tried to decode the given token with the code below. The key is supposed to be base64 encoded. However when I attempt to decode it tells me I have invalid signature. The token is generated from a system using Java and I have to decode it in PHP.
Token:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyZXN1bHQiOiJzdWNjZWVkZWQiLCJpc3MiOiJ4eXoubmUuanAiLCJwcm9maWxlSWRlbnRpZmllciI6IioqKioqKio0NTY3IiwiZXhwIjoxNTk3MjAxNzQyLCJub25jZSI6ImRlNTRlODE3YmQ4NjM4MTI5ZWQ2ZDkxNDA1YTkwMTUyYWIzNTE4N2NkYWMxMDIxNmQ5NWI5NmUzYjgyMjAxNTFhZmU0ZDE4NWZlMzYzNTExNWMwNDFhOWY4OTNjMGZmMGFmZjFkYzBjODgyMDhmMjEwN2ZlMzk5Mzg3ZDMzZGMyZTllY2E5ODA0NDNmZjJiNjZiZDM1ZDk1YjAzY2ExMjIiLCJyZWZlcmVuY2VJZCI6IlRFU1QxMjM1ZjMzNTc3MzBlYjcxIn0.fvEsTg6OcCx2iBPMP-7e9AZtEviDqAEfTMZJib7UVQg
Decoding script
use \Firebase\JWT\JWT;
$encodedString = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyZXN1bHQiOiJzdWNjZWVkZWQiLCJpc3MiOiJ4eXoubmUuanAiLCJwcm9maWxlSWRlbnRpZmllciI6IioqKioqKio0NTY3IiwiZXhwIjoxNTk3MjAxNzQyLCJub25jZSI6ImRlNTRlODE3YmQ4NjM4MTI5ZWQ2ZDkxNDA1YTkwMTUyYWIzNTE4N2NkYWMxMDIxNmQ5NWI5NmUzYjgyMjAxNTFhZmU0ZDE4NWZlMzYzNTExNWMwNDFhOWY4OTNjMGZmMGFmZjFkYzBjODgyMDhmMjEwN2ZlMzk5Mzg3ZDMzZGMyZTllY2E5ODA0NDNmZjJiNjZiZDM1ZDk1YjAzY2ExMjIiLCJyZWZlcmVuY2VJZCI6IlRFU1QxMjM1ZjMzNTc3MzBlYjcxIn0.fvEsTg6OcCx2iBPMP-7e9AZtEviDqAEfTMZJib7UVQg";
$key = base64_encode("testing1234453656347nsmvfdbsrtgjnfsjhNJFDJFujragrg");
$decoded = JWT::decode($encodedString, $key, array('HS256'));
It decodes just fine on jwt.io with the secret base64 encoded option selected. What am I doing wrong here?
When the key is already Base64 encoded, you have to decode it before you pass it to JWT::decode:
$key = base64_decode("testing1234453656347nsmvfdbsrtgjnfsjhNJFDJFujragrg");
This is what JWT.io is doing when the checkbox "secret base64 encoded" is checked.
It literally means: "the secret in the input field is base64 encoded and therefore needs to be decoded".
And I can confirm that the tokens signature can be verified with this secret and "secret base64 encoded" checked.
The token is generated from a system using Java and I have to decode it in PHP.
This should generally be irrelevant. JWT is based on language independent standards.
Related
I am working on a simple SOAP request from a server in PHP, using the standard SOAP library calls. I do not have the required username and password for authorization; however, I do have the base64-encoded authorization string (from a database) that encoding the username and password would provide. I don't seem to be able to find an example that uses the already-encoded authorization string. Is there a) a technique I can use that allows and transmits the pre-encoded string, and/or b) a function that allows me to parse out the username and password from the encoded string so I can pass those as params?
TIA for any help you can offer!
I figured out the answer:
The base-64 encoded string is simply the login and password encoded. I just decoded the string using base64_decode and split the string on the semicolon (:) symbol. Here's what the code looks like -
$loginAry = split(":", base64_decode(my_encoded_string_here));
$login = $loginAry[0];
$pwd = $loginAry[1];
and used the decoded values to log into the application. Simple as that.
We're just upgrading to form v3.0 and whilst doing so, refactoring our code.
Whilst doing so, we noticed that when using http_build_query which takes an associative array and converts it into an RFC1738 valid URL, that SagePay fails with the following error:
The SuccessURL format is invalid
The form submitting to the SagePay endpoint has an enctype of application/x-www-form-urlencoded.
However... If we manually build the string to encrypt by doing:
$tmp = '';
foreach ($crypt_store as $key => $value) {
$tmp .= sprintf('&%s=%s', $key, $value);
}
It works...
Now as I understand RFC1738, if an url exists within an url, it should be encoded, i.e.
RFC1738:
&VendorTxCode=Test&SuccessUrl=http%3A%2F%2Fwww.stackoverflow.com%3Fa%3Da%26b%3Db&FailureUrl...
SagePay:
&VendorTxCode=Test&SuccessUrl=http://www.stackoverflow.com?a=a&b=b&FailureUrl...
Surely if SagePay are following RFC1738, encoding the URL should work? Or is it because the string is encrypted which means it doesn't really matter?
Any thoughts?
Thanks
Gavin
You are correct. Because the Success / Failure URLs are encrypted within the Crypt field, there is no need to encode them.
I have a problem creating an input validation hash. JavaScript submits data to API and API validates the sent data with json_encode. Basically it works like this:
$input=array('name'='John Doe','city'=>'New York');
$validationHash=sha1(json_encode($input).$key); // Key is known to both servers
If PHP connects to another server, then everything works. It also works through JavaScript (I have a custom sha1() function there as well):
var validationHash=sha1(JSON.stringify({'name':'John Doe','city'=>'New York'})+key);
My problem comes when the string contains UTF-8 characters. For example, if one of the values is:
Ränisipelgasöösel
Then PHP server that receives the command converts it to this after JSON encoding:
R\u00e4nisipelgas\u00f6\u00f6sel
I need to do this in JavaScript as well, but I haven't been able to work out how. I need to make sure that I send proper validation hash to the server or the command fails. I found from Google that unescape(encodeURIComponent(string)) and decodeURIComponent() could be used, but neither gives me the same string that PHP has and validates with.
UTF-8 is used on both client and server.
Any ideas?
It does not seem to be possible. The only working solution I have found is to encode all data with encodeURIComponent() on browser side and with rawurlencode() on PHP side and then calculate the JSON from these values in arrays.
My fix was to raw url encode my json data like so.
rawurlencode( json_encode( $data ) );
And then from within javascript decode the raw url encoded json and then parse the json string like so.
JSON.parse( decodeURIComponent( data ) );
Hope this helps.
Why not base64 encode the data for safe transport? It encodes UTF-8 characters in a safe string that can be sent across different mediums - php, javascript etc. That way you can base64 decode the string at the receiving end. Voila!
By base64 encoding the data, i mean base64 encoding the values and not the whole json string
is you html page encoding utf-8?
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
So I am using a REST API, where the API issues a POST request to my server in JSON format. Following is the information it sends:
info: {
id: "9890dsds8",
number: 5,
amount: 33
},
sig: "8jhjbhb78979899h"
sig is a SHA1 signature of the info, this should be used to validate the post. For example, we can validate the info in Ruby with (as given in their example):
require 'json'
require 'cgi'
require 'digest/sha1'
key = "some_key"
params = CGI::parse(post_body)
digest = Digest::SHA1.hexdigest(params["info"]+key)
if digest == params["sig"]
# Valid signature
info = JSON.parse(params["info"])
# Respond with status code 200 and some unique_id
else
# Invalid signature. You should response with a non-200 response code.
end
The unique_id must be a string of UTF8 characters 50 characters in length or less and should be the only contents of the body of your response.
Though I am quite able to understand what's happening, I am not completely able to figure out everything. Mostly, may be because its in Ruby.
Can someone please help me on how to do this in PHP? I am not able to handle this JSON POST request in PHP. A PHP converted version of the snippet would be extremely appreciated. I am also not sure, how to deal with SHA1 aspects in PHP, any special knowledge required?
Thanks a lot!!
I assume that the API will populate the "response" variable in your POST array.
Then:
//Get the JSON string
$json_string = $_POST['response'];
//Decode JSON string to array
$decoded = json_decode($json_string);
//Calculate SHA1 (I am not sure how ruby is concatenating a string with an array, so I will just convert the array to string using implode).
$key = 'somekey';
$hash = sha1(implode("",$decoded['info']) . $key);
if($hash == $decoded['sig']){
//OK!
}else{
//Not OK!
}
I need to validate a signature for a callback from ankoder.com who provide the following description:
It is the URL-escaped string of Base64-encoded HMAC-SHA1 digest of your private key and the URL-unescaped message.
$passkey = urlencode(base64_encode(hash_hmac('sha1', urldecode($str), $private_key, true)));
They provide the following Ruby example
encoded_signature = CGI.escape Base64.encode64(HMAC::SHA1::digest(private_key, CGI.unescape(message))).strip
I run this on sample data I have returned from a callback but am not getting the same signature. How do I replicate the Ruby code in PHP?
Edit
The issue was trailing whitespace being sent through.
Your PHP code matches the Ruby code. The problem must be somewhere else.
Check if the key is correct and the message is parsed correctly (urldecode, then json_decode).