Skip to main content

botcha-verify

Server-side verification middleware for BOTCHA JWT tokens.

Supports both JWKS-based ES256 verification (recommended) and shared-secret HS256 verification (legacy).

Installation

pip install botcha-verify

For 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.

Usage

JWKS Verification (Recommended)

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}")

Legacy: Shared Secret Verification

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")
)

FastAPI

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}

Django

# 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"})

Migration from Shared Secret to JWKS

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",
    )
)

Token Structure

BOTCHA JWT tokens contain:

  • sub: Challenge ID
  • iss: Issuer (botcha.ai, validated in JWKS mode)
  • iat: Issued at (Unix timestamp)
  • exp: Expiry (Unix timestamp)
  • jti: JWT ID for revocation
  • type: "botcha-verified"
  • solveTime: Challenge solve time in milliseconds
  • aud: (optional) Audience claim
  • client_ip: (optional) Client IP binding

License

MIT

Metadata

Release files for botcha-verify 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for botcha-verify 0.2.0
File Size Uploaded
botcha_verify-0.2.0.tar.gz 9.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for botcha-verify 0.2.0
File Interpreter ABI Platform
botcha_verify-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 19.0 kB

Release files / botcha_verify-0.2.0.tar.gz

Download URL botcha_verify-0.2.0.tar.gz
Size 9.4 kB
Tags Source
SHA-256 checksum
How to use checksums
1691cb899fce05a02a3c863681ce5e1e457d6aa5f8cf4d171a97f89d409c1190
BLAKE2b-256 checksum
How to use checksums
9f8a79e6774c82272c62eca6d37c41d37a1615865970f27c195dfe037adff4c5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.9

Release files / botcha_verify-0.2.0-py3-none-any.whl

Download URL botcha_verify-0.2.0-py3-none-any.whl
Size 9.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
733ffef6af92eb14438c4deaf1cbfdb224c01facafa753d95ffd6058f40097fa
BLAKE2b-256 checksum
How to use checksums
6bfc52434355bee9962fe20003b0ff2e89fff9fa2eede1ac4c2a08a72188586e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.9

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page