Address review feedback: Upgrade auth to RS256 signing, age-verification field, refresh-token sessions #33

Merged
reviewer-bot merged 7 commits from agent/424ce35e1b38 into main 2026-08-19 21:12:42 +00:00
2 changed files with 11 additions and 7 deletions
Showing only changes of commit 758307bbee - Show all commits
+2 -3
View File
@@ -26,9 +26,8 @@ class RefreshToken(Base):
id = Column(String(36), primary_key=True, default=lambda: str(uuid.uuid4()))
user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
# RS256 JWTs are ~420+ chars; Text avoids length issues and is fine for
# a UUID-indexed lookup by hash in the future.
token = Column(String, unique=True, index=True, nullable=False)
# RS256 JWTs are ~420+ chars; 512 is sufficient and matches the migration.
token = Column(String(512), unique=True, index=True, nullable=False)
expires_at = Column(DateTime(timezone=True), nullable=False)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
+9 -4
View File
@@ -1,7 +1,7 @@
"""Authentication router - login, register, token refresh."""
import uuid
from datetime import datetime, timedelta, timezone
from datetime import date, datetime, timedelta, timezone
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
@@ -76,8 +76,13 @@ def _create_access_token(data: dict) -> str:
def _create_refresh_token(data: dict) -> str:
"""Create a signed refresh token using RS256."""
"""Create a signed refresh token using RS256.
Includes a unique ``jti`` claim so that concurrent calls produce
distinct tokens even when issued within the same second.
"""
to_encode = data.copy()
to_encode["jti"] = str(uuid.uuid4())
expire = datetime.now(timezone.utc) + timedelta(
days=settings.REFRESH_TOKEN_EXPIRE_DAYS
)
@@ -99,7 +104,7 @@ def hash_password(password: str) -> str:
return pwd_context.hash(password)
def calculate_age(birth_date, today=None) -> int:
def calculate_age(birth_date: date, today: date | None = None) -> int:
"""Calculate age in years from a birth date.
Args:
@@ -174,7 +179,7 @@ async def register(req: RegisterRequest, db: AsyncSession = Depends(get_db)):
date_of_birth=dob,
)
db.add(user)
await db.commit()
await db.flush() # flush to get user.id before creating refresh token
await db.refresh(user)
# Create access token