I'm trying to generate a shopify multipass token in Perl but keep getting invalid request responses. My customer data consists of :
{"email": "randomEmail@gmail.com", "last_name": "last_name", "first_name": "first_name"}
Things I've certified as valid:
Here is the current implementation I have
sub generate_multipass_token {
use JSON qw(encode_json);
use MIME::Base64 qw(encode_base64);
use Digest::SHA qw(sha256 hmac_sha256);
use Crypt::CBC;
use Crypt::Cipher::AES;
use POSIX qw(strftime);
use Encode qw(encode);
my ($customer_data) = @_;
my $store_api_key = '';
my $store_url = '';
my $hash = sha256($store_api_key);
my $encryption_key = substr($hash, 0, 16);
my $signing_key = substr($hash, 16, 16);
my ($sec, $min, $hour, $day, $mon, $year) = gmtime();
my $formatted_time = sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ", $year+1900, $mon+1, $day, $hour, $min, $sec);
# Add the formatted time to the customer data
$customer_data->{created_at} = $formatted_time;
# JSON-encode the customer data
my $json_customer_data = encode_json($customer_data);
# Encrypt the customer data using AES
my $iv = Crypt::CBC->random_bytes(16);
my $cipher = Crypt::CBC->new(
-key => $encryption_key,
-iv => $iv,
-cipher => 'Cipher::AES',
-header => 'none',
);
my $encrypted_data = $cipher->encrypt($json_customer_data);
$encrypted_data = $iv . $encrypted_data;
my $signature = hmac_sha256($encrypted_data, $signing_key);
my $token = encode_base64url($encrypted_data . $signature);
return "$store_url/account/login/multipass/" . $token;
}
sub encode_base64url {
my $data = shift;
my $encoded = encode_base64($data, '');
$encoded =~ tr{+/}{-_};
$encoded =~ s/=+$//;
return $encoded;
}
I have used python's spylib to test the store information and was able to generate a valid token there, when comparing variables, the token length ends up to the same length (commenting out the time to check this).
I'm not sure where I'm going wrong, the php equivalent https://shopify.dev/docs/api/multipass is very similar to my implementation. I'm thinking it might be something with the encryption but can't tell what.
Change needed was:
my $cipher = Crypt::CBC->new(
-key => $encryption_key,
-iv => $iv,
-cipher => 'OpenSSL::AES',
-header => 'none',
-literal_key => 1,
-keysize => 128/8
);