Skip to content

fix(auth): OAuth refresh race and Scheduler thread leak#16

Merged
knep merged 2 commits into
masterfrom
feat/vuetify
Jun 11, 2026
Merged

fix(auth): OAuth refresh race and Scheduler thread leak#16
knep merged 2 commits into
masterfrom
feat/vuetify

Conversation

@knep

@knep knep commented Jun 11, 2026

Copy link
Copy Markdown
Owner

What changed

Two OAuth token-refresh fixes in src/auth/oauth_token_manager.py:

  1. Serialize per-user token refreshes. Two refreshes in flight with the same refresh token caused the second to get a 401 from the provider (the token had already been rotated) and log the user out. _refresh_token is now guarded by a per-user asyncio.Lock.
  2. Stop leaking a Scheduler thread per refresh. _schedule_token_refresh checked self._scheduler but assigned self.scheduler (no underscore), so the check never passed and every refresh created a new Scheduler, each starting its own daemon thread. The attribute is now used consistently, so a single scheduler is created lazily and reused.

Tests

  • New regression tests: a refresh racing with validate_user, and two concurrent refreshes with the same token.
  • Keycloak test mock no longer expires old access tokens on refresh — real Keycloak access tokens are stateless JWTs that stay valid until expiration.
  • cd src && PYTHONPATH=. python -m pytest tests/auth/ -q: 84 passed, 4 skipped.

Notes for reviewers

This branch previously carried the Vuetify migration (merged in #15); this PR contains only the two auth commits on top.

🤖 Generated with Claude Code

Thomas Kpenou and others added 2 commits June 11, 2026 18:36
Two refreshes in flight with the same refresh token caused the second
to get a 401 from the provider (token already rotated) and log the
user out. Guard _refresh_token with a per-user asyncio.Lock and add
regression tests for refresh/validation races. Also stop expiring old
access tokens in the Keycloak test mock on refresh - real Keycloak
access tokens are stateless JWTs that stay valid until expiration.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
_schedule_token_refresh checked self._scheduler but assigned
self.scheduler, so the check never passed and every refresh created a
new Scheduler with its own daemon thread. Use _scheduler consistently
so a single instance is created lazily and reused.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@knep knep merged commit 453e3fd into master Jun 11, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant