Split-out of the "split oidc.rs" item from #1249.
src/webserver/oidc.rs is the largest file in the codebase at 1556 lines (wc -l src/webserver/oidc.rs). Anyone touching cookie flags has to scroll past JWT verifier generics, HMAC logout signing, the awc transport adapter, and ~12 large openidconnect type aliases. These concerns are independent of each other, and the file's coupling to the rest of the codebase is tiny, so the split is low-risk and high-payoff.
External surface is only 5 symbols
$ grep -rn "oidc::" src | grep -v "src/webserver/oidc.rs"
src/lib.rs:89:use crate::webserver::oidc::OidcState;
src/lib.rs:138: let oidc_state = crate::webserver::oidc::initialize_oidc_state(config).await?;
src/webserver/http.rs:27:use super::oidc::OidcMiddleware;
src/webserver/http_request_info.rs:28:use super::oidc::OidcClaims;
src/webserver/database/sqlpage_functions/functions.rs:1058: if !crate::webserver::oidc::is_safe_relative_redirect(redirect_uri) {
So the entire 1556-line file is reached from outside through just OidcState, initialize_oidc_state, OidcMiddleware, OidcClaims, and is_safe_relative_redirect. A split is almost entirely internal and mechanical.
The concerns are physically interleaved
(line ranges at HEAD 162f996)
- Config / path matching (
OidcConfig, is_public_path, get_app_host) talks only to AppConfig.
- Provider discovery + client build (
OidcSnapshot, OidcState, maybe_refresh, build_oidc_client, make_oidc_client) plus the ~12 large openidconnect type aliases (OidcToken, OidcClaims, OidcTokenResponse, OidcClient) that visually dominate the file.
- Actix middleware / request routing (
OidcMiddleware, OidcService, handle_request and the handle_* family).
- Token exchange + claim/nonce verification (
process_oidc_callback, exchange_code_for_token, check_nonce, AudienceVerifier).
- Cookie/session + redirect plumbing (the
*_cookie builders such as set_auth_cookie and create_tmp_login_flow_state_cookie, HMAC logout signing compute_logout_signature / verify_logout_params, is_safe_relative_redirect, build_redirect_response).
- A generic
awc transport adapter (AwcHttpClient, ~110 lines through AwcWrapperError) implementing openidconnect::AsyncHttpClient over awc. This is not OIDC-specific. It is pub but used only within this file, so it should move to its own module where it becomes independently unit-testable.
Proposed change
Convert to a directory module:
oidc/
mod.rs // re-exports the ~5 public symbols
config.rs // OidcConfig, is_public_path, get_app_host
discovery.rs // OidcState/OidcSnapshot, maybe_refresh, client build, type aliases
middleware.rs // OidcMiddleware/OidcService, handle_request + handle_*
flow.rs // callback / token exchange / claim + nonce verification
session.rs // cookie builders, logout signing, redirect safety
http_client.rs // the AwcHttpClient adapter (now independently testable)
Do not regress the good existing state
Two things must be preserved by the move:
- The real integration suite at
tests/oidc/mod.rs (882 lines) spins up an embedded mock IdP (discovery/jwks/token endpoints) and covers the happy path, CSRF/nonce/signature/audience/issuer/expiry rejection, site-prefix, session-bound logout, and slow-discovery non-blocking behavior.
- The lock-free read discipline:
OidcState::snapshot() returns an Arc<OidcSnapshot> so request handling never holds the RwLock across .await. The split must keep this intact.
Risks and mitigations
Purely mechanical move, no behavior change. Mitigations:
- Keep the public re-exports in
mod.rs so no external code changes (the 5 call sites above stay byte-for-byte identical).
- Rely on the existing OIDC integration tests above to catch any wiring mistake.
Expected win
Navigable auth code; the transport adapter becomes unit-testable in isolation; and it is a prerequisite for any future second-IdP or server-side-session work.
Split-out of the "split
oidc.rs" item from #1249.src/webserver/oidc.rsis the largest file in the codebase at 1556 lines (wc -l src/webserver/oidc.rs). Anyone touching cookie flags has to scroll past JWT verifier generics, HMAC logout signing, theawctransport adapter, and ~12 largeopenidconnecttype aliases. These concerns are independent of each other, and the file's coupling to the rest of the codebase is tiny, so the split is low-risk and high-payoff.External surface is only 5 symbols
So the entire 1556-line file is reached from outside through just
OidcState,initialize_oidc_state,OidcMiddleware,OidcClaims, andis_safe_relative_redirect. A split is almost entirely internal and mechanical.The concerns are physically interleaved
(line ranges at HEAD
162f996)OidcConfig,is_public_path,get_app_host) talks only toAppConfig.OidcSnapshot,OidcState,maybe_refresh,build_oidc_client,make_oidc_client) plus the ~12 largeopenidconnecttype aliases (OidcToken,OidcClaims,OidcTokenResponse,OidcClient) that visually dominate the file.OidcMiddleware,OidcService,handle_requestand thehandle_*family).process_oidc_callback,exchange_code_for_token,check_nonce,AudienceVerifier).*_cookiebuilders such asset_auth_cookieandcreate_tmp_login_flow_state_cookie, HMAC logout signingcompute_logout_signature/verify_logout_params,is_safe_relative_redirect,build_redirect_response).awctransport adapter (AwcHttpClient, ~110 lines throughAwcWrapperError) implementingopenidconnect::AsyncHttpClientoverawc. This is not OIDC-specific. It ispubbut used only within this file, so it should move to its own module where it becomes independently unit-testable.Proposed change
Convert to a directory module:
Do not regress the good existing state
Two things must be preserved by the move:
tests/oidc/mod.rs(882 lines) spins up an embedded mock IdP (discovery/jwks/token endpoints) and covers the happy path, CSRF/nonce/signature/audience/issuer/expiry rejection, site-prefix, session-bound logout, and slow-discovery non-blocking behavior.OidcState::snapshot()returns anArc<OidcSnapshot>so request handling never holds theRwLockacross.await. The split must keep this intact.Risks and mitigations
Purely mechanical move, no behavior change. Mitigations:
mod.rsso no external code changes (the 5 call sites above stay byte-for-byte identical).Expected win
Navigable auth code; the transport adapter becomes unit-testable in isolation; and it is a prerequisite for any future second-IdP or server-side-session work.