fipsign-sdk
Post-quantum signing SDK for Python. Signs and verifies any payload using ML-DSA-65 (NIST FIPS 204) — resistant to Shor's algorithm, standardized by NIST in August 2024.
Not just for auth. Sign users, orders, documents, devices, AI agents, events — any entity that needs a tamper-proof, quantum-resistant signature.
📖 Full documentation, API reference, and guides →
Install
pip install fipsign-sdk
For async support (httpx-based):
pip install fipsign-sdk[async]
Quick start
- Create a free account at app.fipsign.dev.
- In the dashboard, create a project, then create an API key inside it. Save the key — it won't be shown again.
- Use it:
from fipsign import PQAuth
pq = PQAuth("pqa_your_api_key")
result = pq.sign("user_123", role="admin")
token = result.token
verified = pq.verify(token)
if not verified.valid:
raise PermissionError("invalid token")
print(verified.payload["sub"]) # "user_123"
That's signing and verifying. The SDK also covers async usage (AsyncPQAuth), Flask/FastAPI middleware, offline (in-memory) verification, revocation, webhooks, and a full Certificate Authority module (PQCert + X.509) for issuing post-quantum certificates to devices and services — all in the developer guide.
Mandate — authorization for AI agents
Give an agent a bounded, revocable credential: which actions it may perform, how much it may spend, and until when. Check every action with one call, and suspend or revoke the mandate at any time.
result = pq.mandate.emit(
agent_id="agent-reporting-v2",
issued_by="user@empresa.com",
scope=["read:crm", "send_reply"],
budget_total=1000,
expires_in_seconds=28800,
)
check = pq.mandate.verify(result.mandate.token, "send_reply", 1)
if check.result != "granted":
raise PermissionError(check.reason)
To make a copied token useless on its own, emit the mandate with the agent's public key (agent_public_key=): the agent then signs every call with its private key (generate_agent_key_pair() and sign_agent_call()). Details in the Mandate section of the guide.
When verify() says no
verify() never raises. When valid is False, failure says why:
failure |
Meaning | What to do |
|---|---|---|
"rejected" |
The token is not acceptable (bad signature, expired, revoked, ...) | Answer 401 |
"rate_limited" |
Too many requests in the current minute. The token was not checked | Wait retry_after seconds and try again |
"quota_exhausted" |
Free tokens and packs used up. The token was not checked | Buy a pack from the dashboard |
"unavailable" |
FIPSign could not answer (timeout, network, server error, invalid API key). The token was not checked | Try again; answer 503 |
verified = pq.verify(token)
if not verified.valid and verified.failure == "rejected":
raise PermissionError("invalid token") # the token is bad
if not verified.valid:
raise RuntimeError("could not check the token, try again") # not the token's fault
flask_middleware() and fastapi_middleware() do this for you: 401 for a refused token, 503 (with Retry-After when known) for the rest.
Check the revocation list of your CA
ca.get_crl() returns the certificates your CA has revoked, and the list is signed by the CA (ML-DSA-65). ca.verify_crl() checks that signature offline, so a list that was altered on the way, or that belongs to another CA, is not taken as good:
revocations = pq.ca.get_crl()
check = pq.ca.verify_crl(revocations, root_cert) # the CA_ROOT you saved when the CA was created (a PEM string for an X.509 CA)
if not check.valid:
raise RuntimeError(check.error)
if pq.ca.is_cert_revoked(cert, revocations.crl):
raise PermissionError("revoked")
The signature covers generatedAt, so an old list cannot pass as a new one, but a correctly signed old list is still valid: check.generatedAt tells you when it was made, and how old a list you accept is up to you. verify_crl() is offline, so it is a plain call with AsyncPQAuth too. Details: the CA chapter of the guide.
Why ML-DSA-65?
JWT with RS256/ES256 and standard OAuth tokens rely on ECDSA or RSA — both breakable by Shor's algorithm on a sufficiently powerful quantum computer. ML-DSA-65 is based on lattice problems (Module-LWE / Module-SIS) with no known quantum speedup. Standardized by NIST in August 2024 as FIPS 204.
Links
- 📖 Developer guide — full API reference, error codes, webhooks, CA/X.509
- Dashboard: app.fipsign.dev
- API status: status.fipsign.dev
- NIST FIPS 204: csrc.nist.gov/pubs/fips/204/final
Metadata
Release files for fipsign-sdk 0.15.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fipsign_sdk-0.15.0.tar.gz | 54.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fipsign_sdk-0.15.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 113.5 kB
Release files / fipsign_sdk-0.15.0.tar.gz
| Download URL | fipsign_sdk-0.15.0.tar.gz |
|---|---|
| Size | 54.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ce1dc5a79d20db2ef8e9de2aeff6905b7270e0e49349ad5a9aad938511cf3070
|
|
BLAKE2b-256 checksum How to use checksums |
56b1e5979992b7deb13cb539b422354ed4d03fffb636b61d42c7195e7e9fb5e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|
Release files / fipsign_sdk-0.15.0-py3-none-any.whl
| Download URL | fipsign_sdk-0.15.0-py3-none-any.whl |
|---|---|
| Size | 58.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a0c6b633176cc952e4a10d30b91df92ce766fa5105db6ca0f2a5525a5e2cd04c
|
|
BLAKE2b-256 checksum How to use checksums |
300afc96204720875de04cdf142dbecace50e56bc35985998847f4d3fd5d6f4a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.2
|