Go

Installation

go get github.com/zourzouvillys/httpsig/golang

Requires Go 1.22 or later. The package name is httpsig.

Quick Example: Sign a Request

package main

import (
    "crypto/ed25519"
    "fmt"
    "net/http"
    "time"

    "github.com/zourzouvillys/httpsig/golang"
)

func main() {
    // Load or generate your private key
    _, privateKey, _ := ed25519.GenerateKey(nil)

    // Create a key pair (auto-detects algorithm from key type)
    kp, _ := httpsig.NewKeyPair("my-key-id", privateKey)
    key := kp.Signing

    // Build a request
    req, _ := http.NewRequest("POST", "https://example.com/api/resource", nil)
    req.Header.Set("Content-Type", "application/json")

    // Define what to sign
    params := httpsig.SignatureParameters{
        Components: []httpsig.ComponentIdentifier{
            httpsig.Component("@method"),
            httpsig.Component("@path"),
            httpsig.Component("@authority"),
            httpsig.Component("content-type"),
        },
        KeyID:   "my-key-id",
        Created: httpsig.Int64Ptr(time.Now().Unix()),
    }

    // Sign it
    msg := &httpsig.RequestMessage{Req: req}
    result, err := httpsig.SignMessage(msg, "sig1", params, key, nil)
    if err != nil {
        panic(err)
    }

    // Apply signature headers
    req.Header.Set("Signature-Input", httpsig.SignatureInputHeader(result))
    req.Header.Set("Signature", httpsig.SignatureHeader(result))

    fmt.Println("Signature-Input:", req.Header.Get("Signature-Input"))
}

Quick Example: Verify a Signature

package main

import (
    "crypto/ed25519"
    "fmt"
    "time"

    "github.com/zourzouvillys/httpsig/golang"
)

func main() {
    // Load the public key
    publicKey := loadPublicKey() // your public key

    // Set up a KeyProvider (auto-detects algorithm from public key type)
    provider := func(keyID string, alg httpsig.Algorithm) (httpsig.VerifyingKey, error) {
        if keyID == "my-key-id" {
            return httpsig.NewVerifyingKeyFromPublic(keyID, publicKey)
        }
        return nil, fmt.Errorf("unknown key: %s", keyID)
    }

    // Verify the message (msg is an httpsig.Message with Signature and Signature-Input headers)
    result, err := httpsig.VerifyMessage(msg, provider, &httpsig.VerifyOptions{
        RequiredComponents: []httpsig.ComponentIdentifier{
            httpsig.Component("@method"),
            httpsig.Component("@authority"),
        },
        MaxAge: 5 * time.Minute,
    }, nil)
    if err != nil {
        panic(err)
    }

    fmt.Printf("Verified signature %q signed by key %q\n", result.Label, result.KeyID)
}

HTTP Client Integration

The Transport type wraps any http.RoundTripper to sign outgoing requests automatically:

client := &http.Client{
    Transport: &httpsig.Transport{
        Key: signingKey,
        // Optionally customize what gets signed per-request:
        // Params: func(req *http.Request) httpsig.SignatureParameters { ... },
    },
}

// Every request made with this client will be signed
resp, err := client.Get("https://example.com/api/resource")

For server-side verification, use RequireSignature middleware:

handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("authenticated!"))
})

protected := httpsig.RequireSignature(keyProvider, &httpsig.VerifyOptions{
    RequiredComponents: []httpsig.ComponentIdentifier{
        httpsig.Component("@method"),
        httpsig.Component("@authority"),
    },
})(handler)

http.ListenAndServe(":8080", protected)

See the Integrations Guide for more details.