Skip to content

Go SDK

If your Go service calls a TrustPlane-protected API, the Go caller SDK for TrustPlane Auth builds and signs the proof-bound request material for you before the call leaves your process, and can enroll the workload with Control. It is available at version v0.2.2:

Terminal window
go get github.com/trustplane-dev/trustplane-auth-sdk-go@v0.2.2

Releases are published as signed tags with a public GitHub release, and go get resolves the module through normal Go module resolution.

At v0.2.2, the Go SDK supports:

  • generating, importing, and exporting CLI-compatible Ed25519 software keys;
  • issuing the short-lived passport-v0.1 shape used by the current CLI;
  • exact transcript-v1 request signing, including the body SHA-256 value used in TrustPlane request headers;
  • strict parsing and enforcement of active Control key-grant signing profiles;
  • signed GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, and custom HTTP methods;
  • TA-G1 public auto-enrollment (challenge, server-bound proof, key proof-of-possession, submission, retry, secret-capability polling, and runtime activation);
  • compact JWT, AWS IID, and Azure IMDS enrollment proof values; and
  • broker IPC v1 request building, Unix-socket calls, and adapter-ready headers.

The module does not include a verifier, adapter, broker runtime, bundle policy engine, SPIFFE issuer, deployment code, Control administrative API, or Control data model. Operator-only verification, bundle authoring/signing, runtime startup, and local-demo commands remain CLI-only and are not part of the caller SDK.

Raw local signing is software-only. The remote_kms, hardware_local, and attested_workload key bindings require an appropriate broker or signer path; the SDK does not relabel an exportable local key.

package main
import (
"fmt"
trustplane "github.com/trustplane-dev/trustplane-auth-sdk-go"
)
func main() {
fmt.Println(trustplane.HeaderAuthorization)
fmt.Println(trustplane.BodySHA256([]byte("request body")))
}

Control returns a safe signing profile for a specific active key grant. Decode that JSON into SigningProfile, load the corresponding local key, and let ProtectedClient issue a fresh passport and sign each request:

var profile trustplane.SigningProfile // json.Unmarshal(Control response, &profile)
privateKey, err := trustplane.ParsePrivateKeyBase64URL(privateKeyFileContents)
if err != nil { /* handle */ }
client := trustplane.ProtectedClient{
Profile: profile,
PrivateKey: privateKey,
}
response, err := client.Do(
context.Background(),
profile.Method,
"/orders/123?expand=items",
nil,
http.Header{"Accept": {"application/json"}},
)

The client rejects a method or path outside the exact Control profile. PathPrefix matching does not match sibling prefixes (/api never matches /apix). Exact route templates such as /orders/{id} require a concrete path such as /orders/123; template braces, encoded paths, dot segments, duplicate separators, and non-root trailing slashes fail before signing. Query-only targets such as ?expand=items retain a literal profile path. Redirects are returned without forwarding TrustPlane credentials.

Use BuildRequest when you want the canonical transcript material and body hash before signing or before comparing against conformance vectors. Passport-bound fields such as PassportJTI, IssuedAtUnix, and KeyBinding must come from the real passport you are preparing to use.

package main
import (
"fmt"
trustplane "github.com/trustplane-dev/trustplane-auth-sdk-go"
)
func main() {
body := []byte(`{"order_id":"ord_123","amount":"42.00"}`)
material, err := trustplane.BuildRequest(trustplane.RequestInput{
Method: "POST",
Scheme: "https",
Authority: "orders.example",
Path: "/v1/orders",
RawQuery: "region=us&priority=standard",
Audience: "orders-api",
RouteID: "orders.create",
ContentEncoding: "identity",
Body: body,
Headers: []trustplane.Header{
{Name: "Content-Type", Value: "application/json"},
{Name: trustplane.HeaderNonce, Value: "nonce-v1-001"},
},
HeaderAllowList: []string{"content-type", "x-trustplane-nonce"},
Nonce: "nonce-v1-001",
PassportJTI: "passport-jti-from-real-passport",
IssuedAtUnix: 1740000000,
KeyBinding: trustplane.SoftwareKeyBinding,
})
if err != nil {
panic(err)
}
fmt.Println(material.BodySHA256)
fmt.Println(material.TranscriptSHA256)
}

