Server-side verification middleware for BOTCHA JWT tokens.
Supports both JWKS-based ES256 verification (recommended) and shared-secret HS256 verification (legacy).
pip install botcha-verifyFor FastAPI support:
pip install "botcha-verify[fastapi]"For Django support:
pip install "botcha-verify[django]"Note: The
[crypto]extra (cryptography) is included automatically for ES256 key support.
Fetches BOTCHA's public key from the JWKS endpoint. No shared secret to manage.
from botcha_verify import verify_botcha_token, VerifyOptions
result = verify_botcha_token(
token="eyJhbG...",
options=VerifyOptions(
jwks_url="https://botcha.ai/.well-known/jwks",
audience="https://api.example.com",
)
)
if result.valid:
print(f"Challenge solved in {result.payload.solve_time}ms")
else:
print(f"Invalid token: {result.error}")Still supported for existing HS256 integrations.
from botcha_verify import verify_botcha_token, VerifyOptions
result = verify_botcha_token(
token="eyJhbG...",
secret="your-secret-key",
options=VerifyOptions(audience="https://api.example.com")
)from fastapi import FastAPI, Depends
from botcha_verify.fastapi import BotchaVerify
from botcha_verify import BotchaPayload
app = FastAPI()
# RECOMMENDED: JWKS verification
botcha = BotchaVerify(jwks_url='https://botcha.ai/.well-known/jwks')
# LEGACY: Shared secret
# botcha = BotchaVerify(secret='your-secret-key')
@app.get('/api/data')
async def get_data(token: BotchaPayload = Depends(botcha)):
return {"solve_time": token.solve_time}# settings.py
MIDDLEWARE = [
# ... other middleware
'botcha_verify.django.BotchaVerifyMiddleware',
]
# RECOMMENDED: JWKS verification
BOTCHA_JWKS_URL = 'https://botcha.ai/.well-known/jwks'
# LEGACY: Shared secret
# BOTCHA_SECRET = 'your-secret-key'
BOTCHA_PROTECTED_PATHS = ['/api/']
BOTCHA_EXCLUDED_PATHS = ['/api/health']
# views.py
def my_view(request):
if hasattr(request, 'botcha'):
print(f"Solved in {request.botcha.solve_time}ms")
return JsonResponse({"data": "protected"})During the transition period, provide both secret and jwks_url. JWKS is tried first with a fallback to the shared secret:
result = verify_botcha_token(
token="eyJhbG...",
secret="your-secret-key", # fallback during migration
options=VerifyOptions(
jwks_url="https://botcha.ai/.well-known/jwks",
audience="https://api.example.com",
)
)BOTCHA JWT tokens contain:
sub: Challenge IDiss: Issuer (botcha.ai, validated in JWKS mode)iat: Issued at (Unix timestamp)exp: Expiry (Unix timestamp)jti: JWT ID for revocationtype: "botcha-verified"solveTime: Challenge solve time in millisecondsaud: (optional) Audience claimclient_ip: (optional) Client IP binding
MIT