Skip to content

OIDC: non-blocking background refresh#1233

Merged
lovasoa merged 6 commits intomainfrom
refactor/oidc-background-refresh
Mar 8, 2026
Merged

OIDC: non-blocking background refresh#1233
lovasoa merged 6 commits intomainfrom
refactor/oidc-background-refresh

Conversation

@lovasoa
Copy link
Collaborator

@lovasoa lovasoa commented Mar 8, 2026

Summary

  • OIDC provider metadata refreshes now run in a background task (spawn_local), never blocking incoming HTTP requests. The write lock is only held briefly to swap data, not during upstream HTTP calls.
  • Multiple concurrent refresh triggers (e.g. several users with invalid tokens) are deduplicated via an AtomicBool flag.
  • Adds a body-read timeout (response.timeout()) to OIDC HTTP requests to prevent hangs when the provider stalls after sending response headers.
  • Includes force_expire() test helper on OidcState for deterministic testing of refresh behavior.

Fixes #1231

Test plan

  • test_slow_discovery_does_not_block_authenticated_requests — verifies authenticated requests complete while a slow provider refresh runs in the background
  • test_slow_token_endpoint_does_not_freeze_server — verifies the body-read timeout prevents hangs on slow token endpoints
  • All 11 OIDC tests pass
  • All 57 tests pass
  • clippy clean

🤖 Generated with Claude Code

lovasoa and others added 5 commits March 8, 2026 10:48
- OIDC provider metadata refreshes now run in a background task via
  spawn_local, never blocking incoming HTTP requests.
- Multiple concurrent refresh triggers are deduplicated via an AtomicBool.
- The write lock on the OIDC client is only held briefly to swap data,
  not during the upstream HTTP call.
- Add a body-read timeout to OIDC HTTP requests to prevent hangs when
  the provider stalls after sending headers.
- Add tests for both scenarios: slow discovery and slow token endpoint.

Fixes #1231

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace tokio::sync::RwLock<ClientWithTime> with std::sync::RwLock<Arc<OidcSnapshot>>.
The std lock makes it structurally impossible to hold across await points.
Readers clone an Arc (nanoseconds) and use it freely — no lock contention.
Many previously-async functions become synchronous (get_token_claims,
build_auth_url, handle_unauthenticated_request, handle_oidc_logout, etc).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace std::time::Instant with tokio::time::Instant in OidcSnapshot so
that tokio::time::pause()/advance() controls elapsed time in tests.
Remove force_expire() — tests advance time past MAX_REFRESH_INTERVAL
instead. Simplify slow discovery test from ~70 to ~30 lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a discovery request counter to FakeOidcProvider and assert it
increments after the background refresh completes. Remove unused
set_discovery_delay method.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@lovasoa lovasoa force-pushed the refactor/oidc-background-refresh branch from 32ec48c to 6dcd690 Compare March 8, 2026 09:49
@lovasoa lovasoa force-pushed the refactor/oidc-background-refresh branch from 1977a2d to ba06855 Compare March 8, 2026 09:57
@lovasoa lovasoa merged commit ba06855 into main Mar 8, 2026
14 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.

Slow OIDC provider permanently freezes all request handling

1 participant