phpadobe-sign

Why do I get Error 400 Bad Request "INVALID_X_API_USER_HEADER" while trying to call the AdobeSign API?


Introduction: Currently, I'm developing an app (in laravel-backpack) with a formulary you can check out in the next image: formulary_of_my_app

I'm trying to use the API of Adobe Sign (the objective of this app is to ease the process of signing contracts, making it automatic just by adding the PDF and clicking the "Firmar" button (Firmar = Sign), and this will send the PDF). I have everything I need (Developer Account, IntegrationKey, SecretKey, UserId, Access-Token, etc...) to call the API.

Error I got: But I have this problem where It says that the "API-USER-HEADER" is invalid because the value provided is in invalid format. In the next image you check out the error: error_invalid_x_api_user

Php Code (here goes the code that I'm using to call the API):

<?php

namespace App\Services;

use GuzzleHttp\Client;

class AdobeSign
{
    private $client;
    private $baseUrl;
    private $integrationKey;
    private $secretKey;
    private $userId;

    public function __construct()
    {
        $this->client = new Client();
        $this->baseUrl = "https://api.eu1.echosign.com/api/rest/v6";/*URL DE LA API*/
        $this->integrationKey = env('ADOBE_SIGN_INTEGRATION_KEY');/*De la cuenta de Adobe Sign*/
        $this->secretKey = env('ADOBE_SIGN_SECRET_KEY');/*De la cuenta de Adobe Sign*/
        $this->userId = env('ADOBE_SIGN_USER_ID');/*De la cuenta de Adobe Sign*/
    }

    private function getAuthorizationHeader()
    { 
        $headers = [
            'Content-Type' => 'application/json',
            'Access-Control-Allow-Origin' => '*',
            'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS',
            'Authorization' => sprintf('Bearer %s', env('ADOBE_SIGN_TOKEN')),
            'x-api-user' => base64_encode(json_encode([
                'email' => 'email@domain.domain',
                'firstName' => 'name',
                'lastName' => 'secondName',
                'groupIds' => [env('ADOBE_SIGN_GROUP_ID')],
                'userId' => env('ADOBE_SIGN_USER_ID')
            ])),
        ];

        $timeStamp = time();
        //$headers['x-api-user'] = sprintf('{"userId":"%s"}', $this->userId);
        $headers['x-sdk-date'] = gmdate('D, d M Y H:i:s T', $timeStamp);
        
        print_r($headers);
        echo(base64_encode(json_encode($headers)));
        //$headers['x-api-user'] = base64_encode(json_encode($headers));
        return $headers;
    }

    private function getAccessToken($timeStamp)
    {
        $jwtPayload = [
            'iss' => $this->integrationKey,
            'sub' => base64_encode(json_encode(env('ADOBE_SIGN_USER_EMAIL'))),
            'aud' => 'https://api.eu1.echosign.com',
            'exp' => $timeStamp + 3600,
            'iat' => $timeStamp
        ];

        $jwtHeader = [
            'alg' => 'HS256',
            'typ' => 'JWT'
        ];

        $jwtHeaderEncoded = base64_encode(json_encode($jwtHeader));
        $jwtPayloadEncoded = base64_encode(json_encode($jwtPayload));
        $jwtSignatureEncoded = base64_encode(hash_hmac('sha256', "$jwtHeaderEncoded.$jwtPayloadEncoded", $this->secretKey, true));

        $jwtToken = "$jwtHeaderEncoded.$jwtPayloadEncoded.$jwtSignatureEncoded";

        return $jwtToken;
    }

    public function sendAgreement($name, $email, $fileUrl, $X, $Y, $page)
    {
        $response = $this->client->post($this->baseUrl . '/agreements', [
            'headers' => $this->getAuthorizationHeader(),
            'json' => [
                'documentCreationInfo' => [
                    'fileInfos' => [/*Documento pdf INFO*/
                        [
                            'libraryDocumentId' => '',/*Se utiliza si ya esta en la biblioteca*/
                            'transientDocumentId' => '',/*Se utiliza si el archivo aún no se ha subido a la biblioteca*/
                            'documentURL' => $fileUrl,/*URL DEL ARCHIVO*/
                            'name' => $name/*nombre del archivo*/
                        ]
                    ],
                    'recipientSetInfos' => [/*Destinatario INFO*/
                        [
                            'recipientSetMemberInfos' => [/*Info, por si se quieren añadir mas de un destinatario */
                                [
                                    'email' => $email/*Email del destinatario*/
                                ]
                            ],
                            'recipientSetRole' => 'SIGNER'/*ROL DEL DESTINATARIO [SIGNER :=: Firmar el acuerdo]*/
                        ]
                    ],
                    'signatureType' => 'ESIGN', /*TIPO DE FIRMA QUE SE UTILIZARÁ [ESIGN :=: Puede firmar el acuerdo digitalmente]*/
                    'signatureFlow' => 'SENDER_SIGNATURE_NOT_REQUIRED',/*FLUJO DE LA FIRMA [SENDER_SIGNATURE_NOT_REQUIRED :=: El que lo envia necesita firmar el acuerdo]*/
                    'name' => $name,/*NOMBRE DEL ACUERDO QUE SE VA A FIRMAR */
                    'signatureFieldInfos' => [
                        [
                            'defaultValue' => '',
                            'locations' => [
                                [
                                    'height' => $Y,
                                    'left' => $X,
                                    'pageNumber' => $page,
                                    'top' => '50',
                                    'width' => '100'
                                ]
                            ],
                            'name' => 'Signature'
                        ]
                    ]
                ]
            ]
        ]);
    }
}

What have I already tried?: I navigated a bunch of webs that related to this error and checked out the Adobe documentation, but I'm still stuck. Also, I tried changing the code (It didn't make a difference) and tested If It really responded the API in this AdobeSign link. When I tested in the AdobeSign link that I have provided, I got this result: test_adobe_sign_1 and test_adobe_sign_2"

