package server import ( "context" "crypto/ecdsa" "crypto/rand" "crypto/x509" "encoding/hex" "encoding/pem" "fmt" "time" "github.com/golang-jwt/jwt/v5" x402http "github.com/x402-foundation/x402/go/v2/http" ) type CDPAuth struct { keyName string privateKey *ecdsa.PrivateKey signingMethod jwt.SigningMethod } func NewCDPAuth(keyName, privateKeyPEM string) (*CDPAuth, error) { block, _ := pem.Decode([]byte(privateKeyPEM)) if block == nil { return nil, fmt.Errorf("failed to decode PEM block") } var signingMethod jwt.SigningMethod privKey, err := x509.ParseECPrivateKey(block.Bytes) if err != nil { parsed, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { return nil, fmt.Errorf("failed to parse private key: %w", err) } var ok bool privKey, ok = parsed.(*ecdsa.PrivateKey) if !ok { return nil, fmt.Errorf("not an ECDSA private key") } signingMethod = jwt.SigningMethodEdDSA } else { signingMethod = jwt.SigningMethodES256 } return &CDPAuth{ keyName: keyName, privateKey: privKey, signingMethod: signingMethod, }, nil } func (a *CDPAuth) generateBearerToken(method, path string) (string, error) { nonceBytes := make([]byte, 16) if _, err := rand.Read(nonceBytes); err != nil { return "", err } nonce := hex.EncodeToString(nonceBytes) uri := fmt.Sprintf("%s api.cdp.coinbase.com%s", method, path) now := time.Now().Unix() claims := jwt.MapClaims{ "sub": a.keyName, "iss": "cdp", "nbf": now, "exp": now + 120, "uris": []string{uri}, } token := jwt.NewWithClaims(a.signingMethod, claims) token.Header["kid"] = a.keyName token.Header["nonce"] = nonce return token.SignedString(a.privateKey) } func (a *CDPAuth) GetAuthHeaders(ctx context.Context) (x402http.AuthHeaders, error) { verify, _ := a.generateBearerToken("POST", "/platform/v2/x402/verify") settle, _ := a.generateBearerToken("POST", "/platform/v2/x402/settle") supported, _ := a.generateBearerToken("GET", "/platform/v2/x402/supported") return x402http.AuthHeaders{ Verify: map[string]string{"Authorization": "Bearer " + verify}, Settle: map[string]string{"Authorization": "Bearer " + settle}, Supported: map[string]string{"Authorization": "Bearer " + supported}, }, nil }