HTTP Client Integrations
Each language provides drop-in integrations with popular HTTP clients. These handle the signing plumbing so you do not need to manually construct messages and apply headers.
Go: net/http
Signing Client (Transport)
Transport wraps any http.RoundTripper to sign outgoing requests:
import "github.com/zourzouvillys/httpsig/golang"
client := &http.Client{
Transport: &httpsig.Transport{
Key: signingKey,
// Optional: customize label (default "sig1")
Label: "sig1",
// Optional: customize parameters per request
Params: func(req *http.Request) httpsig.SignatureParameters {
return httpsig.SignatureParameters{
Components: []httpsig.ComponentIdentifier{
httpsig.Component("@method"),
httpsig.Component("@path"),
httpsig.Component("@authority"),
httpsig.Component("content-type"),
},
KeyID: signingKey.KeyID(),
Created: httpsig.Int64Ptr(time.Now().Unix()),
}
},
},
}
resp, err := client.Post("https://example.com/api", "application/json", body)
If Params is nil, the default signs @method, @path, and @authority with the current timestamp.
Verifying Server (Middleware)
RequireSignature returns standard http.Handler middleware:
mux := http.NewServeMux()
mux.HandleFunc("/api/resource", handleResource)
protected := httpsig.RequireSignature(keyProvider, &httpsig.VerifyOptions{
RequiredComponents: []httpsig.ComponentIdentifier{
httpsig.Component("@method"),
httpsig.Component("@authority"),
},
MaxAge: 5 * time.Minute,
})(mux)
http.ListenAndServe(":8080", protected)
For custom error handling, use VerifyMiddleware directly:
middleware := &httpsig.VerifyMiddleware{
Provider: keyProvider,
Options: verifyOpts,
OnError: func(w http.ResponseWriter, r *http.Request, err error) {
http.Error(w, "invalid signature: "+err.Error(), http.StatusForbidden)
},
}
http.ListenAndServe(":8080", middleware.Wrap(mux))
TypeScript: fetch
createSigningFetch returns a fetch-compatible function:
import { createSigningFetch } from '@zourzouvillys/httpsig/fetch';
const signedFetch = createSigningFetch({
key: signingKey,
label: 'sig1',
// Optional: customize parameters per request
params: (request) => ({
components: [
component('@method'),
component('@path'),
component('@authority'),
component('content-type'),
],
keyId: 'my-key-id',
created: Math.floor(Date.now() / 1000),
}),
});
const response = await signedFetch('https://example.com/api', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ data: 'value' }),
});
TypeScript: axios
addSigningInterceptor registers a request interceptor on an axios instance:
import axios from 'axios';
import { addSigningInterceptor } from '@zourzouvillys/httpsig/axios';
const client = axios.create({ baseURL: 'https://api.example.com' });
const interceptorId = addSigningInterceptor(client, {
key: signingKey,
label: 'sig1',
});
// All requests through this instance are now signed
const response = await client.post('/resource', { data: 'value' });
// To remove later:
// client.interceptors.request.eject(interceptorId);
TypeScript: undici
createSigningRequest wraps undici's request function:
import { request } from 'undici';
import { createSigningRequest } from '@zourzouvillys/httpsig/undici';
const signedRequest = createSigningRequest(request, {
key: signingKey,
});
const { statusCode, body } = await signedRequest('https://example.com/api', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ data: 'value' }),
});
Java: OkHttp
SigningInterceptor implements OkHttp's Interceptor interface:
import io.zrz.httpsig.okhttp.SigningInterceptor;
var interceptor = new SigningInterceptor(
signingKey,
req -> SignatureParameters.builder()
.component("@method")
.component("@authority")
.component("content-type")
.keyId("my-key")
.created(Instant.now())
.build()
);
var client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
var request = new Request.Builder()
.url("https://example.com/api")
.post(RequestBody.create(json, MediaType.parse("application/json")))
.build();
var response = client.newCall(request).execute();
Java: JDK HttpClient
HttpSigning signs a HttpRequest.Builder in place:
import io.zrz.httpsig.jdkhttp.HttpSigning;
var builder = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json));
HttpSigning.sign(builder, params, signingKey);
var request = builder.build();
var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
Java: Spring WebClient
SigningFilterFunction implements ExchangeFilterFunction:
import io.zrz.httpsig.spring.SigningFilterFunction;
var filter = new SigningFilterFunction(
signingKey,
req -> SignatureParameters.builder()
.component("@method")
.component("@authority")
.keyId("my-key")
.created(Instant.now())
.build()
);
var client = WebClient.builder()
.filter(filter)
.baseUrl("https://example.com")
.build();
var result = client.post()
.uri("/api/resource")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(requestBody)
.retrieve()
.bodyToMono(String.class)
.block();
Swift: URLSession
The HTTPSigURLSession module extends URLRequest with a signed() method:
import HTTPSigURLSession
var request = URLRequest(url: URL(string: "https://example.com/api")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
let signed = try request.signed(label: "sig1", params: params, key: signingKey)
let (data, response) = try await URLSession.shared.data(for: signed)
Swift: Alamofire
The HTTPSigAlamofire module provides a SigningInterceptor that conforms to RequestInterceptor:
import Alamofire
import HTTPSigAlamofire
let interceptor = SigningInterceptor(
key: signingKey,
label: "sig1",
params: params
)
// Use as a session-level interceptor
let session = Session(interceptor: interceptor)
let response = await session.request(
"https://example.com/api",
method: .post,
parameters: ["data": "value"],
encoding: JSONEncoding.default
).serializingData().response
Kotlin: OkHttp
The Kotlin OkHttp integration mirrors the Java one with Kotlin-idiomatic syntax:
import io.zrz.httpsig.okhttp.SigningInterceptor
val interceptor = SigningInterceptor(
key = signingKey,
paramsFactory = { request ->
SignatureParameters.builder()
.component("@method")
.component("@authority")
.component("content-type")
.keyId("my-key")
.created(Instant.now())
.build()
}
)
val client = OkHttpClient.Builder()
.addInterceptor(interceptor)
.build()
val request = Request.Builder()
.url("https://example.com/api")
.post(json.toRequestBody("application/json".toMediaType()))
.build()
val response = client.newCall(request).execute()
Integration Summary
| Language | HTTP Client | Integration Type | Module/Import |
|---|---|---|---|
| Go | net/http (client) | Transport (RoundTripper) |
httpsig |
| Go | net/http (server) | RequireSignature middleware |
httpsig |
| TypeScript | fetch | Wrapper function | @zourzouvillys/httpsig/fetch |
| TypeScript | axios | Request interceptor | @zourzouvillys/httpsig/axios |
| TypeScript | undici | Wrapper function | @zourzouvillys/httpsig/undici |
| Java | OkHttp | Interceptor |
httpsig-okhttp |
| Java | JDK HttpClient | Builder helper | httpsig-jdk-http |
| Java | Spring WebClient | ExchangeFilterFunction |
httpsig-spring-webclient |
| Swift | URLSession | URLRequest.signed() |
HTTPSigURLSession |
| Swift | Alamofire | RequestInterceptor |
HTTPSigAlamofire |
| Kotlin | OkHttp | Interceptor |
httpsig-kotlin-okhttp |