Use the Weldall SDK with FastAPI to protect a contract API, or start from the Django example.
Weldall validates incoming requests to web services. We provide libraries you can add to your application to check who is making a request and whether they have the required permissions. These checks run before the application reads data or makes changes.
For Python, use weldall-sdk, which supports FastAPI and Django. This guide uses it with FastAPI to build a service that returns a contract list only with the contracts:read permission. The service also publishes a skill: instructions with the command an agent needs to call it.
You need Python 3.11 or newer, uv, and a running Weldall instance. The published package is weldall-sdk on PyPI. Its source and reference live alongside the TypeScript SDK in the Weldall repository.
1. Create the FastAPI project
Section titled “1. Create the FastAPI project”uv init --bare --python 3.11 weldall-contractscd weldall-contractsuv add 'weldall-sdk[fastapi]' uvicornIf you manage dependencies with pip instead, install weldall-sdk[fastapi] and uvicorn in your virtual environment.
2. Protect the contract route
Section titled “2. Protect the contract route”Create app.py:
import os
from fastapi import Depends, FastAPIfrom weldall import generate_es256_key_pair, in_memoryfrom weldall.adapters.fastapi import init_weldall
weldall_issuer = os.environ.get("WELDALL_ISSUER", "https://weldall.example.com")public_origin = os.environ.get("PUBLIC_ORIGIN", "http://localhost:8000")key = generate_es256_key_pair()
weldall = init_weldall( weldall_issuer, { "resource": f"{public_origin}/api", "public_origin": public_origin, "client_id": "weldall-cli-at-contracts", "supported_scopes": ["contracts:read"], "signing_key": { "kid": "development-only", "private_jwk": key["private_jwk"], "public_jwk": key["public_jwk"], }, "replay_store": in_memory(), "skills": { "items": [ { "id": "list", "title": "List contracts", "requiredScopes": ["contracts:read"], "visibility": "HIDDEN_IF_UNALLOWED", "content": ( "# List contracts\n\nRun `weldall request --scope contracts:read " f"{public_origin}/api/contracts`." ), } ] }, "allow_insecure_loopback": public_origin == "http://localhost:8000", },)
app = FastAPI()weldall.register_routes(app)
@app.get("/api/contracts")def contracts(auth=Depends(weldall.require_auth({"scopes": ["contracts:read"]}))): return { "requested_by": auth.identity.subject, "contracts": [ {"id": "contract-1001", "customer": "Nordstern GmbH", "status": "active"}, {"id": "contract-1002", "customer": "Südwind AG", "status": "review"}, ], }register_routes() adds discovery, signing-key, token, and skill routes. The require_auth() dependency checks authorization before FastAPI calls the contract handler. The handler receives the verified identity as auth. How you map it to your own user records is up to your application.
Python options use names such as public_origin and supported_scopes. Skill fields such as requiredScopes keep their wire-format spelling. The skill’s visibility setting hides it from employees without contracts:read; it does not replace the route’s authorization check.
3. Check the service locally
Section titled “3. Check the service locally”Set WELDALL_ISSUER to your Weldall instance and start the service:
WELDALL_ISSUER=https://weldall.example.com \PUBLIC_ORIGIN=http://localhost:8000 \uv run uvicorn app:app --port 8000In another terminal, check discovery and the protected route:
curl -i http://localhost:8000/.well-known/oauth-protected-resourcecurl -i http://localhost:8000/api/contractsDiscovery returns 200 with the resource identifier http://localhost:8000/api. The contract request returns 401 because it has no Weldall authorization. These checks do not require a CLI login. You can also call weldall.ready() during startup to check issuer discovery and signing configuration before serving requests.
4. Deploy and register the service
Section titled “4. Deploy and register the service”In production, use HTTPS and load your ES256 signing key from configuration rather than generating a new one on every start as the example does.
Deploy the service at https://contracts.example.com and set PUBLIC_ORIGIN to that exact URL. Keep WELDALL_ISSUER set to your Weldall instance. The resource identifier becomes https://contracts.example.com/api, and the skill uses the deployed URL.
Continue with registration and permission assignment. Those steps are the same for TypeScript and Python.
Examples on GitHub
Section titled “Examples on GitHub”Each README lists the commands to run the example. Both examples protect /api/expenses with expenses:read, but do not publish skills.
