Skip to main content

Overview

The CDP Go SDK uses JWT (JSON Web Token) based authentication to secure API requests. The SDK provides utilities for generating both API key JWTs and wallet authentication JWTs.

Package Import

import "github.com/coinbase/cdp-sdk/go/auth"

JWT Types

The SDK supports two types of JWTs:
  1. API Key JWT - For authenticating all API requests
  2. Wallet JWT - For signing mutations to accounts and spend permissions

JwtOptions

Configuration for generating API key JWTs:
type JwtOptions struct {
    // API key ID
    KeyID string
    
    // API key secret (EC PEM or Ed25519 base64)
    KeySecret string
    
    // HTTP method (e.g., "GET", "POST")
    RequestMethod string
    
    // Request host (e.g., "api.cdp.coinbase.com")
    RequestHost string
    
    // Request path (e.g., "/platform/v2/evm/accounts")
    RequestPath string
    
    // JWT expiration in seconds (default: 120)
    ExpiresIn int64
    
    // Optional audience claim
    Audience []string
}

Field Details

KeyID
string
required
Your CDP API key ID. Examples:
  • xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  • organizations/xxx/apiKeys/xxx
KeySecret
string
required
Your API key secret in one of these formats:
  • Ed25519: Base64-encoded 64-byte key
  • EC: PEM-formatted EC private key
RequestMethod
string
HTTP method. Empty string for WebSocket JWTs
RequestHost
string
Request host. Empty string for WebSocket JWTs
RequestPath
string
Request path. Empty string for WebSocket JWTs
ExpiresIn
int64
default:"120"
JWT expiration time in seconds
Audience
[]string
Optional audience claim for the JWT

Generating API Key JWTs

Generate a JWT for API authentication:
package main

import (
    "fmt"
    "log"
    
    "github.com/coinbase/cdp-sdk/go/auth"
)

func main() {
    options := auth.JwtOptions{
        KeyID:         "your-api-key-id",
        KeySecret:     "your-api-key-secret",
        RequestMethod: "GET",
        RequestHost:   "api.cdp.coinbase.com",
        RequestPath:   "/platform/v2/evm/accounts",
        ExpiresIn:     120,
    }
    
    jwt, err := auth.GenerateJWT(options)
    if err != nil {
        log.Fatalf("Failed to generate JWT: %v", err)
    }
    
    fmt.Printf("JWT: %s\n", jwt)
}

REST API JWTs

For REST API requests, provide all request parameters:
options := auth.JwtOptions{
    KeyID:         "your-api-key-id",
    KeySecret:     "your-api-key-secret",
    RequestMethod: "POST",
    RequestHost:   "api.cdp.coinbase.com",
    RequestPath:   "/platform/v2/evm/accounts",
    ExpiresIn:     120,
}

jwt, err := auth.GenerateJWT(options)

WebSocket JWTs

For WebSocket connections, omit request parameters:
options := auth.JwtOptions{
    KeyID:         "your-api-key-id",
    KeySecret:     "your-api-key-secret",
    RequestMethod: "", // Empty for WebSocket
    RequestHost:   "", // Empty for WebSocket
    RequestPath:   "", // Empty for WebSocket
    ExpiresIn:     120,
}

jwt, err := auth.GenerateJWT(options)

WalletJwtOptions

Configuration for generating wallet authentication JWTs:
type WalletJwtOptions struct {
    // Wallet secret (base64-encoded EC DER private key)
    WalletSecret string
    
    // HTTP method (e.g., "POST", "DELETE")
    RequestMethod string
    
    // Request host
    RequestHost string
    
    // Request path
    RequestPath string
    
    // Request body data
    RequestData map[string]interface{}
}

Field Details

WalletSecret
string
required
Base64-encoded EC DER format private key for wallet signing
RequestMethod
string
required
HTTP method (typically “POST” or “DELETE”)
RequestHost
string
required
The host for the request
RequestPath
string
required
The path for the request
RequestData
map[string]interface{}
required
The request body data to be hashed and included in the JWT

Generating Wallet JWTs

Generate a wallet JWT for signing operations:
package main

import (
    "fmt"
    "log"
    
    "github.com/coinbase/cdp-sdk/go/auth"
)

func main() {
    options := auth.WalletJwtOptions{
        WalletSecret:  "your-wallet-secret",
        RequestMethod: "POST",
        RequestHost:   "api.cdp.coinbase.com",
        RequestPath:   "/platform/v2/evm/accounts",
        RequestData: map[string]interface{}{
            "name": "my-account",
        },
    }
    
    walletJwt, err := auth.GenerateWalletJWT(options)
    if err != nil {
        log.Fatalf("Failed to generate wallet JWT: %v", err)
    }
    
    fmt.Printf("Wallet JWT: %s\n", walletJwt)
}

WalletAuthClaims

