Skip to content

pywry.auth

OAuth2 authentication system — providers, token storage, session management, and flow orchestration.


Package Exports

OAuth2 authentication system for PyWry.

Provides OAuth2 provider abstractions, token storage, session management, and auth flow orchestration for both native window and deploy modes.

Classes

AuthFlowManager

AuthFlowManager(provider: OAuthProvider, token_store: TokenStore | None = None, session_manager: SessionManager | None = None, use_pkce: bool = True, auth_timeout: float = 120.0)

Orchestrates OAuth2 authentication flows.

Supports two modes:

  • Native mode: Opens a dedicated auth window pointing at the provider's authorize URL, captures the redirect on an ephemeral localhost HTTP server, and exchanges the code for tokens.

  • Deploy mode: Returns the /auth/login URL for the frontend to navigate to. The server-side routes handle the actual flow.

Initialize the auth flow manager.

Attributes

flow_state property
flow_state: AuthFlowState

Current state of the auth flow.

Functions

run_native
run_native(show_window: Any | None = None, close_window: Any | None = None, window_config: dict[str, Any] | None = None) -> AuthFlowResult

Run the OAuth2 flow in native window mode.

This method blocks until authentication completes, times out, or is cancelled.

Raises:

Type Description
AuthFlowTimeout

If the callback is not received within the timeout.

AuthFlowCancelled

If the user closes the auth window or aborts.

AuthenticationError

If the provider returns an error.

run_deploy
run_deploy(base_url: str = '') -> str

Get the login URL for deploy mode.

In deploy mode, the actual OAuth2 flow is handled server-side by the routes in deploy_routes.py. This method simply returns the URL that the frontend should navigate to.

authenticate
authenticate(app: Any, show_window: Any | None = None, close_window: Any | None = None, window_config: dict[str, Any] | None = None) -> AuthFlowResult

Unified authentication entry point.

Detects the app mode and runs the appropriate flow.

cancel
cancel() -> None

Cancel the current authentication flow.

Sets the cancellation event which unblocks _wait_for_callback_with_cancellation.

OAuthProvider

OAuthProvider(client_id: str, client_secret: str = '', scopes: list[str] | None = None, authorize_url: str = '', token_url: str = '', userinfo_url: str = '', revocation_url: str = '')

Bases: ABC

Abstract base class for OAuth2 providers.

Attributes:

Name Type Description
client_id str

OAuth2 client identifier registered with the provider.

client_secret str

Client secret or empty string for public clients.

scopes list[str]

Scopes requested during the authorization flow.

authorize_url str

Provider authorization endpoint.

token_url str

Provider token endpoint.

userinfo_url str

Provider userinfo endpoint, if supported.

revocation_url str

Provider token revocation endpoint, if supported.

Initialize an OAuth provider.

Functions

close async
close() -> None

Close the shared HTTP client.

Notes

Call this from application shutdown hooks to release open sockets.

build_authorize_url
build_authorize_url(redirect_uri: str, state: str, pkce: PKCEChallenge | None = None, extra_params: dict[str, str] | None = None) -> str

Build the full authorization URL.

exchange_code abstractmethod async
exchange_code(code: str, redirect_uri: str, pkce_verifier: str | None = None, nonce: str | None = None) -> OAuthTokenSet

Exchange authorization code for tokens.

Raises:

Type Description
TokenError

If the code exchange fails.

refresh_tokens abstractmethod async
refresh_tokens(refresh_token: str) -> OAuthTokenSet

Refresh an expired access token.

Raises:

Type Description
TokenRefreshError

If the refresh fails.

get_userinfo async
get_userinfo(access_token: str) -> dict[str, Any]

Fetch user profile information from the provider.

Raises:

Type Description
HTTPError

Raised when the userinfo endpoint returns an error response.

revoke_token async
revoke_token(token: str) -> bool

Revoke a token at the provider (RFC 7009).

Posts to the revocation_url if one is configured. Subclasses with non-standard revocation APIs should override.

GenericOIDCProvider

