@@ -144,8 +144,18 @@ pywry/
144144│ ├── _factory.py # Factory functions for store instantiation
145145│ ├── memory.py # In-memory state backends (default)
146146│ ├── redis.py # Redis-backed state backends
147- │ ├── types.py # Type definitions (StateBackend, WidgetData, etc.)
148- │ └── auth.py # Authentication and RBAC utilities
147+ │ ├── types.py # Type definitions (StateBackend, WidgetData, OAuthTokenSet, etc.)
148+ │ ├── auth.py # Authentication and RBAC utilities
149+ │ └── sync_helpers.py # Sync↔async bridging (run_async, wait_for_event)
150+ ├── auth/ # OAuth2 authentication system
151+ │ ├── __init__.py # Public exports
152+ │ ├── pkce.py # PKCE challenge generation (RFC 7636)
153+ │ ├── providers.py # OAuthProvider ABC + Google, GitHub, Microsoft, OIDC implementations
154+ │ ├── token_store.py # TokenStore ABC + Memory, Keyring, Redis backends
155+ │ ├── callback_server.py # Ephemeral localhost server for native auth redirects
156+ │ ├── deploy_routes.py # FastAPI /auth/* routes for deploy mode
157+ │ ├── flow.py # AuthFlowManager orchestrator
158+ │ └── session.py # SessionManager with automatic token refresh
149159├── utils/ # Utility helpers
150160└── window_manager/ # Window mode implementations
151161 ├── controller.py
@@ -1134,6 +1144,72 @@ PYWRY_DEPLOY__DEFAULT_ROLE=viewer
11341144
11351145---
11361146
1147+ ## Authentication & OAuth2
1148+
1149+ PyWry includes a full OAuth2 authentication system that works in both native window mode and deploy mode.
1150+
1151+ ### Quick Start (Native Mode)
1152+
1153+ ``` python
1154+ from pywry import PyWry
1155+
1156+ app = PyWry()
1157+
1158+ # Login with Google (configure via environment variables)
1159+ # PYWRY_OAUTH2__PROVIDER=google
1160+ # PYWRY_OAUTH2__CLIENT_ID=your-client-id
1161+ # PYWRY_OAUTH2__CLIENT_SECRET=your-secret
1162+ result = app.login()
1163+
1164+ if result.success:
1165+ print (f " Logged in! Tokens: { result.tokens.token_type} " )
1166+ app.show(" <h1>Welcome!</h1>" )
1167+ app.block()
1168+ ```
1169+
1170+ ### Quick Start (Deploy Mode)
1171+
1172+ ``` bash
1173+ PYWRY_DEPLOY__AUTH_ENABLED=true
1174+ PYWRY_DEPLOY__STATE_BACKEND=redis
1175+ PYWRY_OAUTH2__PROVIDER=github
1176+ PYWRY_OAUTH2__CLIENT_ID=your-client-id
1177+ PYWRY_OAUTH2__CLIENT_SECRET=your-secret
1178+ ```
1179+
1180+ Deploy mode automatically mounts ` /auth/login ` , ` /auth/callback ` , ` /auth/logout ` , ` /auth/status ` routes.
1181+
1182+ ### Architecture
1183+
1184+ | Component | File | Purpose |
1185+ | -----------| ------| ---------|
1186+ | ` OAuthProvider ` | ` auth/providers.py ` | ABC for OAuth2 providers (Google, GitHub, Microsoft, OIDC, custom) |
1187+ | ` PKCEChallenge ` | ` auth/pkce.py ` | PKCE code challenge generation (RFC 7636) |
1188+ | ` TokenStore ` | ` auth/token_store.py ` | ABC for token persistence (Memory, Keyring, Redis) |
1189+ | ` OAuthCallbackServer ` | ` auth/callback_server.py ` | Ephemeral localhost HTTP server for native redirect capture |
1190+ | ` AuthFlowManager ` | ` auth/flow.py ` | Orchestrates the complete OAuth2 flow |
1191+ | ` SessionManager ` | ` auth/session.py ` | Token lifecycle with automatic background refresh |
1192+ | ` deploy_routes ` | ` auth/deploy_routes.py ` | FastAPI ` /auth/* ` routes for production deployments |
1193+
1194+ ### OAuth2Settings
1195+
1196+ | Setting | Type | Default | Description |
1197+ | ---------| ------| ---------| -------------|
1198+ | ` provider ` | ` str ` | ` "custom" ` | ` google ` , ` github ` , ` microsoft ` , ` oidc ` , or ` custom ` |
1199+ | ` client_id ` | ` str ` | ` "" ` | OAuth2 client ID |
1200+ | ` client_secret ` | ` str ` | ` "" ` | Client secret (empty for PKCE public clients) |
1201+ | ` scopes ` | ` str ` | ` "openid email profile" ` | Space-separated scopes |
1202+ | ` use_pkce ` | ` bool ` | ` True ` | Enable PKCE for public clients |
1203+ | ` token_store_backend ` | ` str ` | ` "memory" ` | ` memory ` , ` keyring ` , or ` redis ` |
1204+ | ` auth_timeout_seconds ` | ` float ` | ` 120.0 ` | Max wait for OAuth callback |
1205+ | ` refresh_buffer_seconds ` | ` int ` | ` 60 ` | Pre-expiry refresh margin |
1206+
1207+ ### Frontend Integration
1208+
1209+ When authenticated, ` window.__PYWRY_AUTH__ ` contains ` { user_id, roles, token_type } ` . Use ` window.pywry.auth.isAuthenticated() ` , ` .getState() ` , ` .login() ` , ` .logout() ` , ` .onAuthStateChange(cb) ` .
1210+
1211+ ---
1212+
11371213## Key Classes Reference
11381214
11391215### Core Classes
0 commit comments