JWT claims structure for wallet authentication:
type WalletAuthClaims struct {
    // List of URIs being accessed
    URIs []string `json:"uris"`
    
    // SHA-256 hash of sorted request data (hex-encoded)
    ReqHash string `json:"reqHash,omitempty"`
    
    // Standard JWT claims (iat, nbf, jti)
    jwt.RegisteredClaims
}
URIs
[]string
Array containing the request URI (e.g., ["POST api.cdp.coinbase.com/platform/v2/evm/accounts"])
ReqHash
string
Hex-encoded SHA-256 hash of the sorted JSON request body
RegisteredClaims
jwt.RegisteredClaims
Standard JWT claims including:
  • iat (issued at)
  • nbf (not before)
  • jti (JWT ID / nonce)

Key Formats

EC Private Key (PEM Format)

For ES256 signing:
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIBKuSvr...
-----END EC PRIVATE KEY-----

Ed25519 Key (Base64 Format)

For EdDSA signing (64 bytes when decoded):
YmFzZTY0ZW5jb2RlZGtleWJ5dGVz...==

Wallet Secret (Base64 DER Format)

For wallet signing:
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg...

Error Handling

Handle authentication errors properly:
jwt, err := auth.GenerateJWT(options)
if err != nil {
    switch {
    case strings.Contains(err.Error(), "key name is required"):
        log.Fatal("API key ID is missing")
    case strings.Contains(err.Error(), "private key is required"):
        log.Fatal("API key secret is missing")
    case strings.Contains(err.Error(), "invalid key format"):
        log.Fatal("Key format is invalid - use PEM EC or base64 Ed25519")
    default:
        log.Fatalf("JWT generation failed: %v", err)
    }
}

Request Body Hashing

The wallet JWT includes a hash of the request body for integrity:
options := auth.WalletJwtOptions{
    WalletSecret:  "your-wallet-secret",
    RequestMethod: "POST",
    RequestHost:   "api.cdp.coinbase.com",
    RequestPath:   "/platform/v2/evm/accounts",
    RequestData: map[string]interface{}{
        "name": "my-account",
        "metadata": map[string]interface{}{
            "key": "value",
        },
    },
}

// The RequestData is:
// 1. Recursively sorted by keys
// 2. Serialized to JSON
// 3. Hashed with SHA-256
// 4. Hex-encoded and included in the ReqHash claim

walletJwt, err := auth.GenerateWalletJWT(options)

Security Best Practices

Store Credentials Securely

Use environment variables for sensitive data:
import "os"

options := auth.JwtOptions{
    KeyID:     os.Getenv("CDP_API_KEY_ID"),
    KeySecret: os.Getenv("CDP_API_KEY_SECRET"),
    // ...
}

Set Appropriate Expiration

Use shorter expiration times for sensitive operations:
options := auth.JwtOptions{
    KeyID:     "your-api-key-id",
    KeySecret: "your-api-key-secret",
    ExpiresIn: 60, // 1 minute for high-security operations
    // ...
}

Validate Key Format

Ensure keys are in the correct format before use:
import "encoding/base64"

func isValidEd25519Key(key string) bool {
    decoded, err := base64.StdEncoding.DecodeString(key)
    if err != nil {
        return false
    }
    return len(decoded) == 64
}

Complete Example

Full example using both JWT types:
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    
    "github.com/coinbase/cdp-sdk/go"
    "github.com/coinbase/cdp-sdk/go/auth"
    "github.com/coinbase/cdp-sdk/go/openapi"
)

func main() {
    // Load credentials from environment
    apiKeyID := os.Getenv("CDP_API_KEY_ID")
    apiKeySecret := os.Getenv("CDP_API_KEY_SECRET")
    walletSecret := os.Getenv("CDP_WALLET_SECRET")
    
    // Create client (handles auth automatically)
    client, err := cdp.NewClient(cdp.ClientOptions{
        APIKeyID:     apiKeyID,
        APIKeySecret: apiKeySecret,
        WalletSecret: walletSecret,
    })
    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }
    
    // The client automatically:
    // 1. Generates API key JWT for Authorization header
    // 2. Generates wallet JWT for X-Wallet-Auth header (when needed)
    
    ctx := context.Background()
    
    // Make authenticated request
    resp, err := client.CreateEvmAccountWithResponse(
        ctx,
        &openapi.CreateEvmAccountParams{
            XWalletAuth:      "", // Auto-filled by client
            XIdempotencyKey: "unique-request-id",
        },
        openapi.CreateEvmAccountJSONRequestBody{
            Name: openapi.NewOptional("my-account"),
        },
    )
    
    if err != nil {
        log.Fatalf("Request failed: %v", err)
    }
    
    if resp.JSON201 != nil {
        fmt.Printf("Created account: %s\n", resp.JSON201.Address)
    }
}

See Also

Build docs developers (and LLMs) love