Skip to content
SDKs · GoIn development

Go

A small, dependency-free Go module for the server→server Background-Check flow: mint a challenge, appraise the client's opaque evidence with your rh_sk_ secret key, and get the verdict back directly in the response. Mirrors @rootherald/node's issueChallenge / verify.

In development

This SDK is implemented but not yet published to its package registry. Until it ships, collect an opaque evidence blob on the device and appraise it server-side with @rootherald/node (or any available server SDK). The API shown below is the planned surface and may change before release.

How it works

Your keyless client (browser or native) collects an opaque evidence blob and hands it to your backend. Your backend uses this module — authenticated with its rh_sk_ secret key — to mint a nonce (IssueChallenge) and submit the evidence for appraisal (Verify). The verdict is computed by RootHerald and returned to your backend; it never travels through the client, which holds no key.

1

Install

go get github.com/RootHerald/sdk-go
2

Construct the client

NewAttestClient rejects any key that doesn't start with rh_sk_. Options: WithBaseURL, WithAttestHTTPClient.

import rootherald "github.com/RootHerald/sdk-go"

// Construct once; safe for concurrent use. rh_sk_… is your secret key.
client, err := rootherald.NewAttestClient(os.Getenv("RH_SECRET_KEY"))
if err != nil {
    log.Fatalf("attest client: %v", err)
}
3

Mint a challenge

// (a) Mint a nonce and relay it to your client. The client quotes over
//     'nonce' and returns an opaque evidence blob to your backend.
chal, err := client.IssueChallenge(ctx, "" /* optional device hint */)
if err != nil {
    return err
}
// send chal.Nonce (and chal.ChallengeID) to your client
4

Verify the evidence

Verify returns an AttestResult: Verdict (one of VerdictAllow / VerdictDeny / VerdictReview), Device (the typed verdict.device view, including advisory-only cohort fields), and Raw (the full decoded verdict map).

// (b) The client posted back its opaque evidence blob. Appraise it.
verdict, err := client.Verify(ctx, evidence, rootherald.AttestOptions{
    ChallengeID: chal.ChallengeID,
    Policy:      "rootherald:builtin:strict-hardware",
})
if err != nil {
    // Only protocol/auth/quota problems land here — see "Errors".
    return err
}

// A real-but-rejected device is NOT an error: branch on the verdict.
if verdict.Verdict != rootherald.VerdictAllow {
    http.Error(w, "device rejected", http.StatusForbidden)
    return
}

// verdict.Device.UEID is a stable device id — use it for
// one-device-one-account enforcement.
deviceID := verdict.Device.UEID

Errors

Protocol/auth/quota failures wrap a sentinel you can switch on with errors.Is. Anything else — including a device that simply failed appraisal — comes back as a normal verdict, not an error.

switch {
case errors.Is(err, rootherald.ErrQuotaExceeded):    // 429, back off
case errors.Is(err, rootherald.ErrUnknownPolicy):    // 422, fix the policy name
case errors.Is(err, rootherald.ErrInvalidSecretKey): // 401, check rh_sk_ key
case errors.Is(err, rootherald.ErrChallenge):        // 409, challenge unknown/expired
case errors.Is(err, rootherald.ErrInvalidEvidence):  // 400, evidence malformed
}
// A real-but-rejected device is not an error — branch on verdict.Verdict.

Sample

A runnable hello-world HTTP server that wires IssueChallengeVerify is at RootHerald/sdk-go/examples/hello.