Skip to content

apsig.draft

An implementation of HTTP signatures compliant with the draft-cavage-http-signatures-12

apsig.draft.Signer

Class for signing HTTP signatures.

You can import directly from apsig.draft:

from apsig.draft import Signer

Example

import json

from apsig.draft import Signer
from cryptography.hazmat.primitives.asymmetric import rsa

private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)

# HTTP Request Details (Here we use dummy, actually copying this code will not work)
method = "POST"
url = "https://example.com/api"
headers = {
    "Content-Type": "application/json",
    "Date": "Wed, 21 Oct 2015 07:28:00 GMT",
}
body = {"key": "value"}
signer = Signer(
    headers=headers,
    private_key=private_key,
    method=method,
    url=url,
    key_id="https://example.com/users/johndoe#main-key",
    body=body,
)
parameter type description
private_key cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey The RSA private key used to sign the request.
method str The HTTP method (e.g., GET, POST).
url str The URL of the request.
headers dict A dictionary of HTTP headers that will be signed.
key_id str The key identifier to include in the signature header.
body bytes or dict The request body. Defaults to an empty byte string.

apsig.draft.Signer.sign

Create HTTP Signature.

Example

...
signed_headers = signer.sign()

print(signed_headers) # signed headers

apsig.draft.Verifier

Class for verifying HTTP signatures.

You can import directly from apsig.draft:

from apsig.draft import Verifier

Example

import json

from apsig.draft import Verifier

public_key = """
-----BEGIN PUBLIC KEY-----
... (RSA PublicKey Here)
-----END PUBLIC KEY-----
""" # or cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey

# HTTP Request Details (Here we use dummy, actually copying this code will not work)
method = "POST"
url = "https://example.com/api"
headers = {
    "Content-Type": "application/json",
    "Date": "Wed, 21 Oct 2015 07:28:00 GMT",
    "signature": 'keyId="my-key-id",algorithm="rsa-sha256",headers="(request-target) Content-Type Date",signature="..."',
    "digest": "SHA-256=...",
}
body = {"key": "value"}
verifier = Verifier(public_key, method, url, headers, body)

Warning

The body is also acceptable in bytes format, but should be passed as dict for dictionary types since verification may fail.

parameter type description
public_pem str Public key in PEM format or cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey format used to verify signatures.
method str The HTTP method (e.g., GET, POST).
url str The URL of the request.
headers dict A dictionary of HTTP headers, including the signature and other relevant information.
body bytes or dict The request body. Defaults to an empty byte string.

apsig.draft.Verifier.verify

Verify signatures.

parameter type description
raise_on_fail bool Whether to return an error on verification failure. Default is False.

Example

...
result = verifier.verify()

print(result) # keyId or None (failed)

Errors

The following will only occur if the raise_on_fail argument is passed as True when calling Verifier.verify:

  • apsig.exceptions.MissingSignature: Occurs when the Signature header is not present in the signed text.
  • apsig.exceptions.UnknownSignature: Occurs when signed using an unsupported algorithm.
  • apsig.exceptions.VerificationFailed: This occurs when the signature is invalid, the Digest does not match, the Date header value is more than a certain amount of time past the current time, etc.