Skip to main content

Overview

The CDP Rust SDK uses JWT-based authentication to secure API requests. The WalletAuth middleware handles automatic JWT generation and header management for all requests.

WalletAuth Struct

The main authentication type that implements reqwest middleware:
use cdp_sdk::auth::WalletAuth;

Configuration Fields

api_key_id
String
required
Your CDP API key ID
api_key_secret
String
required
Your CDP API key secret (supports EC PEM keys and Ed25519 base64 keys)
wallet_secret
Option<String>
Optional wallet secret for signing transactions (base64-encoded EC key)
debug
bool
default:"false"
Enable debug logging for requests and responses
source
String
default:"sdk-auth"
Source identifier for tracking requests
source_version
Option<String>
Version of the source making requests
expires_in
u64
default:"120"
JWT expiration time in seconds

Creating WalletAuth

From Environment Variables

Load credentials from environment variables:
use cdp_sdk::auth::WalletAuth;

// Set environment variables first:
// export CDP_API_KEY_ID="your-api-key-id"
// export CDP_API_KEY_SECRET="your-api-key-secret"
// export CDP_WALLET_SECRET="your-wallet-secret"

let wallet_auth = WalletAuth::builder().build()?;

With Explicit Credentials

Pass credentials directly:
let wallet_auth = WalletAuth::builder()
    .api_key_id("your-api-key-id".to_string())
    .api_key_secret("your-api-key-secret".to_string())
    .wallet_secret("your-wallet-secret".to_string())
    .build()?;

With Custom Options

Configure additional options:
let wallet_auth = WalletAuth::builder()
    .api_key_id("your-api-key-id".to_string())
    .api_key_secret("your-api-key-secret".to_string())
    .wallet_secret("your-wallet-secret".to_string())
    .debug(true)
    .expires_in(300) // 5 minutes
    .source("my-app".to_string())
    .source_version("1.0.0".to_string())
    .build()?;

Using with Client

Integrate WalletAuth with the CDP client:
use cdp_sdk::{auth::WalletAuth, Client, CDP_BASE_URL};
use reqwest_middleware::ClientBuilder;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create auth middleware
    let wallet_auth = WalletAuth::builder()
        .api_key_id("your-api-key-id".to_string())
        .api_key_secret("your-api-key-secret".to_string())
        .wallet_secret("your-wallet-secret".to_string())
        .build()?;

    // Build HTTP client with middleware
    let http_client = ClientBuilder::new(reqwest::Client::new())
        .with(wallet_auth)
        .build();

    // Create CDP client
    let client = Client::new_with_client(CDP_BASE_URL, http_client);

    // Make authenticated requests
    let response = client.list_evm_accounts().send().await?;
    
    Ok(())
}

JWT Generation

The WalletAuth middleware automatically generates two types of JWTs:

API Key JWT

Generated for all requests to authenticate with the CDP API:
  • Added to the Authorization header as Bearer <token>
  • Contains request method, host, and path in the uris claim
  • Supports both EC (ES256) and Ed25519 (EdDSA) key formats
  • Automatically includes correlation data for tracking

Wallet JWT

Generated for requests that modify accounts or spend permissions:
  • Added to the X-Wallet-Auth header
  • Required for POST, DELETE, and PUT operations on:
    • /accounts endpoints
    • /spend-permissions endpoints
  • Includes a hash of the request body (reqHash) for integrity
  • Uses ES256 signing algorithm

Key Formats

EC Private Key (ES256)

PEM format EC keys are supported:
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIBK...
-----END EC PRIVATE KEY-----

Ed25519 Key (EdDSA)

Base64-encoded 64-byte Ed25519 keys:
YmFzZTY0ZW5jb2RlZGtleWJ5dGVz...== (64 bytes when decoded)

Wallet Secret

Base64-encoded DER format EC private key:
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...

Error Types

Authentication errors are represented by the CdpError enum:
use cdp_sdk::error::CdpError;

pub enum CdpError {
    Config(String),  // Configuration errors
    Auth(String),    // Authentication errors
}

Handling Auth Errors

match WalletAuth::builder().build() {
    Ok(auth) => println!("Auth configured successfully"),
    Err(CdpError::Config(msg)) => {
        eprintln!("Configuration error: {}", msg);
    }
    Err(CdpError::Auth(msg)) => {
        eprintln!("Authentication error: {}", msg);
    }
}

Automatic Header Management

The WalletAuth middleware automatically manages these headers:
Authorization
String
Bearer token with API key JWT
X-Wallet-Auth
String
Wallet JWT for mutation operations (when applicable)
Content-Type
String
Set to application/json
Correlation-Context
String
Tracking metadata including SDK version, language, and source

Debug Mode

Enable debug mode to log request and response details:
let wallet_auth = WalletAuth::builder()
    .api_key_id("your-api-key-id".to_string())
    .api_key_secret("your-api-key-secret".to_string())
    .debug(true) // Enable debug logging
    .build()?;

// Output will include:
// Request: POST https://api.cdp.coinbase.com/platform/v2/evm/accounts
// Headers: {"Authorization": "Bearer ...", ...}
// Response: 200 OK

Security Best Practices

Environment Variables

Store credentials in environment variables, never in code:
export CDP_API_KEY_ID="your-api-key-id"
export CDP_API_KEY_SECRET="your-api-key-secret"
export CDP_WALLET_SECRET="your-wallet-secret"

Credential Rotation

Recreate the WalletAuth instance when rotating credentials:
fn create_auth_from_env() -> Result<WalletAuth, CdpError> {
    WalletAuth::builder().build()
}

// Recreate when credentials change
let new_auth = create_auth_from_env()?;

JWT Expiration

Set appropriate expiration times for your use case:
let wallet_auth = WalletAuth::builder()
    .api_key_id("your-api-key-id".to_string())
    .api_key_secret("your-api-key-secret".to_string())
    .expires_in(60) // Short-lived tokens for high-security operations
    .build()?;

Example: Complete Setup

Complete example with error handling:
use cdp_sdk::{auth::WalletAuth, Client, CDP_BASE_URL, error::CdpError};
use reqwest_middleware::ClientBuilder;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load auth from environment with error handling
    let wallet_auth = match WalletAuth::builder().build() {
        Ok(auth) => auth,
        Err(CdpError::Config(msg)) => {
            eprintln!("Configuration error: {}", msg);
            eprintln!("Make sure to set CDP_API_KEY_ID and CDP_API_KEY_SECRET");
            return Err(msg.into());
        }
        Err(e) => return Err(e.into()),
    };

    // Create HTTP client with auth middleware
    let http_client = ClientBuilder::new(reqwest::Client::new())
        .with(wallet_auth)
        .build();

    // Create CDP client
    let client = Client::new_with_client(CDP_BASE_URL, http_client);

    // Make authenticated request
    let response = client.list_evm_accounts()
        .page_size(10)
        .send()
        .await?;

    let accounts = response.into_inner();
    println!("Found {} accounts", accounts.accounts.len());

    Ok(())
}

See Also

Build docs developers (and LLMs) love