Optionally require an OIDC sign-in in front of the app - #29
Merged
Conversation
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an optional OpenID Connect sign-in gate, so the app can be put behind an organisation's SSO where no authenticating proxy exists. Off by default (
OIDC_ENABLED=false) — existing deployments are unchanged.Scope
It is a gate, not an authorisation model. Everyone who can sign in gets the same, whole application: no accounts, no roles, no permissions, no user records. Restricting who may sign in stays at the provider.
llmaixweb's flow was the model, minus everything that needs a database (provider CRUD, JIT provisioning, identity linking, audit rows).
Backend
core/config.pyOIDC_*settings +APP_PUBLIC_URL;validate_auth_settings()refuses to start on a half-configured gate — in every environment, since a gate that silently doesn't gate is worse than one that doesn't come uputils/auth.pyservices/oidc_client.pymiddleware/auth_gate.py/api/v1/auth/*and/health/*routers/v1/endpoints/auth.pysession/login/callback/logoutSecurity properties worth naming:
iss,aud,expand nonce; asymmetric algorithms only (HS256andnoneare refused)HttpOnly+SameSite=Lax+Secure(over https), scoped to/apilog_referencehashFrontend
stores/auth.ts+components/auth/SignInGate.vue, plus a header account chip with sign-out. Failed sign-ins come back as?auth_error=<code>and render a sentence rather than JSON. A mid-session 401 — from axios or the NDJSON stream — brings the gate back with "session expired". All strings in de/en/fr/es.Dependency
pyjwt[crypto]==2.13.0(MIT; pullscryptography, Apache-2.0 OR BSD-3-Clause — no AGPL conflict).uv.lockandTHIRD_PARTY_NOTICES.mdregenerated.Tests
51 new:
alg: none, JWKS caching and key rotationFull local gate passes: ruff, 381 pytest,
npm run check,npm run build, 12 Playwright e2e, mkdocs build.Docs
New
docs/operations/sso.md(+ nav), plus configuration reference, deployment, installation,SECURITY.md,THREAT_MODEL.md,DATA_FLOW.md,RISK_REGISTER.md, architecture,.env.exampleandCHANGELOG.md.AGENTS.md's "no auth" claim was corrected rather than left stale.