GenericOIDCProvider(client_id: str, client_secret: str = '', issuer_url: str = '', scopes: list[str] | None = None, authorize_url: str = '', token_url: str = '', userinfo_url: str = '', revocation_url: str = '', *, require_id_token_validation: bool = True)

Bases: OAuthProvider

Generic OpenID Connect provider.

Supports auto-discovery from /.well-known/openid-configuration if an issuer_url is provided.

Attributes:

Name Type Description
issuer_url str

Base issuer URL used for OIDC discovery and issuer validation.

require_id_token_validation bool

Controls whether ID tokens are validated after token exchange.

Initialize a generic OIDC provider.

Functions

close async
close() -> None

Close the shared HTTP client.

Notes

Call this from application shutdown hooks to release open sockets.

build_authorize_url
build_authorize_url(redirect_uri: str, state: str, pkce: PKCEChallenge | None = None, extra_params: dict[str, str] | None = None) -> str

Build the full authorization URL.

get_userinfo async
get_userinfo(access_token: str) -> dict[str, Any]

Fetch user profile information from the provider.

Raises:

Type Description
HTTPError

Raised when the userinfo endpoint returns an error response.

validate_id_token async
validate_id_token(id_token: str, nonce: str | None = None) -> dict[str, Any]

Validate an OIDC ID token.

Checks signature (via JWKS), issuer, audience, expiry, and nonce.

Raises:

Type Description
TokenError

If validation fails for any reason.

exchange_code async
exchange_code(code: str, redirect_uri: str, pkce_verifier: str | None = None, nonce: str | None = None) -> OAuthTokenSet

Exchange authorization code for tokens via OIDC token endpoint.

Raises:

Type Description
TokenError

Raised when discovery fails, the token endpoint is unavailable, or the token exchange response is invalid.

refresh_tokens async
refresh_tokens(refresh_token: str) -> OAuthTokenSet

Refresh tokens via the OIDC token endpoint.

Raises:

Type Description
TokenRefreshError

Raised when discovery or the refresh request fails.

revoke_token async
revoke_token(token: str) -> bool

Revoke a token via the OIDC revocation endpoint.

Triggers endpoint auto-discovery before delegating to the base implementation.

GoogleProvider

GoogleProvider(client_id: str, client_secret: str = '', scopes: list[str] | None = None)

Bases: GenericOIDCProvider

Google OAuth2 provider with preset endpoints.

Notes

Google authorization requests default to offline access and consent prompts so refresh tokens are returned consistently.

Initialize the Google OAuth provider.

Functions

close async
close() -> None

Close the shared HTTP client.

Notes

Call this from application shutdown hooks to release open sockets.

exchange_code async
exchange_code(code: str, redirect_uri: str, pkce_verifier: str | None = None, nonce: str | None = None) -> OAuthTokenSet

Exchange authorization code for tokens via OIDC token endpoint.

Raises:

Type Description
TokenError

Raised when discovery fails, the token endpoint is unavailable, or the token exchange response is invalid.

refresh_tokens async
refresh_tokens(refresh_token: str) -> OAuthTokenSet

Refresh tokens via the OIDC token endpoint.

Raises:

Type Description
TokenRefreshError

Raised when discovery or the refresh request fails.

get_userinfo async
get_userinfo(access_token: str) -> dict[str, Any]

Fetch user profile information from the provider.

Raises:

Type Description
HTTPError

Raised when the userinfo endpoint returns an error response.

revoke_token async
revoke_token(token: str) -> bool

Revoke a token via the OIDC revocation endpoint.

Triggers endpoint auto-discovery before delegating to the base implementation.

validate_id_token async
validate_id_token(id_token: str, nonce: str | None = None) -> dict[str, Any]

Validate an OIDC ID token.

Checks signature (via JWKS), issuer, audience, expiry, and nonce.

Raises:

Type Description
TokenError

If validation fails for any reason.

build_authorize_url
build_authorize_url(redirect_uri: str, state: str, pkce: PKCEChallenge | None = None, extra_params: dict[str, str] | None = None) -> str

Build a Google authorization URL with offline access defaults.

GitHubProvider

GitHubProvider(client_id: str, client_secret: str = '', scopes: list[str] | None = None)

Bases: OAuthProvider

