openkitx403 — Python Server SDK
FastAPI middleware for OpenKitx403 wallet-based authentication. Add Solana wallet verification to any API endpoint with one line.
🚀 Installation
pip install openkitx403
# or
poetry add openkitx403
⚡ Quick Start
from fastapi import FastAPI, Depends
from openkitx403 import OpenKit403Middleware, require_openkitx403_user
app = FastAPI(title="My Wallet-Protected API")
# Attach OpenKitx403 middleware
app.add_middleware(
OpenKit403Middleware,
audience="https://api.example.com",
issuer="my-api-v1",
ttl_seconds=60,
bind_method_path=False, # Set True to bind challenges to specific paths
origin_binding=False,
replay_backend="memory"
)
@app.get("/protected")
async def protected(user = Depends(require_openkitx403_user)):
"""Example protected endpoint"""
return {
"message": f"Authenticated as {user.address}",
"wallet": user.address
}
@app.get("/public")
async def public():
"""Public endpoint - no authentication required"""
return {"message": "Hello World"}
🔒 Optional Token Gating
from openkitx403 import OpenKit403Middleware
from solana.rpc.api import Client
from solders.pubkey import Pubkey
solana_client = Client("https://api.mainnet-beta.solana.com")
async def check_token_holder(address: str) -> bool:
"""Example: verify wallet holds specific token"""
try:
pubkey = Pubkey.from_string(address)
resp = solana_client.get_token_accounts_by_owner(
pubkey,
opts={"mint": str(Pubkey.from_string("YOUR_TOKEN_MINT"))}
)
return len(resp.value) > 0
except Exception as e:
print("Token check failed:", e)
return False
app.add_middleware(
OpenKit403Middleware,
audience="https://api.example.com",
issuer="my-api-v1",
token_gate=check_token_holder,
)
🛤️ Exclude Paths from Authentication
app.add_middleware(
OpenKit403Middleware,
audience="https://api.example.com",
issuer="my-api-v1",
excluded_paths=["/health", "/docs", "/openapi.json"]
)
🧩 API Reference
OpenKit403Middleware
FastAPI middleware that adds OpenKitx403 authentication to your routes.
Configuration Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
audience |
str |
required | Expected API audience/origin |
issuer |
str |
required | Server identifier |
ttl_seconds |
int |
60 |
Challenge TTL in seconds |
clock_skew_seconds |
int |
120 |
Allowed clock skew for timestamp validation |
bind_method_path |
bool |
False |
Bind challenge to specific HTTP method/path |
origin_binding |
bool |
False |
Enable origin header validation |
ua_binding |
bool |
False |
Enable user-agent header validation |
replay_backend |
str |
"memory" |
Replay protection backend |
token_gate |
Callable[[str], bool] |
None |
Optional async function for wallet gating |
excluded_paths |
list[str] |
None |
Paths that bypass authentication |
🔐 Token Gate Function Signature
Your token gate function must:
- Accept a single
address: strparameter (base58-encoded public key) - Return
bool(True = allowed, False = denied) - Can be async or sync
async def my_token_gate(address: str) -> bool:
# Your validation logic
return True # or False
🎯 Accessing User Information
Use the require_openkitx403_user dependency to access authenticated user:
from fastapi import Depends
from openkitx403 import require_openkitx403_user, OpenKit403User
@app.get("/profile")
async def profile(user: OpenKit403User = Depends(require_openkitx403_user)):
return {
"address": user.address,
"challenge": user.challenge # Original challenge object
}
🔧 Custom Replay Store
By default, middleware uses in-memory replay protection. For production with multiple servers:
from openkitx403 import ReplayStore
class RedisReplayStore:
"""Example Redis-based replay store"""
def __init__(self, redis_client):
self.redis = redis_client
async def check(self, key: str, ttl_seconds: int) -> bool:
return await self.redis.exists(key)
async def store(self, key: str, ttl_seconds: int) -> None:
await self.redis.setex(key, ttl_seconds, "1")
# Use custom store
app.add_middleware(
OpenKit403Middleware,
audience="https://api.example.com",
issuer="my-api-v1",
replay_store=RedisReplayStore(redis_client)
)
🔑 Dependencies
fastapi- Web frameworkstarlette- ASGI toolkitsolders- Solana SDK (for types)base58- Base58 encodingpynacl- Ed25519 signature verification
📚 Documentation
🪪 License
Metadata
Release files for openkitx403 0.1.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| openkitx403-0.1.5.tar.gz | 8.0 kB | Without provenance | Details for openkitx403-0.1.5.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| openkitx403-0.1.5-py3-none-any.whl | Python 3 | none | any | Details for openkitx403-0.1.5-py3-none-any.whl |
Total release size: 17.1 kB
Release files / openkitx403-0.1.5.tar.gz
| Download URL | openkitx403-0.1.5.tar.gz |
|---|---|
| Size | 8.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e8fd34d5f37b31c4c39ceecca200db5da4d42e2c6f5effd09faf7a4b01207549
|
|
BLAKE2b-256 checksum How to use checksums |
af8f523377cb7ce0afb5e745dc965e45bd71b2acefe4ef5a44f89ffc9696d418
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.2.1 CPython/3.13.6 Windows/11
|
Release files / openkitx403-0.1.5-py3-none-any.whl
| Download URL | openkitx403-0.1.5-py3-none-any.whl |
|---|---|
| Size | 9.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bb370f2041b2000d137ac3e3146f82e7564626e991ac5161b05e9d105a32f4a3
|
|
BLAKE2b-256 checksum How to use checksums |
fe6af0faedd0954f28822bacfa03382159ae9a814aff9e4b2325147d6763d729
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.2.1 CPython/3.13.6 Windows/11
|
Security for openkitx403 0.1.5
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.