""" RefreshToken model — tracks token rotation chain. Maps to AGENT.md DBML: `refresh_tokens` table (Lines 202-209). """ from django.conf import settings from django.db import models from django.utils import timezone from core.models import BaseModel class RefreshToken(BaseModel): """ Refresh token with rotation tracking. Each rotation creates a new token linked to its parent via `rotated_from`. Detects token reuse attacks by checking if a revoked token is used again. """ user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="refresh_tokens", ) rotated_from = models.UUIDField( null=True, blank=True, help_text="Parent token ID this was rotated from.", ) expires_at = models.DateTimeField() revoked_at = models.DateTimeField(null=True, blank=True) class Meta: db_table = "refresh_tokens" ordering = ["-created_at"] indexes = [ models.Index(fields=["user", "-created_at"]), ] def __str__(self) -> str: return f"RefreshToken {self.pk} for {self.user_id}" @property def is_active(self) -> bool: return self.revoked_at is None and self.expires_at > timezone.now() def revoke(self) -> None: self.revoked_at = timezone.now() self.save(update_fields=["revoked_at"])