title: Using the new Coinbase Key + Secret, I can't create a valid ADDRESS_SIGNATURE. What's wrong with this code?
body: <p>I'm modifying the current Coinbase Php Gem to use the new Key+Secret API authentication.  I think I'm following their instructions perfectly, but I always get a response: <code>"error":"ACCESS_SIGNATURE does not validate"</code></p>
  
  <p>So far, I have:</p>
  
  <ul>
  <li>Confirmed that the signature is a lowercase hex hash</li>
  <li>Confirmed from the CB callback that my access key is accepted</li>
  <li>Confirmed from the CB callback that my nonce is valid</li>
  <li>Confirmed that my API Secret Key is correct</li>
  </ul>
  
  <p>My test is a POST request to <code>https://coinbase.com/api/v1/buttons</code> with a few $params.  It worked using the old API method.  I'm not sure what I'm doing wrong under this new API method.</p>
  
  <p>Here's the modified Coinbase_Rpc::request method:</p>
  
  <pre><code>public function request($method, $url, $params)
  {
      if ($this-&gt;_apiKey === null) {
          throw new Coinbase_ApiException("Invalid API key", 500, "An invalid API key was provided.");
      }
  
      $url   = Coinbase::API_BASE . $url;
      $nonce = (int)(microtime(true) * 100);
  
      // Create query string
      $queryString = http_build_query($params);
  
      // Initialize CURL
      $curl     = curl_init();
      $curlOpts = array();
  
      // HTTP method
      $method = strtolower($method);
      if ($method == 'get') {
          $curlOpts[CURLOPT_HTTPGET] = 1;
          $url .= "?" . $queryString;
      } else if ($method == 'post') {
          $curlOpts[CURLOPT_POST]       = 1;
          $curlOpts[CURLOPT_POSTFIELDS] = $queryString;
      } else if ($method == 'delete') {
          $curlOpts[CURLOPT_CUSTOMREQUEST] = "DELETE";
          $url .= "?" . $queryString;
      } else if ($method == 'put') {
          $curlOpts[CURLOPT_CUSTOMREQUEST] = "PUT";
          $curlOpts[CURLOPT_POSTFIELDS]    = $queryString;
      }
  
      // Headers
      $headers = array(
          'User-Agent: CoinbasePHP/v1',
          'Accept: */*',
          'Connection: close',
          'Host: coinbase.com',
          'ACCESS_KEY: ' . $this-&gt;_apiKey,
          'ACCESS_NONCE: ' . $nonce,
          'ACCESS_SIGNATURE: ' . hash_hmac("sha256", $nonce . $url, $this-&gt;_apiSecret)
      );
  
      // CURL options
      $curlOpts[CURLOPT_URL]            = $url;
      $curlOpts[CURLOPT_HTTPHEADER]     = $headers;
      $curlOpts[CURLOPT_CAINFO]         = dirname(__FILE__) . '/ca-coinbase.crt';
      $curlOpts[CURLOPT_RETURNTRANSFER] = true;
  
      // Do request
      curl_setopt_array($curl, $curlOpts);
      $response = $this-&gt;_requestor-&gt;doCurlRequest($curl);
  
      // Decode response
      try {
          $json = json_decode($response['body']);
      } catch (Exception $e) {
          throw new Coinbase_ConnectionException("Invalid response body", $response['statusCode'], $response['body']);
      }
      if ($json === null) {
          throw new Coinbase_ApiException("Invalid response body", $response['statusCode'], $response['body']);
      }
      if (isset($json-&gt;error)) {
          throw new Coinbase_ApiException($json-&gt;error, $response['statusCode'], $response['body']);
      } else if (isset($json-&gt;errors)) {
          throw new Coinbase_ApiException(implode($json-&gt;errors, ', '), $response['statusCode'], $response['body']);
      }
  
      return $json;
  }
  </code></pre>
  
  <p>Any ideas?</p>
  
  <hr>
  
  <p>EDIT:  Though not modified above, it is fixed, and the full PHP Gem is available here: <a href="https://github.com/Luth/CoinbasePhpGem" rel="nofollow">https://github.com/Luth/CoinbasePhpGem</a></p>