we-promise/sure · error · Provider::Coinbase::AuthenticationError

Unauthorized - check your API key and secret

Error message

Unauthorized - check your API key and secret

What it means

Raised by Provider::Coinbase#handle_response when the Coinbase API returns HTTP 401. The message is extract_error_message(parsed) — which reads parsed.dig("errors", 0, "message") — or the fallback "Unauthorized - check your API key and secret". Coinbase CDP keys fail auth when the key/secret pair is wrong, the key was revoked, or it belongs to a different environment (sandbox vs production).

Source

Thrown at app/models/provider/coinbase.rb:201

      "#{message}.#{encoded_signature}"
    end

    def auth_headers(method, path)
      {
        "Authorization" => "Bearer #{generate_jwt(method, path)}",
        "Content-Type" => "application/json"
      }
    end

    def handle_response(response)
      parsed = response.parsed_response

      case response.code
      when 200..299
        parsed.is_a?(Hash) ? parsed : { "data" => parsed }
      when 401
        error_msg = extract_error_message(parsed) || "Unauthorized - check your API key and secret"
        raise AuthenticationError, error_msg
      when 429
        raise RateLimitError, "Rate limit exceeded"
      else
        error_msg = extract_error_message(parsed) || "API error: #{response.code}"
        raise ApiError, error_msg
      end
    end

    def extract_error_message(parsed)
      return parsed if parsed.is_a?(String)
      return nil unless parsed.is_a?(Hash)

      parsed.dig("errors", 0, "message") || parsed["error"] || parsed["message"]
    end
end

View on GitHub (pinned to e69894adb9)

Solutions

  1. Verify the stored key and secret match an active key in the Coinbase Developer Platform (correct project and environment).
  2. Re-copy both values (watch for trailing newlines/spaces) and update the stored credential, then retry.
  3. Confirm you are hitting the right base URL for the key type (sandbox vs production).
  4. If auth still fails, create a fresh key/secret pair and swap it in.
  5. Handle Provider::Coinbase::AuthenticationError by flagging the connection for re-auth instead of dead-looping retries.

Example fix

# before
provider = Provider::Coinbase.new(api_key: key, api_secret: secret)
balance = provider.get_accounts

# after
begin
  provider = Provider::Coinbase.new(api_key: key.strip, api_secret: secret.strip)
  balance = provider.get_accounts
rescue Provider::Coinbase::AuthenticationError => e
  coinbase_account.update!(status: :reauth_required)
  Rails.logger.warn("Coinbase auth failed: #{e.message}")
end
Defensive patterns

Strategy: try-catch

Validate before calling

raise ArgumentError, "Coinbase credentials incomplete" if api_key.to_s.strip.empty? || api_secret.to_s.strip.empty?

Type guard

def coinbase_auth_error?(err)
  err.is_a?(Provider::Coinbase::AuthenticationError)
end

Try / catch

begin
  accounts = provider.get_accounts
rescue Provider::Coinbase::AuthenticationError => e
  connection.update!(status: :reauth_required)
  Rails.logger.warn("Coinbase auth failed: #{e.message}")
end

Prevention

When it happens

Trigger: Any Coinbase request with a revoked, expired, or mistyped CDP API key/secret; using a sandbox key against api.coinbase.com (or vice versa); whitespace or truncated secrets pasted from the Coinbase developer console; keys deleted when the CDP project was removed.

Common situations: Credential rotation on the Coinbase developer console without updating the stored secret; env vars overridden per-environment (test key in prod); secrets mangled by shell interpolation or YAML formatting; team members revoking old keys not knowing the app still uses them.

Understand the failure class

Related errors


AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21). Data as JSON: /api/errors/fd723c8ab9035a0c. Report an issue: GitHub.