fix: gate second factors after SSO/LDAP behind an admin setting

This commit is contained in:
LukeGus committed 2026-09-23 07:17:03 -05:00
1 parent f217d8db89
commit 95abe24798
13 files changed
+307 -5

No files matched your search

+8 -1
View File
@@ -610,6 +610,7 @@ ctx.auth.registerLoginMethod({
id: "corp-sso",
labelKey: "signIn",
kind: "redirect",
external: true, // governs the "second factor after external logins" setting
describe: async () => [{ id: "main", label: "Corp", enabled: true }],
start: async (request, instanceId) => ({ redirectUrl }),
callback: async (request) => ({
@@ -648,7 +649,13 @@ or an external identity. Core then:
3. runs second factors: every row in `user_second_factors` plus any factor
that reports itself enrolled. **Fail closed:** a row whose plugin is
disabled or gone refuses the login ("contact an admin"). A trusted device
or a method that already proved a factor (a verified passkey) skips the step;
or a method that already proved a factor (a verified passkey) skips the step.
This step is skipped entirely for a login method whose registration sets
`external: true` (OIDC, LDAP; a plugin declares it the same way) unless the
admin setting "ask for a second factor after external logins" is on. Off
by default, matching the behaviour before second factors applied to every
method: a local method (password, a passkey, a plugin's own local form)
always runs them;
4. issues the JWT, cookie, trusted device and the `login` audit line.
Routes, all under `/users/auth`: `GET methods` (public), `GET :methodId/start`,
+8
View File
@@ -697,6 +697,14 @@ export interface PluginLoginMethod {
labelKey: string;
icon?: string;
kind: "redirect" | "form";
/**
* True for a method that authenticates against something other than a
* password or key this server holds: SSO, an external directory, a
* federated identity provider. Governs whether the "ask for a second
* factor after external logins" admin setting applies to it. Leave unset
* for a local method (password, a passkey, a plugin's own local form).
*/
external?: boolean;
/** Enabled instances, shown on the login screen. No secrets. */
describe?: () => Promise<PluginLoginInstance[]>;
/** Redirect methods: where to send the browser. */