diff --git a/README.md b/README.md index 32e5d1e..0328a7d 100644 --- a/README.md +++ b/README.md @@ -177,10 +177,12 @@ Off by default — a clean clone is password-only. Kratos activates a provider p from the environment (no code, no rebuild): set `SELFSERVICE_METHODS_OIDC_ENABLED=true` and `SELFSERVICE_METHODS_OIDC_CONFIG_PROVIDERS` to a JSON array of providers (`google`, `microsoft`, …), each carrying its `client_id`/`client_secret` and referencing the -committed claims mapper `ory/kratos/oidc/claims.jsonnet`. No creds ⇒ no provider ⇒ no -SSO button (§4 derives the buttons from this list). Open-source Kratos has **no native -SAML** — front it with an OIDC bridge (Ory Polis) and register that bridge as a generic -OIDC provider the same way. +committed claims mapper `ory/kratos/oidc/claims.jsonnet`. The themed sign-in/register +pages derive one button per provider from the live flow's `oidc` nodes, so no creds ⇒ no +provider ⇒ no button, and the whole SSO section disappears when none are configured — no +code change to add or remove one. Open-source Kratos has **no native SAML** — front it +with an OIDC bridge (Ory Polis) and register that bridge as a generic OIDC provider the +same way. ### JWT signing key & rotation diff --git a/public/css/auth.css b/public/css/auth.css index 89dfde3..0165968 100644 --- a/public/css/auth.css +++ b/public/css/auth.css @@ -49,9 +49,8 @@ body:has(#forgot:target) #login { display: none; } } .auth-back:hover { color: var(--text); } -/* ---- SSO section (toggle on/off via #sso-toggle) ---- */ +/* ---- SSO section (rendered server-side only when providers are configured) ---- */ .sso { display: flex; flex-direction: column; gap: 10px; } -body:not(:has(#sso-toggle:checked)) .sso { display: none; } .sso-list { display: flex; flex-direction: column; gap: 8px; } .sso-btn { diff --git a/src/app.test.ts b/src/app.test.ts index bcd1129..7562cff 100644 --- a/src/app.test.ts +++ b/src/app.test.ts @@ -213,6 +213,7 @@ const loginFlow = (id: string): Flow => ({ node({ name: "identifier", required: true, type: "email" }, "E-Mail"), node({ name: "password", required: true, type: "password" }, "Password"), node({ name: "method", type: "submit", value: "password" }, "Sign in"), + { attributes: { name: "provider", type: "submit", value: "google" }, group: "oidc", messages: [], meta: { label: { id: 1, text: "Sign in with Google", type: "info" } }, type: "input" }, ], }, }); @@ -256,6 +257,9 @@ test("renders a fetched flow as the themed auth page: fields post straight to Kr assert.match(html, /name="password"[^>]*type="password"/); assert.match(html, /', alt: { text: "Don't have an account?", href: "/register", label: "Create one" }, @@ -25,6 +26,8 @@ test("auth-card renders head, SSO providers (text logo + icon link), body slot a assert.match(html, /
+
<%= sso.divider || "or" %>
<% } -%>