Getting 401 Unauthorized message: Invalid signature

Hello, I’m developping in php and this is my function:

            $body = [
                'type' => 'send',
                'to' => $address,
                'amount' => $amount,
                'currency' => $currency,
                'idem' => uniqid('CB-SENT-')
            ];

            try {
                $client = new \GuzzleHttp\Client();
                $account_id = $this->getAccountId($client, $currency);
                $path = '/v2/accounts/' . $account_id . '/transactions';
                $time = time();
                $signature = $this->signature(false, $path, $time, $body, 'POST');

                if ($account_id == null) {
                    // Crypto account not found
                    $this->addFlash('notice', 'We could not send you crypto. Please wait while for an operation proceed');
                    return $this->redirectToRoute('cryptoexchange');
                }

                $response = $client->request('POST', 'https://api.coinbase.com' . $path, [
                    'headers' => [
                        'Content-Type' => 'application/json',
                        'CB-ACCESS-KEY' => $this->key,
                        'CB-ACCESS-SIGN' => $signature,
                        'CB-ACCESS-TIMESTAMP' => $time,
                        'CB-VERSION' => '2022-03-28',
                    ]
                ]);

                $body = json_decode($response->getBody(), true);
                dd($body);
            } catch (\Throwable $th) {
                dd($th);
            }

And my signature function is:

    public function signature(bool $cbPro, string $request_path, $timestamp, $body = '', $method = 'GET')
    {
        $body = is_array($body) ? json_encode($body) : $body;
        $what = $timestamp . $method . $request_path . $body;
        if ($cbPro)
            return base64_encode(hash_hmac("sha256", $what, base64_decode($this->secret)));
        else
            return hash_hmac('SHA256', $what, $this->secret);
    }

Whether the $cbPro bool in the signature is true or not, i always get an invalid signature error when sending crypto. But the getAccountId() works and they have same signatures.

    public function getAccountId(\GuzzleHttp\Client $client, string $currency): string | null
    {
        try {
            $path = '/v2/accounts/' . $currency;
            $time = time();
            $signature = $this->signature(false, $path, $time);
            $response = $client->request('GET', 'https://api.coinbase.com' . $path, [
                'headers' => [
                    'Content-Type' => 'application/json',
                    'CB-ACCESS-KEY' => $this->key,
                    'CB-ACCESS-SIGN' => $signature,
                    'CB-ACCESS-TIMESTAMP' => $time,
                    'CB-VERSION' => '2022-03-28',
                ]
            ]);

            $body = json_decode($response->getBody(), true);
            return $body['data']['id'];
        } catch (\Throwable $th) {
            // dd($th);
            return null;
        }
    }

I am sorry that my message is long but can i know what it the problem with my function ? Which “code” is better for sending crypto please

1 Like

Hello @Asmitta. Thank you for taking an interest in trying out Coinbase APIs. For the details regarding your concern, we will check on this for you with our team. We will get back to you once we have more information. Keep in touch!

2 Likes

Hello @Asmitta, first of all, welcome to the forum! Thank you for taking an interest in trying out Coinbase APIs. We’d like you to try something out. Can you remove this entire line?

$body = is_array($body) ? json_encode($body) : $body;

This is so you can use the string version of the array containing the arguments for your POST request. From our working code, this addressed a previous “invalid signature” error where we had to remove our JSON.parse() function in JavaScript.

2 Likes

Thanks for the reply.
When i comment this line i get : Warning: Array to string conversion so i put it back.
I spent some time reading the code and i noticed that i was adding $body to the signature but i was not addingthat $body in the request as ‘body’ parameters.
Adding 'body' => json_encode($body) as parameter after the ‘header’ resolve the problem. e.g:

                $response = $client->request('POST', 'https://api.coinbase.com' . $path, [
                    'headers' => [
                        'Content-Type' => 'application/json',
                        'CB-ACCESS-KEY' => $this->key,
                        'CB-ACCESS-SIGN' => $signature,
                        'CB-ACCESS-TIMESTAMP' => $time,
                        'CB-VERSION' => '2022-03-28',
                    ],
                    'body' => json_encode($body)  // The missing line
                ]);

We can therefore says that the signature function of coinbase api in php can be :slight_smile:

    public function signature(string $path, int $timestamp, string $method = 'GET', ?array $body = []): string
    {
        $body = is_array($body) ? json_encode($body) : $body;
        $what = $timestamp . $method . $path . $body;
        return hash_hmac('SHA256', $what, $this->secret);
    }

Thanks again.
But please, is there a sandbox for this api ? I’m not finding it
i don’t see the “Mark as resolved” button…

Hi @Asmitta thank you so much for this contribution of yours. We are glad that to know that the signature function of yours in PHP is working and that you’ve figured out the solution to the invalid signature error.

Regarding Sandboxes, we regret to inform you that only Coinbase Pro and Exchange have sandboxes as of this moment. You may want to try exploring these APIs by visiting our documentation. Please note that the two are interchangeable, thus the same documentation. And that the only difference between them are their intended users: Pro is for individuals while Exchange is for institutional accounts. Since you already have an account with Coinbase, you may start with Coinbase Pro. For the use cases explicitly available in your code which are sending cryptocurrency to a crypto address and getting account details, both of these are available via Coinbase Pro as well.

For more information about them you may look into their API references:

With this API, you will then be able to use our sandboxes which you can learn more about here.

Again, we’d like to extend our gratitude for your contribution and may you continue doing so so that you may be able to help other developers here in this forum.

3 Likes