Metadata-Version: 2.4
Name: botcha-verify
Version: 0.2.0
Summary: Server-side verification middleware for BOTCHA JWT tokens
Project-URL: Homepage, https://botcha.ai
Project-URL: Repository, https://github.com/dupe-com/botcha
Project-URL: Documentation, https://github.com/dupe-com/botcha/tree/main/packages/python-verify
Project-URL: Issues, https://github.com/dupe-com/botcha/issues
Author-email: Ramin <ramin@dupe.com>
License-Expression: MIT
Keywords: authentication,botcha,django,fastapi,jwt,middleware,verification
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Django
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
Classifier: Topic :: Security
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: pyjwt[crypto]>=2.8.0
Provides-Extra: dev
Requires-Dist: django>=4.2; extra == 'dev'
Requires-Dist: fastapi>=0.100.0; extra == 'dev'
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Provides-Extra: django
Requires-Dist: django>=4.2; extra == 'django'
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.100.0; extra == 'fastapi'
Description-Content-Type: text/markdown

# botcha-verify

Server-side verification middleware for BOTCHA JWT tokens.

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

## Installation

```bash
pip install botcha-verify
```

For FastAPI support:
```bash
pip install "botcha-verify[fastapi]"
```

For Django support:
```bash
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.

```python
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.

```python
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

```python
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

```python
# 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:

```python
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
