I am trying to create an Authorized Signature with IAM to the Rekognition endpoint. It works fine in Postman using Postman's internal AWS Signature, but trying to generate the Authorization Header + Signature (in PHP) and enter it in manually is proving to be impossible.
I've taken a look at the following questions and answers in:
- Signature Version 4 Signing Process in PHP to access API Gateway endpoint
- How do you calculate an AWS signature in PHP?
- AWS Signature creation using PHP
- How do I hash the canonical request in aws4 using php to match what is expected by amazon aws sp api?
- https://github.com/avi-wish/aws4-signature-php
None of these solutions seem worked for me. What I'm trying to do is to have a PHP function that generate the Authorization Header, the Date header, ect., and to paste this into Postman to get it to return a result.
It doesn't matter what combination I try (omit payload, add payload, add param, omit params) I get:
The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
Yes I have checked the Access keys, and data is the same JSON in both PHP script and Postman -- it works with Postman's "AWS Signuature"
But below will not work?
The code I'm trying here:
function sign_request($url, $data) {
$host = 'rekognition.eu-west-2.amazonaws.com';
$access_key = '<<Acess_Key>>';
$secret_key = '<<Secret_Key>>';
$region = '<<Region>>';
$service = 'rekognition';
$current = new DateTime('UTC');
$current_date_time = $current->format('Ymd\THis\Z');
$current_date = $current->format('Ymd');
$signed_headers = [
'content-type' => 'application/x-amz-json-1.1',
'host' => $host,
'x-amz-date' => $current_date_time,
'x-amz-target' => 'RekognitionService.DetectFaces'
//'x-amz-security-token' => $token, // leave this one out if you have a IAM created fixed access key - secret pair and do not need the token.
];
$signed_headers_string = implode(';', array_keys($signed_headers));
$canonical = [
'POST',
parse_url($url, PHP_URL_PATH),
parse_url($url, PHP_URL_QUERY),
];
foreach ($signed_headers as $header => $value) {
$canonical[] = "$header:$value";
}
$canonical[] = '';
$canonical[] = $signed_headers_string;
$canonical[] = hash('sha256', http_build_query($data));
$canonical = implode("\n", $canonical);
$credential_scope = [$current_date, $region, $service, 'aws4_request'];
$key = array_reduce($credential_scope, fn ($key, $credential) => hash_hmac('sha256', $credential, $key, TRUE), 'AWS4' . $secret_key);
$credential_scope = implode('/', $credential_scope);
$string_to_sign = implode("\n", [
'AWS4-HMAC-SHA256',
$current_date_time,
$credential_scope,
hash('sha256', $canonical),
]);
$signature = hash_hmac('sha256', $string_to_sign, $key);
unset($signed_headers['host']);
$signed_headers['Authorization'] = "AWS4-HMAC-SHA256 Credential=$access_key/$credential_scope, SignedHeaders=$signed_headers_string, Signature=$signature";
return $signed_headers;
}
$requestUrl = 'https://rekognition.eu-west-2.amazonaws.com/?Action=DetectFaces';
$body = [
"Attributes"=> [
"ALL"
],
"Image"> [
"Bytes"=> "<<BASE64_of_Face_Image>>"
]
];
print_r(sign_request($requestUrl, $body ));
Am I missing something?

