feat(auth): add JWT authentication with python-jose dependency
Browse files- Add new auth.py with JWT token verification functionality
- Include python-jose as dependency for JWT handling
- Implement OAuth2 password bearer scheme for token validation
- api/dependencies/auth.py +39 -0
- pyproject.toml +1 -0
- uv.lock +28 -0
api/dependencies/auth.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import uuid
|
| 2 |
+
from pydantic import BaseModel, ValidationError
|
| 3 |
+
|
| 4 |
+
from fastapi import Depends, HTTPException, status
|
| 5 |
+
from fastapi.security import OAuth2PasswordBearer
|
| 6 |
+
from jose import JWTError, jwt
|
| 7 |
+
|
| 8 |
+
from core.config import get_settings
|
| 9 |
+
|
| 10 |
+
settings = get_settings()
|
| 11 |
+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
| 12 |
+
|
| 13 |
+
class TokenPayload(BaseModel):
|
| 14 |
+
sub: uuid.UUID
|
| 15 |
+
aud: str
|
| 16 |
+
|
| 17 |
+
async def get_current_user(token: str = Depends(oauth2_scheme)) -> uuid.UUID:
|
| 18 |
+
"""
|
| 19 |
+
Decodes and verifies the JWT token to get the current user.
|
| 20 |
+
Raises HTTPException if the token is invalid.
|
| 21 |
+
"""
|
| 22 |
+
credentials_exception = HTTPException(
|
| 23 |
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
| 24 |
+
detail="Could not validate credentials",
|
| 25 |
+
headers={"WWW-Authenticate": "Bearer"},
|
| 26 |
+
)
|
| 27 |
+
try:
|
| 28 |
+
payload = jwt.decode(
|
| 29 |
+
token,
|
| 30 |
+
settings.SUPABASE_JWT_SECRET,
|
| 31 |
+
algorithms=["HS256"],
|
| 32 |
+
audience="authenticated"
|
| 33 |
+
)
|
| 34 |
+
token_data = TokenPayload(**payload)
|
| 35 |
+
|
| 36 |
+
except (JWTError, ValidationError):
|
| 37 |
+
raise credentials_exception
|
| 38 |
+
|
| 39 |
+
return token_data.sub
|
pyproject.toml
CHANGED
|
@@ -20,5 +20,6 @@ dependencies = [
|
|
| 20 |
"pinecone>=7.3.0",
|
| 21 |
"pydantic-settings>=2.10.1",
|
| 22 |
"python-dotenv>=1.1.1",
|
|
|
|
| 23 |
"sqlmodel>=0.0.24",
|
| 24 |
]
|
|
|
|
| 20 |
"pinecone>=7.3.0",
|
| 21 |
"pydantic-settings>=2.10.1",
|
| 22 |
"python-dotenv>=1.1.1",
|
| 23 |
+
"python-jose>=3.5.0",
|
| 24 |
"sqlmodel>=0.0.24",
|
| 25 |
]
|
uv.lock
CHANGED
|
@@ -362,6 +362,18 @@ wheels = [
|
|
| 362 |
{ url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 },
|
| 363 |
]
|
| 364 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 365 |
[[package]]
|
| 366 |
name = "executing"
|
| 367 |
version = "2.2.0"
|
|
@@ -1184,6 +1196,7 @@ dependencies = [
|
|
| 1184 |
{ name = "pinecone" },
|
| 1185 |
{ name = "pydantic-settings" },
|
| 1186 |
{ name = "python-dotenv" },
|
|
|
|
| 1187 |
{ name = "sqlmodel" },
|
| 1188 |
]
|
| 1189 |
|
|
@@ -1204,6 +1217,7 @@ requires-dist = [
|
|
| 1204 |
{ name = "pinecone", specifier = ">=7.3.0" },
|
| 1205 |
{ name = "pydantic-settings", specifier = ">=2.10.1" },
|
| 1206 |
{ name = "python-dotenv", specifier = ">=1.1.1" },
|
|
|
|
| 1207 |
{ name = "sqlmodel", specifier = ">=0.0.24" },
|
| 1208 |
]
|
| 1209 |
|
|
@@ -2108,6 +2122,20 @@ wheels = [
|
|
| 2108 |
{ url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556 },
|
| 2109 |
]
|
| 2110 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2111 |
[[package]]
|
| 2112 |
name = "pytz"
|
| 2113 |
version = "2025.2"
|
|
|
|
| 362 |
{ url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 },
|
| 363 |
]
|
| 364 |
|
| 365 |
+
[[package]]
|
| 366 |
+
name = "ecdsa"
|
| 367 |
+
version = "0.19.1"
|
| 368 |
+
source = { registry = "https://pypi.org/simple" }
|
| 369 |
+
dependencies = [
|
| 370 |
+
{ name = "six" },
|
| 371 |
+
]
|
| 372 |
+
sdist = { url = "https://files.pythonhosted.org/packages/c0/1f/924e3caae75f471eae4b26bd13b698f6af2c44279f67af317439c2f4c46a/ecdsa-0.19.1.tar.gz", hash = "sha256:478cba7b62555866fcb3bb3fe985e06decbdb68ef55713c4e5ab98c57d508e61", size = 201793 }
|
| 373 |
+
wheels = [
|
| 374 |
+
{ url = "https://files.pythonhosted.org/packages/cb/a3/460c57f094a4a165c84a1341c373b0a4f5ec6ac244b998d5021aade89b77/ecdsa-0.19.1-py2.py3-none-any.whl", hash = "sha256:30638e27cf77b7e15c4c4cc1973720149e1033827cfd00661ca5c8cc0cdb24c3", size = 150607 },
|
| 375 |
+
]
|
| 376 |
+
|
| 377 |
[[package]]
|
| 378 |
name = "executing"
|
| 379 |
version = "2.2.0"
|
|
|
|
| 1196 |
{ name = "pinecone" },
|
| 1197 |
{ name = "pydantic-settings" },
|
| 1198 |
{ name = "python-dotenv" },
|
| 1199 |
+
{ name = "python-jose" },
|
| 1200 |
{ name = "sqlmodel" },
|
| 1201 |
]
|
| 1202 |
|
|
|
|
| 1217 |
{ name = "pinecone", specifier = ">=7.3.0" },
|
| 1218 |
{ name = "pydantic-settings", specifier = ">=2.10.1" },
|
| 1219 |
{ name = "python-dotenv", specifier = ">=1.1.1" },
|
| 1220 |
+
{ name = "python-jose", specifier = ">=3.5.0" },
|
| 1221 |
{ name = "sqlmodel", specifier = ">=0.0.24" },
|
| 1222 |
]
|
| 1223 |
|
|
|
|
| 2122 |
{ url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556 },
|
| 2123 |
]
|
| 2124 |
|
| 2125 |
+
[[package]]
|
| 2126 |
+
name = "python-jose"
|
| 2127 |
+
version = "3.5.0"
|
| 2128 |
+
source = { registry = "https://pypi.org/simple" }
|
| 2129 |
+
dependencies = [
|
| 2130 |
+
{ name = "ecdsa" },
|
| 2131 |
+
{ name = "pyasn1" },
|
| 2132 |
+
{ name = "rsa" },
|
| 2133 |
+
]
|
| 2134 |
+
sdist = { url = "https://files.pythonhosted.org/packages/c6/77/3a1c9039db7124eb039772b935f2244fbb73fc8ee65b9acf2375da1c07bf/python_jose-3.5.0.tar.gz", hash = "sha256:fb4eaa44dbeb1c26dcc69e4bd7ec54a1cb8dd64d3b4d81ef08d90ff453f2b01b", size = 92726 }
|
| 2135 |
+
wheels = [
|
| 2136 |
+
{ url = "https://files.pythonhosted.org/packages/d9/c3/0bd11992072e6a1c513b16500a5d07f91a24017c5909b02c72c62d7ad024/python_jose-3.5.0-py2.py3-none-any.whl", hash = "sha256:abd1202f23d34dfad2c3d28cb8617b90acf34132c7afd60abd0b0b7d3cb55771", size = 34624 },
|
| 2137 |
+
]
|
| 2138 |
+
|
| 2139 |
[[package]]
|
| 2140 |
name = "pytz"
|
| 2141 |
version = "2025.2"
|