# kaya-oidc OpenID Connect authentication for the Kaya web framework. Built on top of `kaya-session` and implements the OIDC **Authorization Code Flow with PKCE**. ## Usage ```python import os from kaya.core import HttpContext, KayaApp from kaya.session import SessionMixin, InMemorySessionStore from kaya.oidc import OIDCConfig, OIDCMixin session = SessionMixin(InMemorySessionStore()) oidc = OIDCMixin( OIDCConfig( issuer=os.environ['OIDC_ISSUER'], client_id=os.environ['OIDC_CLIENT_ID'], client_secret=os.environ.get('OIDC_CLIENT_SECRET'), redirect_uri='http://localhost:8000/auth/callback', fetch_userinfo=True, ), session=session, ) app = KayaApp(mixins=[session, oidc]) @app.GET('/') async def home(ctx: HttpContext): await ctx.send_str(200, 'public home') @app.GET('/profile') @oidc.require_auth async def profile(ctx: HttpContext): user = oidc.get_user(ctx) await ctx.send_str(200, f'Hello {user.email or user.sub}') ``` `OIDCMixin` depends on `SessionMixin`; passing only `oidc` to `KayaApp(mixins=...)` also works because the app applies mixin dependencies automatically. ## Multiple providers Use `OIDCProviders` to run several OIDC providers in one application. Each config's `provider` becomes a route segment under `base_path` (`/auth/{provider}/login`, `/auth/{provider}/callback` and `/auth/{provider}/logout`), and all providers share a single `SessionMixin`: ```python from kaya.oidc import OIDCConfig, OIDCProviders session = SessionMixin(InMemorySessionStore()) oidc = OIDCProviders( [ OIDCConfig( issuer='https://accounts.google.com', client_id=os.environ['GOOGLE_CLIENT_ID'], client_secret=os.environ['GOOGLE_CLIENT_SECRET'], redirect_uri='http://localhost:8000/auth/google/callback', provider='google', ), OIDCConfig( issuer='https://github.com/login/oauth', # or any OIDC issuer client_id=os.environ['GITHUB_CLIENT_ID'], client_secret=os.environ['GITHUB_CLIENT_SECRET'], redirect_uri='http://localhost:8000/auth/github/callback', provider='github', ), ], session=session, base_path='/auth', # optional ) app = KayaApp(mixins=[session, oidc]) @app.GET('/google-profile') @oidc.require_auth('google') async def google_profile(ctx: HttpContext): user = oidc.get_user(ctx, 'google') await ctx.send_str(200, f"Hello {user.email or user.sub}") @app.GET('/who') async def who(ctx: HttpContext): users = oidc.get_users(ctx) # {provider: OIDCUser} providers = oidc.logged_in_providers(ctx) # ['google', ...] await ctx.send_str(200, ', '.join(users)) ``` Each provider's session state is namespaced as `oidc:{provider}:...`, so a user can be logged into several providers at once. Logging out of one provider only removes that provider's state and keeps the shared session alive while another provider is still logged in. Make sure each config's `redirect_uri` points at that provider's derived callback path. The composable alternative is to create one `OIDCMixin` per provider, pointing each at distinct `login_path`/`callback_path`/`logout_path` values and sharing the same `SessionMixin`: ```python google = OIDCMixin(google_config, session=session) github = OIDCMixin(github_config, session=session) app = KayaApp(mixins=[session, google, github]) ``` > **Upgrading:** session keys are now prefixed with `oidc:{provider}:` (the > default provider is `default`). Existing logged-in users are signed out once > and simply re-authenticate. ## Features - Generic OIDC discovery - Authorization Code Flow with PKCE (S256) - ID token signature validation with JWKS - `state` and `nonce` protection - Session fixation defense via `regenerate_id()` after login - Optional userinfo endpoint fetch - Refresh token support - RP-initiated logout (when provider advertises `end_session_endpoint`) - Multiple providers in one app via `OIDCProviders` (or several `OIDCMixin` instances) - Composable with any other `KayaMixin` (RSGI, MCP, etc.) ## Security notes - The `none` signing algorithm is rejected by default. - Only algorithms listed in `OIDCConfig.allowed_id_token_algorithms` are accepted. - Always use HTTPS for `redirect_uri` in production. ## Supported flows Only the Authorization Code Flow with PKCE is supported. Implicit and Hybrid flows are intentionally not implemented. ## Supported algorithms ID token signature verification supports: `RS256`, `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `ES256`, `ES384`, `ES512`, and `EdDSA`. HMAC algorithms (`HS*`) are disabled by default and can be enabled by adding them to `allowed_id_token_algorithms` if your provider uses them.