Name | ayz-auth JSON |
Version |
0.2.14
JSON |
| download |
home_page | None |
Summary | FastAPI middleware for Stytch B2B authentication with Redis caching |
upload_time | 2025-07-22 21:04:57 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.8 |
license | MIT |
keywords |
authentication
b2b
fastapi
middleware
stytch
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# ayz-auth
FastAPI middleware for Stytch B2B authentication with Redis caching.
## Overview
`ayz-auth` is a lightweight, production-ready authentication middleware for FastAPI applications using Stytch B2B authentication services. It provides session token verification with Redis caching for optimal performance and includes comprehensive error handling and logging.
## Features
- ๐ **Stytch B2B Integration**: Seamless integration with Stytch B2B authentication
- โก **Redis Caching**: Intelligent caching to reduce API calls and improve performance
- ๐ **FastAPI Native**: Built specifically for FastAPI with proper dependency injection
- ๐ **Type Safe**: Full Pydantic models with type hints throughout
- ๐ก๏ธ **Security First**: Secure token handling with configurable logging levels
- ๐ง **Configurable**: Environment-based configuration with sensible defaults
- ๐ **Comprehensive Logging**: Structured logging with sensitive data protection
- ๐งช **Well Tested**: Comprehensive test suite with mocking support
## Installation
```bash
pip install ayz-auth
```
Or with UV:
```bash
uv add ayz-auth
```
## Quick Start
### 1. Environment Configuration
Create a `.env` file or set environment variables:
```bash
STYTCH_PROJECT_ID=your_project_id
STYTCH_SECRET=your_secret_key
STYTCH_ENV=test # or "live" for production
# STYTCH_ORGANIZATION_ID=your_org_id # optional, only needed for member search operations
REDIS_URL=redis://localhost:6379
```
### 2. Basic Usage
```python
from fastapi import FastAPI, Depends
from ayz_auth import verify_auth, StytchContext
app = FastAPI()
@app.get("/protected")
async def protected_route(user: StytchContext = Depends(verify_auth)):
return {
"message": f"Hello {user.member_email}",
"member_id": user.member_id,
"organization_id": user.organization_id
}
@app.get("/user-info")
async def get_user_info(user: StytchContext = Depends(verify_auth)):
return {
"member_id": user.member_id,
"email": user.member_email,
"name": user.member_name,
"organization_id": user.organization_id,
"session_expires_at": user.session_expires_at,
"authentication_factors": user.authentication_factors
}
```
### 3. Optional Authentication
For endpoints that work with or without authentication:
```python
from typing import Optional
from ayz_auth import verify_auth_optional
@app.get("/optional-auth")
async def optional_route(user: Optional[StytchContext] = Depends(verify_auth_optional)):
if user:
return {"message": f"Hello {user.member_email}"}
else:
return {"message": "Hello anonymous user"}
```
### 4. Custom Authentication Requirements
Create custom dependencies with additional requirements:
```python
from ayz_auth import create_auth_dependency
# Require specific custom claims
admin_auth = create_auth_dependency(required_claims=["admin"])
moderator_auth = create_auth_dependency(required_claims=["moderator", "verified"])
# Require specific authentication factors
mfa_auth = create_auth_dependency(required_factors=["mfa"])
@app.get("/admin")
async def admin_route(user: StytchContext = Depends(admin_auth)):
return {"message": "Admin access granted"}
@app.get("/sensitive")
async def sensitive_route(user: StytchContext = Depends(mfa_auth)):
return {"message": "MFA verified access"}
```
## Configuration
All configuration is handled through environment variables with the `STYTCH_` prefix:
| Variable | Default | Description |
|----------|---------|-------------|
| `STYTCH_PROJECT_ID` | *required* | Your Stytch project ID |
| `STYTCH_SECRET` | *required* | Your Stytch secret key |
| `STYTCH_ENV` | `test` | Stytch environment (`test` or `live`) |
| `STYTCH_REDIS_URL` | `redis://localhost:6379` | Redis connection URL |
| `STYTCH_REDIS_PASSWORD` | `None` | Redis password (if required) |
| `STYTCH_REDIS_DB` | `0` | Redis database number |
| `STYTCH_CACHE_TTL` | `300` | Cache TTL in seconds (5 minutes) |
| `STYTCH_CACHE_PREFIX` | `ayz_auth` | Redis key prefix |
| `STYTCH_LOG_LEVEL` | `INFO` | Logging level |
| `STYTCH_LOG_SENSITIVE_DATA` | `False` | Log sensitive data (never in production) |
| `STYTCH_REQUEST_TIMEOUT` | `10` | Request timeout in seconds |
| `STYTCH_MAX_RETRIES` | `3` | Maximum retry attempts |
## StytchContext Model
The `StytchContext` model contains all the essential session data from Stytch:
```python
class StytchContext(BaseModel):
# Core identifiers
member_id: str
session_id: str
organization_id: str
# Session timing
session_started_at: datetime
session_expires_at: datetime
session_last_accessed_at: datetime
authenticated_at: datetime
# Member information
member_email: Optional[str]
member_name: Optional[str]
# Session metadata
session_custom_claims: Dict[str, Any]
authentication_factors: List[str]
raw_session_data: Dict[str, Any]
# Utility properties
@property
def is_expired(self) -> bool: ...
@property
def time_until_expiry(self) -> Optional[float]: ...
```
## Error Handling
The middleware provides structured error responses:
```python
# 401 Unauthorized - Missing or invalid token
{
"error": "authentication_failed",
"message": "Authorization header is required",
"type": "token_extraction"
}
# 401 Unauthorized - Token verification failed
{
"error": "authentication_failed",
"message": "Invalid or expired session token",
"type": "token_verification"
}
# 503 Service Unavailable - Stytch API issues
{
"error": "service_unavailable",
"message": "Authentication service temporarily unavailable",
"type": "stytch_api"
}
# 403 Forbidden - Insufficient permissions (custom auth)
{
"error": "insufficient_permissions",
"message": "Missing required claims: ['admin']",
"type": "authorization"
}
# 403 Forbidden - Insufficient authentication factors (custom auth)
{
"error": "insufficient_authentication",
"message": "Missing required authentication factors: ['mfa']",
"type": "authorization"
}
```
## Caching Strategy
The middleware implements a two-tier verification system:
1. **Redis Cache Check**: Fast lookup of previously verified tokens
2. **Stytch API Fallback**: Fresh verification when cache misses
Cache entries automatically expire based on the session expiration time, ensuring security while maximizing performance.
## Integration with Your User System
Since the middleware only returns Stytch session data, you can easily integrate it with your existing user system:
```python
from your_app.models import User
from your_app.database import get_user_by_stytch_member_id
@app.get("/profile")
async def get_profile(stytch: StytchContext = Depends(verify_auth)):
# Use the member_id to fetch your user data
user = await get_user_by_stytch_member_id(stytch.member_id)
if not user:
raise HTTPException(404, "User not found")
# Check permissions using your user model
if "read_profile" not in user.permissions:
raise HTTPException(403, "Insufficient permissions")
return {
"stytch_data": stytch.to_dict(),
"user_data": user.to_dict()
}
```
## Development
### Running Tests
```bash
# Install development dependencies
uv sync --dev
# Run tests
pytest
# Run tests with coverage
pytest --cov=ayz_auth
```
### Code Quality
```bash
# Format code
black src/ tests/
isort src/ tests/
# Lint code
ruff check src/ tests/
# Type checking
mypy src/
```
## Contributing
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Ensure all tests pass
6. Submit a pull request
## License
MIT License - see LICENSE file for details.
## Support
For issues and questions:
- GitHub Issues: [https://github.com/brandsoulmates/ayz-auth/issues](https://github.com/brandsoulmates/ayz-auth/issues)
- Documentation: [https://github.com/brandsoulmates/ayz-auth](https://github.com/brandsoulmates/ayz-auth)
Raw data
{
"_id": null,
"home_page": null,
"name": "ayz-auth",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "authentication, b2b, fastapi, middleware, stytch",
"author": null,
"author_email": "Ayzenberg <dev@ayzenberg.com>",
"download_url": "https://files.pythonhosted.org/packages/35/69/63c8788dff5ee876dd5babaaa5561e198efe4da072ed136339e9867c6c47/ayz_auth-0.2.14.tar.gz",
"platform": null,
"description": "# ayz-auth\n\nFastAPI middleware for Stytch B2B authentication with Redis caching.\n\n## Overview\n\n`ayz-auth` is a lightweight, production-ready authentication middleware for FastAPI applications using Stytch B2B authentication services. It provides session token verification with Redis caching for optimal performance and includes comprehensive error handling and logging.\n\n## Features\n\n- \ud83d\udd10 **Stytch B2B Integration**: Seamless integration with Stytch B2B authentication\n- \u26a1 **Redis Caching**: Intelligent caching to reduce API calls and improve performance\n- \ud83d\ude80 **FastAPI Native**: Built specifically for FastAPI with proper dependency injection\n- \ud83d\udcdd **Type Safe**: Full Pydantic models with type hints throughout\n- \ud83d\udee1\ufe0f **Security First**: Secure token handling with configurable logging levels\n- \ud83d\udd27 **Configurable**: Environment-based configuration with sensible defaults\n- \ud83d\udcca **Comprehensive Logging**: Structured logging with sensitive data protection\n- \ud83e\uddea **Well Tested**: Comprehensive test suite with mocking support\n\n## Installation\n\n```bash\npip install ayz-auth\n```\n\nOr with UV:\n\n```bash\nuv add ayz-auth\n```\n\n## Quick Start\n\n### 1. Environment Configuration\n\nCreate a `.env` file or set environment variables:\n\n```bash\nSTYTCH_PROJECT_ID=your_project_id\nSTYTCH_SECRET=your_secret_key\nSTYTCH_ENV=test # or \"live\" for production\n# STYTCH_ORGANIZATION_ID=your_org_id # optional, only needed for member search operations\nREDIS_URL=redis://localhost:6379\n```\n\n### 2. Basic Usage\n\n```python\nfrom fastapi import FastAPI, Depends\nfrom ayz_auth import verify_auth, StytchContext\n\napp = FastAPI()\n\n@app.get(\"/protected\")\nasync def protected_route(user: StytchContext = Depends(verify_auth)):\n return {\n \"message\": f\"Hello {user.member_email}\",\n \"member_id\": user.member_id,\n \"organization_id\": user.organization_id\n }\n\n@app.get(\"/user-info\")\nasync def get_user_info(user: StytchContext = Depends(verify_auth)):\n return {\n \"member_id\": user.member_id,\n \"email\": user.member_email,\n \"name\": user.member_name,\n \"organization_id\": user.organization_id,\n \"session_expires_at\": user.session_expires_at,\n \"authentication_factors\": user.authentication_factors\n }\n```\n\n### 3. Optional Authentication\n\nFor endpoints that work with or without authentication:\n\n```python\nfrom typing import Optional\nfrom ayz_auth import verify_auth_optional\n\n@app.get(\"/optional-auth\")\nasync def optional_route(user: Optional[StytchContext] = Depends(verify_auth_optional)):\n if user:\n return {\"message\": f\"Hello {user.member_email}\"}\n else:\n return {\"message\": \"Hello anonymous user\"}\n```\n\n### 4. Custom Authentication Requirements\n\nCreate custom dependencies with additional requirements:\n\n```python\nfrom ayz_auth import create_auth_dependency\n\n# Require specific custom claims\nadmin_auth = create_auth_dependency(required_claims=[\"admin\"])\nmoderator_auth = create_auth_dependency(required_claims=[\"moderator\", \"verified\"])\n\n# Require specific authentication factors\nmfa_auth = create_auth_dependency(required_factors=[\"mfa\"])\n\n@app.get(\"/admin\")\nasync def admin_route(user: StytchContext = Depends(admin_auth)):\n return {\"message\": \"Admin access granted\"}\n\n@app.get(\"/sensitive\")\nasync def sensitive_route(user: StytchContext = Depends(mfa_auth)):\n return {\"message\": \"MFA verified access\"}\n```\n\n## Configuration\n\nAll configuration is handled through environment variables with the `STYTCH_` prefix:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STYTCH_PROJECT_ID` | *required* | Your Stytch project ID |\n| `STYTCH_SECRET` | *required* | Your Stytch secret key |\n| `STYTCH_ENV` | `test` | Stytch environment (`test` or `live`) |\n| `STYTCH_REDIS_URL` | `redis://localhost:6379` | Redis connection URL |\n| `STYTCH_REDIS_PASSWORD` | `None` | Redis password (if required) |\n| `STYTCH_REDIS_DB` | `0` | Redis database number |\n| `STYTCH_CACHE_TTL` | `300` | Cache TTL in seconds (5 minutes) |\n| `STYTCH_CACHE_PREFIX` | `ayz_auth` | Redis key prefix |\n| `STYTCH_LOG_LEVEL` | `INFO` | Logging level |\n| `STYTCH_LOG_SENSITIVE_DATA` | `False` | Log sensitive data (never in production) |\n| `STYTCH_REQUEST_TIMEOUT` | `10` | Request timeout in seconds |\n| `STYTCH_MAX_RETRIES` | `3` | Maximum retry attempts |\n\n## StytchContext Model\n\nThe `StytchContext` model contains all the essential session data from Stytch:\n\n```python\nclass StytchContext(BaseModel):\n # Core identifiers\n member_id: str\n session_id: str\n organization_id: str\n \n # Session timing\n session_started_at: datetime\n session_expires_at: datetime\n session_last_accessed_at: datetime\n authenticated_at: datetime\n \n # Member information\n member_email: Optional[str]\n member_name: Optional[str]\n \n # Session metadata\n session_custom_claims: Dict[str, Any]\n authentication_factors: List[str]\n raw_session_data: Dict[str, Any]\n \n # Utility properties\n @property\n def is_expired(self) -> bool: ...\n \n @property\n def time_until_expiry(self) -> Optional[float]: ...\n```\n\n## Error Handling\n\nThe middleware provides structured error responses:\n\n```python\n# 401 Unauthorized - Missing or invalid token\n{\n \"error\": \"authentication_failed\",\n \"message\": \"Authorization header is required\",\n \"type\": \"token_extraction\"\n}\n\n# 401 Unauthorized - Token verification failed\n{\n \"error\": \"authentication_failed\", \n \"message\": \"Invalid or expired session token\",\n \"type\": \"token_verification\"\n}\n\n# 503 Service Unavailable - Stytch API issues\n{\n \"error\": \"service_unavailable\",\n \"message\": \"Authentication service temporarily unavailable\", \n \"type\": \"stytch_api\"\n}\n\n# 403 Forbidden - Insufficient permissions (custom auth)\n{\n \"error\": \"insufficient_permissions\",\n \"message\": \"Missing required claims: ['admin']\",\n \"type\": \"authorization\"\n}\n\n# 403 Forbidden - Insufficient authentication factors (custom auth)\n{\n \"error\": \"insufficient_authentication\",\n \"message\": \"Missing required authentication factors: ['mfa']\",\n \"type\": \"authorization\"\n}\n```\n\n## Caching Strategy\n\nThe middleware implements a two-tier verification system:\n\n1. **Redis Cache Check**: Fast lookup of previously verified tokens\n2. **Stytch API Fallback**: Fresh verification when cache misses\n\nCache entries automatically expire based on the session expiration time, ensuring security while maximizing performance.\n\n## Integration with Your User System\n\nSince the middleware only returns Stytch session data, you can easily integrate it with your existing user system:\n\n```python\nfrom your_app.models import User\nfrom your_app.database import get_user_by_stytch_member_id\n\n@app.get(\"/profile\")\nasync def get_profile(stytch: StytchContext = Depends(verify_auth)):\n # Use the member_id to fetch your user data\n user = await get_user_by_stytch_member_id(stytch.member_id)\n \n if not user:\n raise HTTPException(404, \"User not found\")\n \n # Check permissions using your user model\n if \"read_profile\" not in user.permissions:\n raise HTTPException(403, \"Insufficient permissions\")\n \n return {\n \"stytch_data\": stytch.to_dict(),\n \"user_data\": user.to_dict()\n }\n```\n\n## Development\n\n### Running Tests\n\n```bash\n# Install development dependencies\nuv sync --dev\n\n# Run tests\npytest\n\n# Run tests with coverage\npytest --cov=ayz_auth\n```\n\n### Code Quality\n\n```bash\n# Format code\nblack src/ tests/\nisort src/ tests/\n\n# Lint code\nruff check src/ tests/\n\n# Type checking\nmypy src/\n```\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests for new functionality\n5. Ensure all tests pass\n6. Submit a pull request\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Support\n\nFor issues and questions:\n\n- GitHub Issues: [https://github.com/brandsoulmates/ayz-auth/issues](https://github.com/brandsoulmates/ayz-auth/issues)\n- Documentation: [https://github.com/brandsoulmates/ayz-auth](https://github.com/brandsoulmates/ayz-auth)\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "FastAPI middleware for Stytch B2B authentication with Redis caching",
"version": "0.2.14",
"project_urls": {
"Homepage": "https://github.com/ayzenberg/ayz-auth",
"Issues": "https://github.com/ayzenberg/ayz-auth/issues",
"Repository": "https://github.com/ayzenberg/ayz-auth"
},
"split_keywords": [
"authentication",
" b2b",
" fastapi",
" middleware",
" stytch"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "46aae6dc0053492cbe2133d617b1677a184bdaa17a29fd8be3582db12fd2b972",
"md5": "292333ea44c1b04915cb0b8b7444a9b5",
"sha256": "827b22767dab7c779adb4774408879f02936cf7f6ef3099c83dd6d4ade55ad89"
},
"downloads": -1,
"filename": "ayz_auth-0.2.14-py3-none-any.whl",
"has_sig": false,
"md5_digest": "292333ea44c1b04915cb0b8b7444a9b5",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 22730,
"upload_time": "2025-07-22T21:04:56",
"upload_time_iso_8601": "2025-07-22T21:04:56.746561Z",
"url": "https://files.pythonhosted.org/packages/46/aa/e6dc0053492cbe2133d617b1677a184bdaa17a29fd8be3582db12fd2b972/ayz_auth-0.2.14-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "356963c8788dff5ee876dd5babaaa5561e198efe4da072ed136339e9867c6c47",
"md5": "d233248dcd52bfaa4093ccae4149fab0",
"sha256": "ddc7944d3eb2ce4598f3c3bb5d803d737cde6f349735ca7ab075333f149631e5"
},
"downloads": -1,
"filename": "ayz_auth-0.2.14.tar.gz",
"has_sig": false,
"md5_digest": "d233248dcd52bfaa4093ccae4149fab0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 33265,
"upload_time": "2025-07-22T21:04:57",
"upload_time_iso_8601": "2025-07-22T21:04:57.940242Z",
"url": "https://files.pythonhosted.org/packages/35/69/63c8788dff5ee876dd5babaaa5561e198efe4da072ed136339e9867c6c47/ayz_auth-0.2.14.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-22 21:04:57",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ayzenberg",
"github_project": "ayz-auth",
"github_not_found": true,
"lcname": "ayz-auth"
}