Skip to content

Commit

Permalink
fix: make token refresh robust to network errors
Browse files Browse the repository at this point in the history
  • Loading branch information
irishrain committed Dec 28, 2024
1 parent 02f3387 commit f628691
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 11 deletions.
29 changes: 24 additions & 5 deletions backend/app/controller/auth/auth_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,31 @@
def check_if_token_revoked(jwt_header, jwt_payload: dict) -> bool:
jti = jwt_payload["jti"]
token = Token.find_by_jti(jti)
if token is not None:
token.last_used_at = datetime.now(timezone.utc)
token.user.last_seen = token.last_used_at
token.save()
if token is None:
return True

return token is None
# Update last used time
token.last_used_at = datetime.now(timezone.utc)
token.user.last_seen = token.last_used_at

# Handle token refresh chain
if token.type == "access":
refresh_token = token.refresh_token
if refresh_token and len(refresh_token.created_tokens) > 1:
# If this is an old access token and its refresh token has created a new chain
if not token.used:
# First use of old access token - invalidate new chain and keep this one
for t in refresh_token.created_tokens:
if t.id != token.id:
t.delete()
else:
# Old access token already used - reject it
return True

# Mark token as used
token.used = True
token.save()
return False


# Register a callback function that takes whatever object is passed in as the
Expand Down
10 changes: 4 additions & 6 deletions backend/app/models/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Token(db.Model, DbModelMixin):
last_used_at: Mapped[datetime] = db.Column(db.DateTime)
refresh_token_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("token.id"), nullable=True)
user_id: Mapped[int] = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
used: Mapped[bool] = db.Column(db.Boolean, nullable=False, default=False)

created_tokens: Mapped[List["Token"]] = db.relationship(
"Token", back_populates="refresh_token", cascade="all, delete-orphan"
Expand Down Expand Up @@ -118,13 +119,10 @@ def create_refresh_token(
cls, user: User, device: str | None = None, oldRefreshToken: Self | None = None
) -> Tuple[str, Self]:
assert device or oldRefreshToken
if oldRefreshToken and (
oldRefreshToken.type != "refresh"
or oldRefreshToken.has_created_refresh_token()
):
if oldRefreshToken and oldRefreshToken.type != "refresh":
oldRefreshToken.delete_token_familiy()
raise UnauthorizedRequest(
message="Unauthorized: IP {} reused the same refresh token, logging out user".format(
message="Unauthorized: IP {} tried to refresh with non-refresh token".format(
request.remote_addr
)
)
Expand All @@ -136,7 +134,7 @@ def create_refresh_token(
model.name = device or oldRefreshToken.name
model.user = user
if oldRefreshToken:
oldRefreshToken.delete_created_access_tokens()
# Don't delete old access tokens - they will be invalidated when used
model.refresh_token = oldRefreshToken
model.save()
return refreshToken, model
Expand Down
24 changes: 24 additions & 0 deletions backend/migrations/versions/17f14a011697_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Add used to token model
Revision ID: 17f14a011697
Revises: 22dbfbf4cc33
Create Date: 2024-03-19 10:00:00.000000
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '17f14a011697'
down_revision = '22dbfbf4cc33'
branch_labels = None
depends_on = None


def upgrade():
op.add_column('token', sa.Column('used', sa.Boolean(), nullable=False, server_default='false'))


def downgrade():
op.drop_column('token', 'used')

0 comments on commit f628691

Please sign in to comment.