It really works as you can see in the image because is giving back the "Response Body", but in my code something is missing or I did something wrong.


Solution

  • UPDATE "solution": I did not understand the Adobe Sign documentation well. The main problem was that I was writing literally userid:{userId} OR email:{email.com} when the correct way is userid:1234 OR email:email.com (you don't need the {}).

    Also, I was providing a base64 encoded-version of a JSON array with 5 properties that were unnecessaries, I only needed the userid:{userId} OR email:{email}.

    Thanks CBroe for the comments and help.

    <?php
    
    namespace App\Services;
    
    use GuzzleHttp\Client;
    
    class AdobeSign
    {
        private $client;
        private $baseUrl;
        private $integrationKey;
        private $secretKey;
        private $userId;
    
        public function __construct()
        {
            $this->client = new Client();
            $this->baseUrl = "https://api.eu1.echosign.com/api/rest/v6";/*URL DE LA API*/
            $this->integrationKey = env('ADOBE_SIGN_INTEGRATION_KEY');/*De la cuenta de Adobe Sign*/
            $this->secretKey = env('ADOBE_SIGN_SECRET_KEY');/*De la cuenta de Adobe Sign*/
            $this->userId = env('ADOBE_SIGN_USER_ID');/*De la cuenta de Adobe Sign*/
        }
    
        private function getAuthorizationHeader()
        { 
            $headers = [
                'Content-Type' => 'application/json',
                'Access-Control-Allow-Origin' => '*',
                'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS',
                'Authorization' => sprintf('Bearer %s', env('ADOBE_SIGN_TOKEN')),
                'x-api-user' => 'email:mail@mail.com'
            ];
    
            $timeStamp = time();
            $headers['x-sdk-date'] = gmdate('D, d M Y H:i:s T', $timeStamp);
            
            print_r($headers);
            echo(base64_encode(json_encode($headers)));
            return $headers;
        }
    
        private function getAccessToken($timeStamp)
        {
            $jwtPayload = [
                'iss' => $this->integrationKey,
                'sub' => base64_encode(json_encode(env('ADOBE_SIGN_USER_EMAIL'))),
                'aud' => 'https://api.eu1.echosign.com',
                'exp' => $timeStamp + 3600,
                'iat' => $timeStamp
            ];
    
            $jwtHeader = [
                'alg' => 'HS256',
                'typ' => 'JWT'
            ];
    
            $jwtHeaderEncoded = base64_encode(json_encode($jwtHeader));
            $jwtPayloadEncoded = base64_encode(json_encode($jwtPayload));
            $jwtSignatureEncoded = base64_encode(hash_hmac('sha256', "$jwtHeaderEncoded.$jwtPayloadEncoded", $this->secretKey, true));
    
            $jwtToken = "$jwtHeaderEncoded.$jwtPayloadEncoded.$jwtSignatureEncoded";
    
            return $jwtToken;
        }
    
        public function sendAgreement($name, $email, $fileUrl, $X, $Y, $page)
        {
            $response = $this->client->post($this->baseUrl . '/agreements', [
                #HEADER
                'headers' => $this->getAuthorizationHeader(),
                #BODY
                'json' => [
                    'documentCreationInfo' => [
                        'fileInfos' => [/*Documento pdf INFO*/
                            [
                                'libraryDocumentId' => '',/*Se utiliza si ya esta en la biblioteca*/
                                'transientDocumentId' => '',/*Se utiliza si el archivo aún no se ha subido a la biblioteca*/
                                'documentURL' => $fileUrl,/*URL DEL ARCHIVO*/
                                'name' => $name/*nombre del archivo*/
                            ]
                        ],
                        'recipientSetInfos' => [/*Destinatario INFO*/
                            [
                                'recipientSetMemberInfos' => [/*Info, por si se quieren añadir mas de un destinatario */
                                    [
                                        'email' => $email/*Email del destinatario*/
                                    ]
                                ],
                                'recipientSetRole' => 'SIGNER'/*ROL DEL DESTINATARIO [SIGNER :=: Firmante]*/
                            ]
                        ],
                        'signatureType' => 'ESIGN', /*TIPO DE FIRMA QUE SE UTILIZARÁ [ESIGN :=: Puede firmar el acuerdo digitalmente]*/
                        'signatureFlow' => 'SENDER_SIGNATURE_NOT_REQUIRED',/*FLUJO DE LA FIRMA [SENDER_SIGNATURE_NOT_REQUIRED :=: El que lo envia necesita firmar el acuerdo]*/
                        'name' => $name,/*NOMBRE DEL ACUERDO QUE SE VA A FIRMAR */
                        'signatureFieldInfos' => [
                            [
                                'defaultValue' => '',
                                'locations' => [
                                    [
                                        'height' => $Y,
                                        'left' => $X,
                                        'pageNumber' => $page,
                                        'top' => '50',
                                        'width' => '100'
                                    ]
                                ],
                                'name' => 'Signature'
                            ]
                        ]
                    ]
                ]
            ]);
        }
    }