Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
386 changes: 384 additions & 2 deletions sdks/golang.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,388 @@
---
title: "Golang"
description: "Turnkey offers native tooling for interacting with the API using Golang. See [https://github.com/tkhq/go-sdk](https://github.com/tkhq/go-sdk) for more details."
title: "Go"
description: "The Turnkey Go SDK provides a native interface for interacting with the Turnkey API, including API key signing, wallet management, and HPKE encryption for secure enclave communication."
sidebarTitle: "Go"
mode: wide
---

## Overview

The [Turnkey Go SDK](https://github.com/tkhq/go-sdk) provides a complete implementation for interacting with the Turnkey API from Go applications. It includes:

- **Swagger-generated API client** with 300+ typed request/response models
- **Request signing** supporting P-256, secp256k1, and ED25519 API keys
- **HPKE encryption** for secure wallet export/import with Turnkey's enclaves
- **Nitro attestation verification** for validating enclave proofs

<Note>
Go is the only Turnkey SDK that supports **ED25519 API key signing**, which is useful for chains like Near, Aptos, and Sui that use ED25519 natively.
</Note>

## Installation

```bash
go get github.com/tkhq/go-sdk
```

## Authentication

The Go SDK uses API keys to sign requests via the `X-Stamp` header. API keys can be generated on the [Turnkey Dashboard](https://app.turnkey.com) or via the CLI.

### Loading an API Key

```go
import (
sdk "github.com/tkhq/go-sdk"
"github.com/tkhq/go-sdk/pkg/apikey"
"github.com/tkhq/go-sdk/pkg/store/local"
)

// Load from ~/.config/turnkey/keys/ directory
client, err := sdk.New(sdk.WithAPIKeyName("default"))

// Or load from a Turnkey private key string directly
apiKey, err := apikey.FromTurnkeyPrivateKey(privateKeyHex, apikey.SchemeP256)
client, err := sdk.New(sdk.WithAPIKey(apiKey))
```

### Supported Signature Schemes

| Scheme | Constant | Use Case |
|--------|----------|----------|
| P-256 (secp256r1) | `apikey.SchemeP256` | Default, most common |
| secp256k1 | `apikey.SchemeSECP256K1` | Ethereum-compatible |
| ED25519 | `apikey.SchemeED25519` | Near, Aptos, Sui |

## Client Setup

```go
import (
sdk "github.com/tkhq/go-sdk"
)

client, err := sdk.New(
sdk.WithAPIKeyName("default"),
// Optional: custom transport config
// sdk.WithTransportConfig(customConfig),
)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
```

<Warning>
**Important**: You must pass `client.Authenticator` to every API call. The Go SDK does not set a global default authenticator.

```go
// ✅ Correct - pass Authenticator explicitly
resp, err := client.V0().Sessions.GetWhoami(params, client.Authenticator)

// ❌ Wrong - missing Authenticator will fail
resp, err := client.V0().Sessions.GetWhoami(params, nil)
```
</Warning>

## Usage Examples

### Get Whoami

The simplest API call to verify your credentials:

```go
import (
sdk "github.com/tkhq/go-sdk"
"github.com/tkhq/go-sdk/pkg/api/client/sessions"
"github.com/tkhq/go-sdk/pkg/api/models"
)

client, _ := sdk.New(sdk.WithAPIKeyName("default"))

params := sessions.NewGetWhoamiParams().WithBody(&models.GetWhoamiRequest{
OrganizationID: client.DefaultOrganization(),
})

resp, err := client.V0().Sessions.GetWhoami(params, client.Authenticator)
if err != nil {
log.Fatalf("Whoami failed: %v", err)
}

fmt.Printf("User ID: %s\n", *resp.Payload.UserID)
fmt.Printf("Organization ID: %s\n", *resp.Payload.OrganizationID)
```

### Create Wallet

```go
import (
"github.com/tkhq/go-sdk/pkg/api/client/wallets"
"github.com/tkhq/go-sdk/pkg/api/models"
"github.com/tkhq/go-sdk/pkg/util"
)

walletName := "My Wallet"
path := "m/44'/60'/0'/0/0"

params := wallets.NewCreateWalletParams().WithBody(&models.CreateWalletRequest{
OrganizationID: client.DefaultOrganization(),
TimestampMs: util.RequestTimestamp(),
Type: (*string)(models.ActivityTypeCreateWallet.Pointer()),
Parameters: &models.CreateWalletIntent{
WalletName: &walletName,
Accounts: []*models.WalletAccountParams{{
AddressFormat: models.AddressFormatEthereum.Pointer(),
Curve: models.CurveSecp256k1.Pointer(),
Path: &path,
PathFormat: models.PathFormatBip32.Pointer(),
}},
},
})

resp, err := client.V0().Wallets.CreateWallet(params, client.Authenticator)
if err != nil {
log.Fatalf("Failed to create wallet: %v", err)
}

walletID := resp.Payload.Activity.Result.CreateWalletResult.WalletID
address := resp.Payload.Activity.Result.CreateWalletResult.Addresses[0]
fmt.Printf("Wallet ID: %s\n", *walletID)
fmt.Printf("Address: %s\n", *address)
```

### Sign a Message

```go
import (
"github.com/tkhq/go-sdk/pkg/api/client/signing"
"github.com/tkhq/go-sdk/pkg/api/models"
)

params := signing.NewSignRawPayloadParams().WithBody(&models.SignRawPayloadRequest{
OrganizationID: client.DefaultOrganization(),
TimestampMs: util.RequestTimestamp(),
Type: (*string)(models.ActivityTypeSignRawPayloadV2.Pointer()),
Parameters: &models.SignRawPayloadIntentV2{
SignWith: &address,
Payload: stringPtr("hello world"),
Encoding: models.PayloadEncodingTextUtf8.Pointer(),
HashFunction: models.HashFunctionKeccak256.Pointer(),
},
})

resp, err := client.V0().Signing.SignRawPayload(params, client.Authenticator)
if err != nil {
log.Fatalf("Failed to sign: %v", err)
}

signature := resp.Payload.Activity.Result.SignRawPayloadResult
fmt.Printf("R: %s\n", *signature.R)
fmt.Printf("S: %s\n", *signature.S)
fmt.Printf("V: %s\n", *signature.V)
```

### Email OTP Authentication

```go
import (
"github.com/tkhq/go-sdk/pkg/api/client/sessions"
"github.com/tkhq/go-sdk/pkg/api/models"
)

// Step 1: Initialize OTP
initParams := sessions.NewInitOtpParams().WithBody(&models.InitOtpRequest{
OrganizationID: &orgID,
TimestampMs: util.RequestTimestamp(),
Type: (*string)(models.ActivityTypeInitOtp.Pointer()),
Parameters: &models.InitOtpIntent{
OtpType: models.OtpTypeOtpTypeEmail.Pointer(),
Contact: &email,
},
})

initResp, err := client.V0().Sessions.InitOtp(initParams, client.Authenticator)
// Handle error, extract otpID from result

// Step 2: User receives code, then verify
verifyParams := sessions.NewOtpParams().WithBody(&models.OtpRequest{
OrganizationID: &orgID,
TimestampMs: util.RequestTimestamp(),
Type: (*string)(models.ActivityTypeOtp.Pointer()),
Parameters: &models.OtpIntent{
OtpID: &otpID,
OtpCode: &userProvidedCode,
},
})

verifyResp, err := client.V0().Sessions.Otp(verifyParams, client.Authenticator)

// Step 3: Create authenticated session
authParams := sessions.NewOtpAuthParams().WithBody(&models.OtpAuthRequest{
OrganizationID: &orgID,
TimestampMs: util.RequestTimestamp(),
Type: (*string)(models.ActivityTypeOtpAuth.Pointer()),
Parameters: &models.OtpAuthIntent{
OtpID: &otpID,
TargetPublicKey: &targetPublicKey,
SessionLengthSeconds: int64Ptr(3600),
},
})

authResp, err := client.V0().Sessions.OtpAuth(authParams, client.Authenticator)
```

## Activity Polling

<Warning>
**The Go SDK does not auto-poll for activity completion.** Unlike TypeScript and Rust, you must implement polling yourself for activities that may be pending.
</Warning>

```go
import (
"time"
"github.com/tkhq/go-sdk/pkg/api/client/activities"
"github.com/tkhq/go-sdk/pkg/api/models"
)

func pollForCompletion(client *sdk.Client, activityID, orgID string) (*models.V1Activity, error) {
maxAttempts := 10
for i := 0; i < maxAttempts; i++ {
params := activities.NewGetActivityParams().WithBody(&models.GetActivityRequest{
OrganizationID: &orgID,
ActivityID: &activityID,
})

resp, err := client.V0().Activities.GetActivity(params, client.Authenticator)
if err != nil {
return nil, err
}

status := resp.Payload.Activity.Status
switch *status {
case models.ActivityStatusActivityStatusCompleted:
return resp.Payload.Activity, nil
case models.ActivityStatusActivityStatusFailed:
return nil, fmt.Errorf("activity failed")
case models.ActivityStatusActivityStatusPending:
time.Sleep(time.Second)
continue
default:
return nil, fmt.Errorf("unexpected status: %s", *status)
}
}
return nil, fmt.Errorf("polling timeout")
}
```

## HPKE Encryption (Wallet Export)

The Go SDK includes full HPKE support for encrypting/decrypting wallet exports:

```go
import (
"github.com/tkhq/go-sdk/pkg/encryptionkey"
"github.com/tkhq/go-sdk/pkg/enclave_encrypt"
)

// 1. Generate a client-side encryption key
encryptionKey, err := encryptionkey.New(userID, organizationID)

// 2. Export wallet (encrypted to your target key)
params := wallets.NewExportWalletParams().WithBody(&models.ExportWalletRequest{
OrganizationID: &orgID,
TimestampMs: util.RequestTimestamp(),
Type: (*string)(models.ActivityTypeExportWallet.Pointer()),
Parameters: &models.ExportWalletIntent{
WalletID: &walletID,
TargetPublicKey: &encryptionKey.TkPublicKey,
},
})

resp, err := client.V0().Wallets.ExportWallet(params, client.Authenticator)
exportBundle := resp.Payload.Activity.Result.ExportWalletResult.ExportBundle

// 3. Decrypt locally
kemPrivateKey, _ := encryptionkey.DecodeTurnkeyPrivateKey(encryptionKey.GetPrivateKey())
signerKey, _ := hexToPublicKey(encryptionkey.SignerProductionPublicKey)
encryptClient, _ := enclave_encrypt.NewEnclaveEncryptClientFromTargetKey(signerKey, *kemPrivateKey)
mnemonic, err := encryptClient.Decrypt([]byte(*exportBundle), organizationID)
```

## Nitro Attestation Verification

The Go SDK can verify AWS Nitro attestation documents from Turnkey's enclaves:

```go
import (
"github.com/tkhq/go-sdk/pkg/proofs"
)

// Verify an attestation document
doc, err := proofs.VerifyNitroAttestation(attestationBytes, timestamp)
if err != nil {
log.Fatalf("Attestation verification failed: %v", err)
}

// Access verified enclave measurements
fmt.Printf("PCR0: %x\n", doc.PCR0)
```

## Ethereum Integration

The Go SDK includes examples for integrating with go-ethereum:

```go
import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
)

// Create a Turnkey-backed SignerFn for go-ethereum
func MakeTurnkeySignerFn(client *sdk.Client, signWith string, chainID *big.Int, orgID string) bind.SignerFn {
return func(from common.Address, tx *types.Transaction) (*types.Transaction, error) {
// Build unsigned EIP-1559 payload
unsignedPayload := []any{
tx.ChainId(), tx.Nonce(), tx.GasTipCap(), tx.GasFeeCap(),
tx.Gas(), tx.To(), tx.Value(), tx.Data(), tx.AccessList(),
}
rlpBytes, _ := rlp.EncodeToBytes(unsignedPayload)
unsigned := append([]byte{types.DynamicFeeTxType}, rlpBytes...)

// Sign with Turnkey
params := signing.NewSignTransactionParams().WithBody(&models.SignTransactionRequest{
OrganizationID: &orgID,
TimestampMs: util.RequestTimestamp(),
Type: (*string)(models.ActivityTypeSignTransactionV2.Pointer()),
Parameters: &models.SignTransactionIntentV2{
SignWith: &signWith,
Type: models.TransactionTypeEthereum.Pointer(),
UnsignedTransaction: stringPtr(hex.EncodeToString(unsigned)),
},
})

resp, _ := client.V0().Signing.SignTransaction(params, client.Authenticator)
rawSigned, _ := hex.DecodeString(*resp.Payload.Activity.Result.SignTransactionResult.SignedTransaction)

finalTx := new(types.Transaction)
finalTx.UnmarshalBinary(rawSigned)
return finalTx, nil
}
}
```

## Examples

The SDK includes working examples in the [`examples/`](https://github.com/tkhq/go-sdk/tree/main/examples) directory:

| Example | Description |
|---------|-------------|
| [`whoami`](https://github.com/tkhq/go-sdk/tree/main/examples/whoami) | Basic API call to verify credentials |
| [`wallets`](https://github.com/tkhq/go-sdk/tree/main/examples/wallets) | Wallet creation and export |
| [`signing`](https://github.com/tkhq/go-sdk/tree/main/examples/signing) | Transaction and payload signing |
| [`delegated_access`](https://github.com/tkhq/go-sdk/tree/main/examples/delegated_access) | Sub-organization and policy setup |
| [`email_otp`](https://github.com/tkhq/go-sdk/tree/main/examples/email_otp) | OTP authentication flow |
| [`go-ethereum`](https://github.com/tkhq/go-sdk/tree/main/examples/go-ethereum) | Ethereum integration patterns |

## Resources

- [GitHub Repository](https://github.com/tkhq/go-sdk)
- [pkg.go.dev Documentation](https://pkg.go.dev/github.com/tkhq/go-sdk)
- [API Reference](/api-reference/overview)
Loading