mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-04 05:12:38 +02:00
Add RefreshToken model for user session management
This commit is contained in:
parent
ecd0985523
commit
04aac379ed
1 changed files with 58 additions and 0 deletions
|
|
@ -1361,6 +1361,13 @@ if config.AUTH_TYPE == "GOOGLE":
|
||||||
display_name = Column(String, nullable=True)
|
display_name = Column(String, nullable=True)
|
||||||
avatar_url = Column(String, nullable=True)
|
avatar_url = Column(String, nullable=True)
|
||||||
|
|
||||||
|
# Refresh tokens for this user
|
||||||
|
refresh_tokens = relationship(
|
||||||
|
"RefreshToken",
|
||||||
|
back_populates="user",
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
class User(SQLAlchemyBaseUserTableUUID, Base):
|
class User(SQLAlchemyBaseUserTableUUID, Base):
|
||||||
|
|
@ -1426,6 +1433,57 @@ else:
|
||||||
display_name = Column(String, nullable=True)
|
display_name = Column(String, nullable=True)
|
||||||
avatar_url = Column(String, nullable=True)
|
avatar_url = Column(String, nullable=True)
|
||||||
|
|
||||||
|
# Refresh tokens for this user
|
||||||
|
refresh_tokens = relationship(
|
||||||
|
"RefreshToken",
|
||||||
|
back_populates="user",
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RefreshToken(Base, TimestampMixin):
|
||||||
|
"""
|
||||||
|
Stores refresh tokens for user session management.
|
||||||
|
|
||||||
|
Refresh tokens are long-lived tokens (2 weeks) used to obtain new
|
||||||
|
access tokens without requiring re-authentication.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = "refresh_tokens"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||||
|
|
||||||
|
# User relationship
|
||||||
|
user_id = Column(
|
||||||
|
UUID(as_uuid=True),
|
||||||
|
ForeignKey("user.id", ondelete="CASCADE"),
|
||||||
|
nullable=False,
|
||||||
|
index=True,
|
||||||
|
)
|
||||||
|
user = relationship("User", back_populates="refresh_tokens")
|
||||||
|
|
||||||
|
# Token hash (stored hashed, not plaintext)
|
||||||
|
token_hash = Column(String(256), unique=True, nullable=False, index=True)
|
||||||
|
|
||||||
|
# Token expiration
|
||||||
|
expires_at = Column(TIMESTAMP(timezone=True), nullable=False, index=True)
|
||||||
|
|
||||||
|
# Revocation flag
|
||||||
|
is_revoked = Column(Boolean, default=False, nullable=False)
|
||||||
|
|
||||||
|
# Token family for rotation tracking (detect reuse attacks)
|
||||||
|
family_id = Column(UUID(as_uuid=True), nullable=False, index=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_expired(self) -> bool:
|
||||||
|
"""Check if the token has expired."""
|
||||||
|
return datetime.now(UTC) >= self.expires_at
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_valid(self) -> bool:
|
||||||
|
"""Check if the token is valid (not expired and not revoked)."""
|
||||||
|
return not self.is_expired and not self.is_revoked
|
||||||
|
|
||||||
|
|
||||||
engine = create_async_engine(DATABASE_URL)
|
engine = create_async_engine(DATABASE_URL)
|
||||||
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
|
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue