Go SDK

Production-grade, thread-safe Go client for CustomKeys secrets management. Designed for backend services, CLI tools, and infrastructure automation.

Installation

go get github.com/cksxe/sdk-go

Quick Start

package main import ( "fmt" "log" "os" customkeys "github.com/cksxe/sdk-go" ) func main() { client, err := customkeys.New( customkeys.WithToken(os.Getenv("CUSTOMKEYS_TOKEN")), customkeys.WithEnv(os.Getenv("CUSTOMKEYS_ENV_ID")), ) if err != nil { log.Fatal(err) } defer client.Close() // Fetch a single secret dbURL, ok := client.Get("DATABASE_URL") if !ok { log.Fatal("DATABASE_URL not found") } fmt.Println("Connected:", dbURL[:20]+"...") // Fetch all secrets all := client.GetAll() fmt.Printf("Loaded %d secrets\n", len(all)) }

Configuration

All options are set via functional options passed to customkeys.New():

OptionDefaultDescription
WithToken(string)requiredAPI token with secrets:read scope
WithEnv(string)requiredEnvironment UUID
WithBaseURL(string)https://customkeys-api.superxepic.devAPI base URL
WithTTL(time.Duration)60sCache freshness window
WithPollInterval(time.Duration)30sBackground refresh interval
WithTimeout(time.Duration)10sHTTP request timeout
WithMaxRetries(int)3Retries on transient failures
WithHTTPClient(*http.Client)autoCustom HTTP client
WithLogger(Logger)disabledDebug logging

Methods

MethodReturnDescription
Get(key)(string, bool)Returns the value or ("", false) if not found
MustGet(key)stringReturns the value or panics — use for required config at startup
GetOrDefault(key, default)stringReturns the value or the provided default
GetAll()map[string]stringReturns a shallow copy of all cached secrets
Refresh(ctx)errorForces an immediate cache refresh (blocking)
Ready()booltrue after initial bulk pull completes
Close()Stops polling, zeros memory, releases resources

Usage with Gin / Echo / Chi

package main import ( "log" "net/http" "os" "github.com/go-chi/chi/v5" customkeys "github.com/cksxe/sdk-go" ) var secrets *customkeys.Client func main() { var err error secrets, err = customkeys.New( customkeys.WithToken(os.Getenv("CUSTOMKEYS_TOKEN")), customkeys.WithEnv(os.Getenv("CUSTOMKEYS_ENV_ID")), ) if err != nil { log.Fatal(err) } defer secrets.Close() r := chi.NewRouter() r.Get("/health", func(w http.ResponseWriter, r *http.Request) { dbHost := secrets.GetOrDefault("DB_HOST", "localhost") w.Write([]byte("OK — DB: " + dbHost)) }) log.Fatal(http.ListenAndServe(":8080", r)) }

Callbacks and Observability

client, _ := customkeys.New( customkeys.WithToken(os.Getenv("CUSTOMKEYS_TOKEN")), customkeys.WithEnv(os.Getenv("CUSTOMKEYS_ENV_ID")), customkeys.WithOnRefresh(func(count int) { log.Printf("Refreshed %d secrets", count) }), customkeys.WithOnError(func(err error) { log.Printf("Refresh failed: %v", err) // Send to your alerting system }), customkeys.WithLogger(log.Default()), )

Security Features

  • TLS 1.2+ enforced on all connections
  • Token sanitization — rejects control characters and newlines
  • Response body limiting — 10 MB max to prevent memory exhaustion
  • Memory zeroingClose() overwrites cached secret values before freeing
  • Singleflight dedup — concurrent refreshes are coalesced into one API call
  • Exponential backoff — retries with 500ms/1s/2s delays, auth errors never retried
  • No disk I/O — secrets are never written to the filesystem

[!IMPORTANT] The API token is sensitive. Always load it from an environment variable — never hardcode it in source.

Last updated: 4/20/2026Report Issue