Skip to main content

fiki (Python)

Python

The Python implementation of fiki. Requires Python 3.11 or newer, and depends on cryptography and http-sfv and on nothing else.

From a fresh clone to passing tests

cd py
uv sync
uv run pytest

The suite enforces 100% branch coverage; a gap needs an approved deviation: node in the repo's this.i.

Signing a request

from fiki import Key, sign_request

key = Key.generate()
print(key.aid)            # register this once with whoever you call
print(key.seed.hex())     # 32 bytes; persist them somewhere the cron job can read

url = "https://api.example.com/things?limit=1"
body = b'{"hello": "world"}'
headers = sign_request(key=key, method="POST", url=url, body=body)

By default the signature binds the method, the host, the path, the query string, and a digest of the body. Pass the body wherever you pass the URL: fiki covers a body it is given, or refuses to sign — but it cannot cover one it never sees.

Verifying a request

from fiki import verify_request

verdict = verify_request(
    method=request.method,
    url=request.url,      # a full URL, or a path plus a Host header
    headers=request.headers,
    body=request.body,
    max_age=300,          # seconds, or None to decline the check
)
verdict.aid               # who signed it

max_age has no default and must be given. Both defaults would be wrong: a number guesses at somebody else's clock skew and replay window, and skipping the check silently is the thing the argument exists to prevent. An expires the signer declared is enforced either way.

Other spellings of a key

aid_from converts a public key given as raw base64url (a JWK's x), a base58btc did:key, a did:peer:0, or an ssh-ed25519 line into the AID to register, and Key.from_openssh signs with an unencrypted OpenSSH private key (this.i @0mvgkwnl). Call aid_from when you load registrations rather than per request. Both refuse anything ambiguous as MalformedKey; the user guide lists what that covers.

from pathlib import Path
from fiki import Key, aid_from

aid = aid_from("did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK")
key = Key.from_openssh(Path("fiki_ed25519").read_text())

Responses, resolved keyids, and a minimum covered set

These exist for the KERI profile of RFC 9421 (this.i @7f28p7xk, @6g9zjsv9). Every port has them; the user guide shows each one's spelling.

from fiki import (REQUEST_MINIMUM, RESPONSE_MINIMUM, Request, sign_request, sign_response,
                  verify_request, verify_response)

# A keyid that is not the key itself, such as a KERI AID, needs a resolver on the verify side.
# The resolver returns the 32 raw bytes of the key, or None; fiki never decodes the keyid itself.
headers = sign_request(key=key, method="POST", url=url, body=body, keyid=aid)
verdict = verify_request(method="POST", url=url, headers=headers, body=body, max_age=300,
                         resolve=current_key_for, minimum=REQUEST_MINIMUM)

# A response binds the request it answers with RFC 9421's req parameter.
asked = Request(method="POST", url=url, headers=request_headers, body=body)
signed = sign_response(key=key, status=200, request=asked, body=reply)
verify_response(status=200, headers=signed, body=reply, request=asked, max_age=300,
                minimum=RESPONSE_MINIMUM)

minimum refuses a signature that covers less than the named components even when it is valid, and refuses a body — Content-Length above zero, any Transfer-Encoding, or one that simply arrived — whose content-digest is not covered. The method is signed exactly as given, with no case change, so pass it as it will go on the wire.

minimum=None, the default, enforces nothing: a body handed to verify_request with no covered content-digest is then accepted, and only the verdict's covered shows it. Pass a minimum whenever you hand over a body. Signers take the same minimum and refuse to cover less. A client checking a response should pass expected_keyid, the AID it is talking to; a server should pass authorities, the set it serves, which also makes @authority required: a signature that does not cover it is InsufficientCoverage. An unsigned 401 is Unauthenticated, and a resolver raises UnsupportedSigner for a key state with no single effective signer.

Conformance

tests/test_rfc9421_conformance.py signs RFC 9421's own Appendix B.2.6 request with the RFC's own published Ed25519 key and asserts the RFC's own signature, byte for byte. tests/test_vectors.py runs the shared vectors/ at the repository root, which every port runs. tests/test_keri_vectors.py runs vectors/keri/, the KERI profile's set, which only this port runs so far.

Metadata

Release files for fiki 0.10.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fiki 0.10.0
File Size Uploaded
fiki-0.10.0.tar.gz 124.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fiki 0.10.0
File Interpreter ABI Platform
fiki-0.10.0-py3-none-any.whl Python 3 none any Details

Total release size: 169.4 kB

Release files / fiki-0.10.0.tar.gz

Download URL fiki-0.10.0.tar.gz
Size 124.9 kB
Tags Source
SHA-256 checksum
How to use checksums
f80ccaa3a006fdd7ed1d4b4e4bc799178d6b82b41b0537844a8651e34da8af03
BLAKE2b-256 checksum
How to use checksums
9d353082f6f7192ae19f01a4f6abc9f7a5de7ab59ddc9b0a4ee77af2cdb17ff4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / fiki-0.10.0-py3-none-any.whl

Download URL fiki-0.10.0-py3-none-any.whl
Size 44.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
240c93591cd5c462af8e93c7ee4bea0dc24ad64d7a047757261d2b1743b16e1c
BLAKE2b-256 checksum
How to use checksums
b715d9fabf7dca31aefc33d9d4fbce2e5051ce2200517968bb15f37760709b24
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.10.0 This release

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page