GitHub OAuth2 provider.

GitHub uses a non-standard token exchange (no OIDC) and a separate API endpoint for user info.

Notes

GitHub is not OIDC-based here, so token exchange and revocation use provider-specific endpoints and payloads.

Initialize the GitHub OAuth provider.

Functions

close async
close() -> None

Close the shared HTTP client.

Notes

Call this from application shutdown hooks to release open sockets.

build_authorize_url
build_authorize_url(redirect_uri: str, state: str, pkce: PKCEChallenge | None = None, extra_params: dict[str, str] | None = None) -> str

Build the full authorization URL.

get_userinfo async
get_userinfo(access_token: str) -> dict[str, Any]

Fetch user profile information from the provider.

Raises:

Type Description
HTTPError

Raised when the userinfo endpoint returns an error response.

exchange_code async
exchange_code(code: str, redirect_uri: str, pkce_verifier: str | None = None, nonce: str | None = None) -> OAuthTokenSet

Exchange an authorization code for a GitHub access token.

Raises:

Type Description
TokenError

Raised when the exchange request fails or GitHub returns an error payload.

refresh_tokens async
refresh_tokens(refresh_token: str) -> OAuthTokenSet

Refresh GitHub tokens using GitHub's refresh-token flow.

Raises:

Type Description
TokenRefreshError

Raised when the refresh request fails or GitHub returns an error payload.

revoke_token async
revoke_token(token: str) -> bool

Revoke a GitHub token via the Applications API.

Uses DELETE /applications/{client_id}/token with HTTP Basic authentication (client_id / client_secret).

MicrosoftProvider

MicrosoftProvider(client_id: str, client_secret: str = '', tenant_id: str = 'common', scopes: list[str] | None = None)

Bases: GenericOIDCProvider

Microsoft / Azure AD OAuth2 provider.

Attributes:

Name Type Description
tenant_id str

Azure AD tenant identifier used to build authorize and token endpoints.

Initialize the Microsoft OAuth provider.

Functions

close async
close() -> None

Close the shared HTTP client.

Notes

Call this from application shutdown hooks to release open sockets.

build_authorize_url
build_authorize_url(redirect_uri: str, state: str, pkce: PKCEChallenge | None = None, extra_params: dict[str, str] | None = None) -> str

Build the full authorization URL.

exchange_code async
exchange_code(code: str, redirect_uri: str, pkce_verifier: str | None = None, nonce: str | None = None) -> OAuthTokenSet

Exchange authorization code for tokens via OIDC token endpoint.

Raises:

Type Description
TokenError

Raised when discovery fails, the token endpoint is unavailable, or the token exchange response is invalid.

refresh_tokens async
refresh_tokens(refresh_token: str) -> OAuthTokenSet

Refresh tokens via the OIDC token endpoint.

Raises:

Type Description
TokenRefreshError

Raised when discovery or the refresh request fails.

get_userinfo async
get_userinfo(access_token: str) -> dict[str, Any]

Fetch user profile information from the provider.

Raises:

Type Description
HTTPError

Raised when the userinfo endpoint returns an error response.

revoke_token async
revoke_token(token: str) -> bool

Revoke a token via the OIDC revocation endpoint.

Triggers endpoint auto-discovery before delegating to the base implementation.

validate_id_token async
validate_id_token(id_token: str, nonce: str | None = None) -> dict[str, Any]

Validate an OIDC ID token.

Checks signature (via JWKS), issuer, audience, expiry, and nonce.

Raises:

Type Description
TokenError

If validation fails for any reason.

SessionManager

SessionManager(provider: OAuthProvider, token_store: TokenStore, session_key: str = 'default', session_store: SessionStore | None = None, refresh_buffer_seconds: int = 60, on_reauth_required: Callable[[], None] | None = None)

Manages OAuth2 token lifecycle with automatic refresh.

Initialize the session manager.

Functions

initialize async
initialize() -> OAuthTokenSet | None

Load existing tokens from store and validate.

save_tokens async
save_tokens(tokens: OAuthTokenSet) -> None

Persist tokens and schedule background refresh.

get_access_token async
get_access_token() -> str

Get a valid access token, refreshing if near expiry.

Raises:

Type Description
TokenExpiredError

If the token is expired and cannot be refreshed.

refresh async
refresh() -> OAuthTokenSet

Refresh the access token.

Uses the stored refresh token to obtain a new access token. Falls back to on_reauth_required if refresh fails.

Raises:

Type Description
TokenRefreshError

If refresh fails and no re-auth callback is set.

logout async
logout() -> None

Clear all tokens and cancel scheduled refresh.

Optionally revokes the token at the provider.

TokenStore

Bases: ABC

Abstract base class for OAuth2 token storage.

All methods are async to support both local and network-backed stores.

Functions

save abstractmethod async
save(key: str, tokens: OAuthTokenSet) -> None

Save tokens under the given key.

load abstractmethod async
load(key: str) -> OAuthTokenSet | None

Load tokens for the given key.

delete abstractmethod async
delete(key: str) -> None

Delete tokens for the given key.

exists abstractmethod async
exists(key: str) -> bool

Check if tokens exist for the given key.

list_keys abstractmethod async
list_keys() -> list[str]

List all stored token keys.

MemoryTokenStore

MemoryTokenStore()

Bases: TokenStore

In-memory token store for development and single-process use.

Thread-safe via asyncio.Lock, same pattern as MemorySessionStore.

Initialize the memory token store.

Functions

save async
save(key: str, tokens: OAuthTokenSet) -> None

Save tokens in memory.

load async
load(key: str) -> OAuthTokenSet | None

Load tokens from memory.

delete async
delete(key: str) -> None

Delete tokens from memory.

exists async
exists(key: str) -> bool

Check if tokens exist in memory.

list_keys async
list_keys() -> list[str]

List all token keys in memory.

RedisTokenStore

RedisTokenStore(redis_url: str = 'redis://localhost:6379/0', prefix: str = 'pywry', pool_size: int = 10)

Bases: TokenStore

Redis-backed token store for multi-worker deployments.

Uses Redis hash keys with optional TTL based on token expires_in.

Initialize the Redis token store.

Functions

save async
save(key: str, tokens: OAuthTokenSet) -> None

Save tokens to Redis with optional TTL.

load async
load(key: str) -> OAuthTokenSet | None

Load tokens from Redis.

delete async
delete(key: str) -> None

Delete tokens from Redis.

exists async
exists(key: str) -> bool

Check if tokens exist in Redis.

list_keys async
list_keys() -> list[str]

List all token keys in Redis.

PKCEChallenge dataclass

PKCEChallenge(verifier: str, challenge: str, method: str = 'S256')

PKCE code verifier and challenge pair.

Attributes:

Name Type Description
verifier str

The code verifier (high-entropy random string).

challenge str

The code challenge (base64url-encoded SHA-256 hash of verifier).

method str

The challenge method, always "S256".

Functions

generate classmethod
generate(length: int = 64) -> PKCEChallenge

Generate a new PKCE code verifier and challenge.

Functions

create_provider_from_settings

create_provider_from_settings(settings: Any) -> OAuthProvider

Create an OAuthProvider instance from OAuth2Settings.

Raises:

Type Description
AuthenticationError

If the provider type is unknown or settings are invalid.

Notes

The settings object is accessed via getattr so callers may supply configuration objects with compatible attribute names rather than a single concrete settings type.

get_token_store

get_token_store(backend: str = 'memory', **kwargs: Any) -> TokenStore

Factory function for token stores.

Returns a singleton instance. Call reset_token_store() to clear the cached instance (e.g. in tests).


Submodules

Module Description
Providers OAuthProvider ABC and concrete implementations (Google, GitHub, Microsoft, OIDC)
Token Store Pluggable token storage backends (memory, keyring, Redis)
Flow AuthFlowManager — orchestrates the full OAuth2 authorization code flow
Session SessionManager — token lifecycle with automatic background refresh
Deploy Routes FastAPI router for server-side OAuth2 in deploy mode
Callback Server Ephemeral localhost server for capturing OAuth2 redirects
PKCE RFC 7636 PKCE code challenge generation