SignRequest is for raw local software signing. First obtain a real TrustPlane passport from the TrustPlane CLI or broker. The Ed25519 private key you pass must match the passport cnf.public_key_b64url value, and the passport cnf.key_binding must be software. Raw signing does not support the remote_kms, hardware_local, or attested_workload key bindings — those require a broker or signer path.

package main
import (
"bytes"
"crypto/ed25519"
"net/http"
trustplane "github.com/trustplane-dev/trustplane-auth-sdk-go"
)
func newSignedOrderRequest(passport string, privateKey ed25519.PrivateKey) (*http.Request, error) {
body := []byte(`{"order_id":"ord_123","amount":"42.00"}`)
req, err := http.NewRequest(
http.MethodPost,
"https://orders.example/v1/orders?region=us&priority=standard",
bytes.NewReader(body),
)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set(trustplane.HeaderNonce, "nonce-v1-001")
signed, err := trustplane.SignRequest(trustplane.ProofInput{
PassportToken: passport,
PrivateKey: privateKey,
Request: trustplane.RequestInput{
Method: req.Method,
Scheme: req.URL.Scheme,
Authority: req.URL.Host,
Path: req.URL.Path,
RawQuery: req.URL.RawQuery,
RouteID: "orders.create",
ContentEncoding: "identity",
Body: body,
Headers: []trustplane.Header{
{Name: "Content-Type", Value: req.Header.Get("Content-Type")},
{Name: trustplane.HeaderNonce, Value: req.Header.Get(trustplane.HeaderNonce)},
},
HeaderAllowList: []string{"content-type", "x-trustplane-nonce"},
Nonce: req.Header.Get(trustplane.HeaderNonce),
},
})
if err != nil {
return nil, err
}
for name, value := range signed.Headers {
req.Header.Set(name, value)
}
return req, nil
}

TA-G1 public auto-enrollment is supported through EnrollmentClient. The Enrollment Policy reference is opaque: Control — not the SDK caller — selects the exact source, revision, proof mode, client, Auth Site, and runtime target.

result, err := (&trustplane.EnrollmentClient{}).Enroll(ctx, trustplane.EnrollmentOptions{
ControlURL: "https://control.example",
EnrollmentPolicyRef: "enrpol_...",
Provider: "kubernetes_service_account_oidc",
PrivateKey: privateKey,
ProofProvider: func(_ context.Context, challenge trustplane.EnrollmentChallenge) (trustplane.EnrollmentProof, error) {
token, err := obtainAudienceBoundWorkloadToken(challenge.ExpectedAudience)
return trustplane.JWTEnrollmentProof(token), err
},
})

The safe result excludes the private key, proof, challenge nonce, proof-of-possession signature, and poll capability. Control enrollment requires HTTPS. Proof callbacks run only after the SDK validates Control’s immutable source-revision and proof-encoding binding.

Provider credential acquisition remains application-owned: the callback can read a projected token, call cloud metadata with the challenge audience/nonce, or use a workload identity library. The SDK owns the complete Control protocol and supplies exact JWT, AWS IID, and Azure IMDS proof-value helpers. After Control accepts a submission, a polling deadline returns a safe pending result with its request ID rather than resubmitting proof material.

Use BuildBrokerRequest, CallBroker, and BrokerHeaders when key custody and signer selection belong to a local TrustPlane broker. The SDK is only an IPC caller over broker IPC v1; it does not include a broker runtime.

Pin the exact module version v0.2.2 and use the shared conformance vectors to check transcript and signing behavior. The TypeScript SDK is also available for Node.js callers, and the Python SDK is released at the same version.