From http-signatures
Reference for org.tomitribe.auth.signatures HTTP Signatures library. TRIGGER when: code imports from org.tomitribe.auth.signatures, or user needs to sign/verify HTTP messages using HMAC, RSA, ECDSA, or DSA (RFC draft Signing HTTP Messages). DO NOT TRIGGER when: working with unrelated authentication or signature libraries.
How this skill is triggered — by the user, by Claude, or both
Slash command
/http-signatures:http-signaturesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Java implementation of HTTP Signature authentication (RFC draft - Signing HTTP Messages). Sign and verify HTTP messages using HMAC, RSA, ECDSA, or DSA algorithms. Zero runtime dependencies.
Java implementation of HTTP Signature authentication (RFC draft - Signing HTTP Messages). Sign and verify HTTP messages using HMAC, RSA, ECDSA, or DSA algorithms. Zero runtime dependencies.
Package: org.tomitribe.auth.signatures
<groupId>org.tomitribe</groupId>
<artifactId>httpSignatures</artifactId>
<version>1.9-SNAPSHOT</version>
// 1. Define signature template
Signature signature = new Signature(
"my-key-id", // keyId
"hs2019", // signingAlgorithm
"hmac-sha256", // algorithm
null, // parameterSpec
Arrays.asList("(request-target)", "host", "date", "content-length")
);
// 2. Create key
Key key = new SecretKeySpec("secret".getBytes(), "HmacSHA256");
// 3. Create reusable, thread-safe signer
Signer signer = new Signer(key, signature);
// 4. Sign request
Map<String, String> headers = new HashMap<>();
headers.put("Host", "example.org");
headers.put("Date", "Tue, 07 Jun 2014 20:51:35 GMT");
headers.put("Content-Length", "18");
Signature signed = signer.sign("POST", "/api/endpoint", headers);
// 5. Set Authorization header
request.setHeader("Authorization", signed.toString());
// "Signature keyId=\"my-key-id\",algorithm=\"hs2019\",..."
// 1. Parse Authorization header
String authHeader = request.getHeader("Authorization");
Signature signature = Signature.fromString(authHeader, Algorithm.HMAC_SHA256);
// 2. Get key for keyId
Key key = lookupKey(signature.getKeyId());
// 3. Verify
Verifier verifier = new Verifier(key, signature);
boolean valid = verifier.verify("POST", "/api/endpoint", headers);
Represents an HTTP signature -- either a template (for signing) or a complete signature (for verification).
// Template for signing
new Signature(keyId, signingAlgorithm, algorithm, parameterSpec, headers)
// Complete signature for verification
new Signature(keyId, signingAlgorithm, algorithm, parameterSpec, signature, headers)
// With time fields
new Signature(keyId, signingAlgorithm, algorithm, parameterSpec, signature, headers,
maxSignatureValidityDuration, signatureCreatedTime, signatureExpiresTime)
// Parse from Authorization header value
Signature sig = Signature.fromString("Signature keyId=\"...\",algorithm=\"...\",...");
Signature sig = Signature.fromString(authHeader, Algorithm.HMAC_SHA256);
sig.toString() // "Signature keyId=\"...\",algorithm=\"...\",..."
sig.toParamString() // parameters without "Signature " prefix
sig.verifySignatureValidityDates() // throws if expired or not yet valid
sig.getSignatureCreation() // Date
sig.getSignatureExpiration() // Date
| Field | Type | Description |
|---|---|---|
keyId | String | REQUIRED. Opaque key identifier |
signingAlgorithm | SigningAlgorithm | HTTP-level algorithm (hs2019, rsa-sha256, etc.) |
algorithm | Algorithm | Cryptographic algorithm (hmac-sha256, rsa-sha256, etc.) |
signature | String | Base64-encoded signature value |
headers | List | HTTP headers included in signature (lowercase) |
parameterSpec | AlgorithmParameterSpec | Optional (e.g., PSSParameterSpec for RSA-PSS) |
Thread-safe, immutable. Create once and reuse across requests.
Signer signer = new Signer(key, signature);
Signer signer = new Signer(key, signature, provider); // custom Provider
Signer signer = new Signer(key, signature, provider, clock); // custom Clock for testing
Signature signed = signer.sign(method, uri, headers);
String signingString = signer.createSigningString(method, uri, headers);
Create a new instance per signature to verify.
Verifier verifier = new Verifier(key, signature);
Verifier verifier = new Verifier(key, signature, provider);
boolean valid = verifier.verify(method, uri, headers);
31 cryptographic algorithms with portable and JVM names.
| Portable Name | JVM Name | Notes |
|---|---|---|
hmac-sha1 | HmacSHA1 | |
hmac-sha224 | HmacSHA224 | |
hmac-sha256 | HmacSHA256 | Recommended |
hmac-sha384 | HmacSHA384 | |
hmac-sha512 | HmacSHA512 |
| Portable Name | JVM Name | Notes |
|---|---|---|
rsa-sha1 | SHA1withRSA | Deprecated |
rsa-sha256 | SHA256withRSA | |
rsa-sha384 | SHA384withRSA | |
rsa-sha512 | SHA512withRSA | |
rsa-sha3-256 | SHA3-256withRSA | |
rsa-sha3-384 | SHA3-384withRSA | |
rsa-sha3-512 | SHA3-512withRSA | |
rsassa-pss | RSASSA-PSS | Requires AlgorithmParameterSpec |
| Portable Name | JVM Name | Notes |
|---|---|---|
ecdsa-sha1 | SHA1withECDSA | |
ecdsa-sha256 | SHA256withECDSA | |
ecdsa-sha384 | SHA384withECDSA | |
ecdsa-sha512 | SHA512withECDSA | |
ecdsa-sha3-256 | SHA3-256withECDSA | |
ecdsa-sha3-384 | SHA3-384withECDSA | |
ecdsa-sha3-512 | SHA3-512withECDSA | |
ecdsa-sha256-p1363 | SHA256withECDSAinP1363Format | |
ecdsa-sha384-p1363 | SHA384withECDSAinP1363Format | |
ecdsa-sha512-p1363 | SHA512withECDSAinP1363Format |
| Portable Name | JVM Name |
|---|---|
dsa-sha1 | SHA1withDSA |
dsa-sha224 | SHA224withDSA |
dsa-sha256 | SHA256withDSA |
dsa-sha384 | SHA384withDSA |
dsa-sha512 | SHA512withDSA |
dsa-sha3-256 | SHA3-256withDSA |
dsa-sha3-384 | SHA3-384withDSA |
dsa-sha3-512 | SHA3-512withDSA |
Algorithm alg = Algorithm.get("hmac-sha256"); // parse from either format
alg.getPortableName() // "hmac-sha256"
alg.getJvmName() // "HmacSHA256"
alg.getType() // Mac.class or java.security.Signature.class
HTTP-level algorithm identifiers (what appears in the Authorization header).
| Value | Algorithm Name | Description |
|---|---|---|
HS2019 | hs2019 | Recommended. Actual algorithm derived from keyId metadata |
RSA_SHA256 | rsa-sha256 | Legacy |
ECDSA_SHA256 | ecdsa-sha256 | Legacy |
HMAC_SHA256 | hmac-sha256 | Legacy |
RSA_SHA1 | rsa-sha1 | Deprecated |
Use HS2019 for new implementations.
Include these in the headers list for the signing string:
| Pseudo-Header | Signing String Line | Description |
|---|---|---|
(request-target) | (request-target): post /api/foo | HTTP method + URI |
(created) | (created): 1591763110 | Signature creation (seconds since epoch) |
(expires) | (expires): 1591766710 | Signature expiration (seconds since epoch) |
Arrays.asList("(request-target)", "(created)", "(expires)", "host", "digest")
Read PEM-encoded keys without Bouncy Castle:
PrivateKey privateKey = PEM.readPrivateKey(new FileInputStream("private.pem"));
PublicKey publicKey = PEM.readPublicKey(new FileInputStream("public.pem"));
Supported PEM formats:
BEGIN RSA PRIVATE KEY (PKCS#1)BEGIN EC PRIVATE KEY (EC PKCS#8)BEGIN PRIVATE KEY (PKCS#8)BEGIN PUBLIC KEY (X.509)BEGIN CERTIFICATE (X.509 certificate)// RSA from DER bytes
RSA.privateKeyFromPKCS8(derBytes)
RSA.privateKeyFromPKCS1(derBytes)
RSA.publicKeyFrom(derBytes)
// EC from DER bytes
EC.privateKeyFromPKCS8(derBytes)
EC.publicKeyFrom(derBytes)
PrivateKey privateKey = PEM.readPrivateKey(new FileInputStream("private.pem"));
Signature signature = new Signature("rsa-key-1", "hs2019", "rsa-sha256", null,
Arrays.asList("(request-target)", "host", "date"));
Signer signer = new Signer(privateKey, signature);
Signature signed = signer.sign("GET", "/resource", headers);
// Verification
PublicKey publicKey = PEM.readPublicKey(new FileInputStream("public.pem"));
Signature parsed = Signature.fromString(signed.toString(), Algorithm.RSA_SHA256);
Verifier verifier = new Verifier(publicKey, parsed);
boolean valid = verifier.verify("GET", "/resource", headers);
Authorization: Signature keyId="my-key",algorithm="hs2019",
created=1591763110,expires=1591766710,
headers="(created) (expires) (request-target) host content-length",
signature="Base64EncodedValue=="
Fields: keyId (required), algorithm (required), headers (required), signature (required), created (optional), expires (optional).
All extend AuthenticationException (RuntimeException):
| Exception | Cause |
|---|---|
MissingKeyIdException | keyId missing from header |
MissingAlgorithmException | algorithm missing from header |
MissingSignatureException | signature missing from header |
MissingRequiredHeaderException | Required header missing from HTTP message |
UnparsableSignatureException | Malformed Authorization header |
UnsupportedAlgorithmException | Algorithm not available |
InvalidCreatedFieldException | (created) field in the future |
InvalidExpiresFieldException | (expires) field in the past |
Clock injection for deterministic testingnpx claudepluginhub tomitribe/claude-plugins --plugin http-signaturesGuides choosing between HMAC and digital signatures for message authentication, including threat context and implementation instructions. Covers webhook verification, JWT signing, and non-repudiation.
Implements JWT signing and verification with HS256, RS256, ES256, and EdDSA, including claims validation, expiration, and defense against algorithm confusion and none algorithm attacks.
Implements secure JWT signing with HS256, RS256, ES256, EdDSA; verifies signatures, claims, expiration; defends against algorithm confusion, none alg, key injection attacks.