Skip to content
Advertisement

Signature Version 4 Signing Process in PHP to access API Gateway endpoint

I am trying to create Authorized Signature to access IAM secured API gateway endpoint.

$alg = "SHA256";
$CanonicalRequest = "GETn/dev/petsnnhost:3r4fgts8e5.execute-api.ap-northeast-1.amazonaws.comnx-amz-date:".$dd."nnhost;x-amz-datene3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";

$CR =  str_replace("n", "", $CanonicalRequest);
            $CR = str_replace("r", "", $CR);
            $CR = strtolower($CR);




$StringToSign  = "AWS4-HMAC-SHA256n".$dd."n".$date->format( 'Ymd' )."/ap-northeast-1/execute-api/aws4_requestn".hash( $alg, $CR )."";





// 1) HMACs
$kSecret = 'AWS4' . $secret_key;
$kDate = hash_hmac( $alg, $date->format( 'Ymd' ), $kSecret, true );     
$kRegion = hash_hmac( $alg, $region, $kDate, true );
$kService = hash_hmac( $alg, $service, $kRegion, true );
$kSigning = hash_hmac( $alg, 'aws4_request', $kService, true );     
$signature = hash_hmac( $alg, $StringToSign, $kSigning );       

$authorization = array(
    'Credential=' . $access_key . '/' . implode( '/', $scope ),
    'SignedHeaders=' . implode( ';', array_keys( $can_headers ) ),
    'Signature=' . $signature,
);
$authorization = $request['algorithm'] . ' ' . implode( ',', $authorization );
$request['Authorization'] = $authorization;

But I am getting “The request signature we calculated does not match the signature you provided” error

“message”: “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.nnThe Canonical String for this request should have beenn’GETn/dev/petsnnhost:3r4fgts8e5.execute-api.ap-northeast-1.amazonaws.comnx-amz-date:20161002T231640Znnhost;x-amz-datene3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855’nnThe String-to-Sign should have beenn’AWS4-HMAC-SHA256n20161002T231640Zn20161002/ap-northeast-1/execute-api/aws4_requestn0b8c12e0a5f21137c5739a9d26056dfb081218631a9adcf37db1d2e09a014c4e’n”

My String-to-sign string is

"AWS4-HMAC-SHA256
20161002T231640Z
20161002/ap-northeast-1/execute-api/aws4_request
fb4f7ebdcb405bceed598ecc097267b929eeb3f8f075b1b7a776f53c8c8c6168"

which is totally different from what AWS expected in signature.

Advertisement

Answer

Here is the solution

private function signRequest(){
        $method ='GET';
        $uri = '/dev';
        $json = file_get_contents('php://input');
        $obj = json_decode($json);


        if(isset($obj->method))
        {
            $m = explode("|", $obj->method);
            $method = $m[0];
            $uri .= $m[1];
        }


        $secretKey = $this->session->data['aws_secret'];
        $access_key = $this->session->data['aws_key'];
        $token = $this->session->data['aws_token'];
        $region = 'ap-southeast-1';
        $service = 'execute-api';

        $options = array(); $headers = array();
        $host = "YOUR-API-HOST.execute-api.ap-southeast-1.amazonaws.com";
//Or you can define your host here.. I am using API gateway.


        $alg = 'sha256';

        $date = new DateTime( 'UTC' );

        $dd = $date->format( 'YmdTHisZ' );

        $amzdate2 = new DateTime( 'UTC' );
        $amzdate2 = $amzdate2->format( 'Ymd' );
        $amzdate = $dd;

        $algorithm = 'AWS4-HMAC-SHA256';


        $parameters = (array) $obj->data;

           if($obj->data == null || empty($obj->data)) 
        {
            $obj->data = "";
        }else{
            $param = json_encode($obj->data);
            if($param == "{}")
            {
                $param = "";

            }

        $requestPayload = strtolower($param);
        $hashedPayload = hash($alg, $requestPayload);

        $canonical_uri = $uri;
        $canonical_querystring = '';

        $canonical_headers = "content-type:"."application/json"."n"."host:".$host."n"."x-amz-date:".$amzdate."n"."x-amz-security-token:".$token."n";
        $signed_headers = 'content-type;host;x-amz-date;x-amz-security-token';
        $canonical_request = "".$method."n".$canonical_uri."n".$canonical_querystring."n".$canonical_headers."n".$signed_headers."n".$hashedPayload;


        $credential_scope = $amzdate2 . '/' . $region . '/' . $service . '/' . 'aws4_request';
        $string_to_sign  = "".$algorithm."n".$amzdate ."n".$credential_scope."n".hash('sha256', $canonical_request)."";
       //string_to_sign is the answer..hash('sha256', $canonical_request)//

        $kSecret = 'AWS4' . $secretKey;
        $kDate = hash_hmac( $alg, $amzdate2, $kSecret, true );
        $kRegion = hash_hmac( $alg, $region, $kDate, true );
        $kService = hash_hmac( $alg, $service, $kRegion, true );
        $kSigning = hash_hmac( $alg, 'aws4_request', $kService, true );     
        $signature = hash_hmac( $alg, $string_to_sign, $kSigning ); 
        $authorization_header = $algorithm . ' ' . 'Credential=' . $access_key . '/' . $credential_scope . ', ' .  'SignedHeaders=' . $signed_headers . ', ' . 'Signature=' . $signature;

        $headers = [
                    'content-type'=>'application/json', 
                    'x-amz-security-token'=>$token, 
                    'x-amz-date'=>$amzdate, 
                    'Authorization'=>$authorization_header];
        return $headers;

    }
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement