""" RefreshToken model - stores refresh tokens for users. """ from datetime import datetime from sqlalchemy import DateTime, ForeignKey, String from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import Mapped, mapped_column, relationship from app.models.base import Base class RefreshToken(Base): """ Refresh token model for JWT token rotation. Stores hashed refresh tokens and device info. Tokens can be revoked by setting revoked_at. """ __tablename__ = "refresh_tokens" id: Mapped[int] = mapped_column(primary_key=True) user_id: Mapped[int] = mapped_column( ForeignKey("users.id", ondelete="CASCADE"), nullable=False ) # Token (should be hashed in production, but for MVP we'll store plain) token: Mapped[str] = mapped_column(String(512), unique=True, nullable=False) expires_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False ) # Device tracking (user agent, IP, etc.) device_info: Mapped[dict | None] = mapped_column(JSONB) # Revocation revoked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) # Relationships user: Mapped["User"] = relationship("User", back_populates="refresh_tokens") @property def is_valid(self) -> bool: """Check if token is valid (not expired and not revoked).""" now = datetime.now() return self.expires_at > now and self.revoked_at is None def __repr__(self) -> str: return f""