Module oauth_client

Module oauth_client 

Source
Expand description

Service-account OAuth 2.0 client for the Trust Center.

Distinct from the CLI-provider OAuth in auth_session.rs (which scrapes a spawned CLI’s stdout): this drives the flow itself — opens the system browser, runs a transient loopback listener (or polls a device endpoint), exchanges the code, and stores the resulting tokens in the OS keychain.

Security posture follows RFC 8252 (OAuth for Native Apps), RFC 7636 (PKCE, S256), RFC 8628 (Device Grant), and RFC 9700 (Security BCP):

  • Authorization Code + PKCE(S256) over a loopback 127.0.0.1:<ephemeral> redirect for code-flow providers (Google, Microsoft).
  • Device Authorization Grant for GitHub (no client secret needed).
  • High-entropy state generated and verified on the callback (CSRF).
  • Public clients carry no secret; secret-mandatory providers (Slack) use BYO credentials (the user supplies their own client_id/secret).
  • Tokens are stored in the OS keychain (never the DB, never logged).

Scaffold status: the per-provider client_ids are not yet provisioned (client_id: None below). Until a client id is supplied — either baked into the catalog or passed as BYO — start returns a clear “not configured” error and no flow runs. Dropping in the ids (and wiring the frontend Connect button) activates this end to end. See specs/SPEC_TRUST_CENTER_2026_06_15.md §4.2/§12.1.

Structs§

ByoCredentials
BYO OAuth-app credentials, supplied by the user for secret-mandatory providers (Slack) or to override the built-in public client.
OAuthSession 🔒
OAuthSessionManager
PkcePair
A PKCE verifier/challenge pair. challenge = BASE64URL(SHA256(verifier)).
ServiceOAuthConfig
Static per-service OAuth configuration. client_id is None in the shipped scaffold — supply it (or BYO) to activate the provider.

Enums§

OAuthFlow
How a provider’s OAuth flow is driven.
OAuthStatus
Terminal/transient status surfaced to the frontend poll.

Constants§

SESSION_RETENTION 🔒
How long a session entry is retained before it’s pruned. Generous margin over the 5-min flow timeout so a slow frontend poll still finds its result.
SESSION_TIMEOUT 🔒

Functions§

config_for
Per-provider catalog. Endpoints + flow choice follow each provider’s native-app guidance (see SPEC §12.1). client_id intentionally None until provisioned.
enc 🔒
URL-encode a query component (RFC 3986 unreserved kept).
exchange 🔒
http 🔒
manager
Process-global manager. A dedicated singleton (rather than an AppState field) keeps this scaffold’s blast radius small; service-OAuth sessions are short-lived and window-agnostic.
open_browser 🔒
parse_callback 🔒
Extract code and state from a raw HTTP request line GET /callback?code=...&state=... HTTP/1.1.
percent_decode 🔒
persist_oauth_account 🔒
Persist the OAuth account: token blob → keychain, pointer + non-secret context → DB. Returns the account id.
pkce_pair
Generate a PKCE pair. The verifier is 256 bits of CSPRNG entropy (two v4 UUIDs, as uuid draws from the OS RNG) base64url-encoded — well within the 43–128 char range, charset-safe. Challenge uses S256 (never plain).
random_state
High-entropy CSRF state value. Verified byte-for-byte on the callback.
resolve_client
Resolve the effective client id: BYO overrides the built-in. Returns an error string when neither is available (the “not configured” gate) or when a secret-mandatory provider is missing its BYO secret.
start
Start an OAuth flow. Resolves config + client (gating on “not configured”), creates a session, and spawns the background task that drives it. Returns (session_id, initial_status). The frontend then polls manager().poll.
start_code_flow 🔒
start_device_flow 🔒
supports_oauth
Whether a provider has an OAuth flow at all (frontend gating).
token_blob 🔒
Tokens returned by an exchange. Stored as a keychain JSON blob — never the DB, never logged.