Skip to content
SDKs · PythonIn development

rootherald

The server-side Python SDK. Default path: server→server Background-Check attest (appraise client evidence with your rh_sk_ secret key, verdict returned directly). Also verifies portable token JWTs against your project's JWKS. Pure Python — no native dependencies. Runs anywhere Python 3.10+ does.

In development

This SDK is implemented but not yet published to its package registry. Until it ships, mint attestation tokens on the device and verify them server-side with @rootherald/node (or any available server SDK). The API shown below is the planned surface and may change before release.

Attesting on the user's device?

If you need to performattestation (Python running on the end-user's machine, talking to a local TPM / Secure Enclave / TEE), you want rootherald-py instead — that ships as a separate package because it pulls in the native C library. Most server-side use cases want this package.

Install

pipbash
pip install rootherald

Verify a token

app.pypython
import rootherald

client = rootherald.Client(
    issuer="https://rootherald.io/myorg",
    jwks_uri="https://rootherald.io/myorg/.well-known/jwks.json",
)
claims = client.verify_token(token)

if claims.verdict is rootherald.Verdict.PASS:
    proceed_with_signup(user_id=claims.sub, device_id=claims.device.ueid)

FastAPI guard

main.pypython
from fastapi import FastAPI
import rootherald
from rootherald.fastapi import RootHeraldGuard, configure

app = FastAPI()
configure(rootherald.Client(issuer="https://rootherald.io/myorg"))

@app.post("/signup", dependencies=[RootHeraldGuard(action="signup")])
async def signup():
    return {"ok": True}

RootHeraldGuard reads the bearer token from the Authorization header (or X-RootHerald-Token) and rejects FAIL verdicts with a 403. Pass deny_on_warn=True to reject WARN as well.

Flask middleware

app.pypython
from flask import Flask
import rootherald
from rootherald.flask import guard_device, configure, current_claims

app = Flask(__name__)
configure(rootherald.Client(issuer="https://rootherald.io/myorg"))

@app.post("/signup")
@guard_device(action="signup")
def signup():
    claims = current_claims()
    return {"ok": True, "device": claims.device.ueid}