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
Your CDP API key secret (supports EC PEM keys and Ed25519 base64 keys)
Optional wallet secret for signing transactions (base64-encoded EC key)
Enable debug logging for requests and responses
Source identifier for tracking requests
Version of the source making requests
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
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);
}
}
The WalletAuth middleware automatically manages these headers:
Bearer token with API key JWT
Wallet JWT for mutation operations (when applicable)
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