Files
nuzlocke-tracker/backend/pyproject.toml
Julian Tabel e9eccc5b21 feat: migrate JWT verification from HS256 shared secret to JWKS
Replace symmetric HS256 JWT verification with asymmetric RS256 using JWKS.
Backend now fetches and caches public keys from Supabase's JWKS endpoint
instead of using a shared secret.

- Add cryptography dependency for RS256 support
- Use PyJWKClient to fetch/cache JWKS from {SUPABASE_URL}/.well-known/jwks.json
- Remove SUPABASE_JWT_SECRET from config, docker-compose, deploy workflow, .env
- Update tests to use RS256 tokens with mocked JWKS client

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 09:24:41 +01:00

74 lines
1.6 KiB
TOML

[project]
name = "another-nuzlocke-tracker-api"
version = "0.1.0"
description = "Backend API for Another Nuzlocke Tracker"
readme = "README.md"
requires-python = ">=3.14"
dependencies = [
"fastapi==0.135.1",
"uvicorn[standard]==0.42.0",
"pydantic==2.12.5",
"pydantic-settings==2.13.1",
"python-dotenv==1.2.2",
"sqlalchemy[asyncio]==2.0.48",
"asyncpg==0.31.0",
"alembic==1.18.4",
"PyJWT==2.12.1",
"cryptography==45.0.3",
]
[project.optional-dependencies]
dev = [
"ruff==0.15.7",
"ty==0.0.24",
"pytest==9.0.2",
"pytest-asyncio==1.3.0",
"httpx==0.28.1",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/app"]
[tool.ruff]
target-version = "py314"
line-length = 88
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # Pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
"SIM", # flake8-simplify
]
ignore = [
"E501", # line too long (handled by formatter)
"B008", # Depends() in defaults — standard FastAPI pattern
]
[tool.ruff.lint.per-file-ignores]
"src/app/models/*.py" = ["F821"] # forward refs in SQLAlchemy relationships
[tool.ruff.lint.isort]
known-first-party = ["app"]
[tool.ty.environment]
python-version = "3.14"
[tool.ty.src]
root = "src"
[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "session"
asyncio_default_test_loop_scope = "session"
testpaths = ["tests"]