Skip to content

How it works

The signed message

URLAuth.sign builds a canonical byte string from the URL and the expiry, then signs it with the configured backend:

  1. The query is parsed and the sig/exp/kid params — plus anything passed to ignore_query_params — are dropped, then sorted and re-encoded. This canonicalisation means signing and verification agree regardless of incoming encoding or the ordering of unrelated parameters.
  2. The expiry, scheme, netloc, path, params, and canonical query are joined with newlines. A newline cannot appear in a URL component, so field boundaries can never be confused (e.g. a value ending in what looks like the next field).
  3. The resulting utf-8 bytes are handed to the backend's sign.

URLAuth.verify rebuilds the same message and checks the signature against every configured key, so a signature made with a rotated-out key still verifies until it expires. With require_kid=True, sign also appends a kid naming the signing key, and verify checks only that key — rejecting URLs whose kid is missing or unknown. The kid isn't signed; it only selects the key, and a forged one simply selects a key that won't verify. HMAC comparisons are constant-time to avoid timing attacks.

Keys and ids

Every key carries a stable id, which must be unique within a KeySet. If you don't supply one, it's a short fingerprint: the first 12 characters of the URL-safe base64 SHA-512 digest of the key bytes.

  • An HMACKey fingerprints the secret itself (safe because SHA-512 is one-way, and repr truncates).
  • An Ed25519KeyPair fingerprints its public bytes, so it shares the id of the matching Ed25519PublicKey and never leaks the seed.

Backends

A Backend owns the algorithm-specific work: parsing key values into Key instances, signing, and verifying. It isn't tied to one algorithm — each key already knows whether it is HMAC or Ed25519, so the backend dispatches on the key's type. Everything algorithm-agnostic — URL canonicalisation, expiry, key rotation — lives in URLAuth. A KeySet pairs a collection of keys with the backend that parses them, and a single keyset can mix HMAC and Ed25519 keys freely.