diff --git a/pyproject.toml b/pyproject.toml index fcfdcf85..34daf7a0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ dependencies = [ "alembic>=1.13.1", "asyncpg>=0.29.0", "SQLAlchemy-Utils>=0.41.1", - "python-jose>=3.3.0", + "PyJWT>=2.8.0", "SQLAlchemy>=2.0.25", "python-multipart>=0.0.9", "greenlet>=2.0.2", diff --git a/src/app/api/v1/logout.py b/src/app/api/v1/logout.py index b4dafc80..db7dedee 100644 --- a/src/app/api/v1/logout.py +++ b/src/app/api/v1/logout.py @@ -1,7 +1,7 @@ from typing import Optional +import jwt from fastapi import APIRouter, Cookie, Depends, Response -from jose import JWTError from sqlalchemy.ext.asyncio import AsyncSession from ...core.db.database import async_get_db @@ -27,5 +27,5 @@ async def logout( return {"message": "Logged out successfully"} - except JWTError: + except jwt.PyJWTError: raise UnauthorizedException("Invalid token.") diff --git a/src/app/core/security.py b/src/app/core/security.py index d589078b..5d36fde8 100644 --- a/src/app/core/security.py +++ b/src/app/core/security.py @@ -3,8 +3,8 @@ from typing import Any, Literal import bcrypt +import jwt from fastapi.security import OAuth2PasswordBearer -from jose import JWTError, jwt from pydantic import SecretStr from sqlalchemy.ext.asyncio import AsyncSession @@ -54,10 +54,10 @@ async def authenticate_user(username_or_email: str, password: str, db: AsyncSess async def create_access_token(data: dict[str, Any], expires_delta: timedelta | None = None) -> str: to_encode = data.copy() if expires_delta: - expire = datetime.now(UTC).replace(tzinfo=None) + expires_delta + expire = datetime.now(UTC) + expires_delta else: - expire = datetime.now(UTC).replace(tzinfo=None) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - to_encode.update({"exp": expire, "token_type": TokenType.ACCESS}) + expire = datetime.now(UTC) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) + to_encode.update({"exp": int(expire.timestamp()), "token_type": TokenType.ACCESS}) encoded_jwt: str = jwt.encode(to_encode, SECRET_KEY.get_secret_value(), algorithm=ALGORITHM) return encoded_jwt @@ -65,10 +65,10 @@ async def create_access_token(data: dict[str, Any], expires_delta: timedelta | N async def create_refresh_token(data: dict[str, Any], expires_delta: timedelta | None = None) -> str: to_encode = data.copy() if expires_delta: - expire = datetime.now(UTC).replace(tzinfo=None) + expires_delta + expire = datetime.now(UTC) + expires_delta else: - expire = datetime.now(UTC).replace(tzinfo=None) + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS) - to_encode.update({"exp": expire, "token_type": TokenType.REFRESH}) + expire = datetime.now(UTC) + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS) + to_encode.update({"exp": int(expire.timestamp()), "token_type": TokenType.REFRESH}) encoded_jwt: str = jwt.encode(to_encode, SECRET_KEY.get_secret_value(), algorithm=ALGORITHM) return encoded_jwt @@ -104,7 +104,7 @@ async def verify_token(token: str, expected_token_type: TokenType, db: AsyncSess return TokenData(username_or_email=username_or_email) - except JWTError: + except jwt.PyJWTError: return None diff --git a/uv.lock b/uv.lock index 10c85d61..e6ddee0a 100644 --- a/uv.lock +++ b/uv.lock @@ -396,8 +396,8 @@ dependencies = [ { name = "psycopg2-binary" }, { name = "pydantic", extra = ["email"] }, { name = "pydantic-settings" }, + { name = "pyjwt" }, { name = "python-dotenv" }, - { name = "python-jose" }, { name = "python-multipart" }, { name = "redis" }, { name = "rich" }, @@ -446,10 +446,10 @@ requires-dist = [ { name = "psycopg2-binary", specifier = ">=2.9.9" }, { name = "pydantic", extras = ["email"], specifier = ">=2.12.5" }, { name = "pydantic-settings", specifier = ">=2.12.0" }, + { name = "pyjwt", specifier = ">=2.8.0" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=7.4.2" }, { name = "pytest-mock", marker = "extra == 'dev'", specifier = ">=3.14.0" }, { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "python-jose", specifier = ">=3.3.0" }, { name = "python-multipart", specifier = ">=0.0.9" }, { name = "redis", specifier = ">=5.0.1" }, { name = "rich", specifier = ">=14.2.0" },