You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An admin creates a user type where password is not marked as a required attribute, then invites a user via the Console's invite-link flow or create a user without password. The invited user fills in the fields the flow actually asks for - if the flow's prompt step doesn't ask for a password, or the user just leaves it blank because the field isn't required - and completes registration successfully.
The account now exists, with no password, no passkey, nothing. If the organization hasn't separately enabled an authenticator that doesn't depend on a stored credential (OTP, magic link, a federated IdP), that user has no way to authenticate again. Not "an awkward first login" - genuinely no path back in. Someone has to notice and fix it by hand.
What I found tracing this
password is a schema-defined credential attribute with a Required flag (entitytype/model/schema.go:110). Admins control it per user type.
CreateEntity validates with skipCredentialRequired=false (entity/service.go:127), which reduces the requiredness check to just prop.isRequired(). If the schema says password isn't required, entity creation succeeds with the credential attribute simply absent.
Nothing above that enforces "this entity must end up with at least one usable authenticator." CredentialSetter (the executor that actually writes a password during a flow) is a registered executor an admin can wire into a flow - flow/executor/register.go:221 - not a step the flow engine requires. I checked flow/mgt/validator.go for a completeness rule along these lines and didn't find one, the only "at least one" check there is about SessionExecutor checkpoint references, unrelated to this.
So the gap isn't in one place - it's that requiredness is a per-attribute schema choice, flow composition is fully open-ended, and nothing sits between the two asking "will a user who goes through this flow, with this schema, actually be able to sign in again?"
There's a real design decision under the practical issue, and I'd rather get input than pick one silently,
Where should the guarantee live? Schema validation (a credential attribute can't be Required: false unless some other org-level authenticator is guaranteed available)? Flow validation (a flow that creates entities must include a credential/authenticator step before it can be published)? A runtime check at the end of provisioning (reject completion if the resulting entity has zero authenticators and the org has no fallback)? Some combination?
Is this actually password-specific, or bigger? The same Required flag exists on other credential-type attributes (passkey is the other one defined today - user/constants.go). If an org's only authenticator is set optional and nobody configured a fallback, the same dead end applies regardless of which credential type it is. Worth framing this as "an entity must end up with at least one authenticator," not "password must be required."
What's the right failure mode? Block the schema from saving with password optional and no fallback configured (fails loud, early, for the admin)? Block flow publishing? Block flow execution at the point registration would otherwise complete (fails loud, late, for the invited user - worse)? Something else?
Related
#5227 is about verifying an existing password before a self-service change - it assumes the account already has one. This is upstream of that: how an account can end up with none in the first place, and what should stop it.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Scenario
An admin creates a user type where
passwordis not marked as a required attribute, then invites a user via the Console's invite-link flow or create a user withoutpassword. The invited user fills in the fields the flow actually asks for - if the flow's prompt step doesn't ask for a password, or the user just leaves it blank because the field isn't required - and completes registration successfully.The account now exists, with no password, no passkey, nothing. If the organization hasn't separately enabled an authenticator that doesn't depend on a stored credential (OTP, magic link, a federated IdP), that user has no way to authenticate again. Not "an awkward first login" - genuinely no path back in. Someone has to notice and fix it by hand.
What I found tracing this
passwordis a schema-defined credential attribute with aRequiredflag (entitytype/model/schema.go:110). Admins control it per user type.CreateEntityvalidates withskipCredentialRequired=false(entity/service.go:127), which reduces the requiredness check to justprop.isRequired(). If the schema sayspasswordisn't required, entity creation succeeds with the credential attribute simply absent.CredentialSetter(the executor that actually writes a password during a flow) is a registered executor an admin can wire into a flow -flow/executor/register.go:221- not a step the flow engine requires. I checkedflow/mgt/validator.gofor a completeness rule along these lines and didn't find one, the only "at least one" check there is aboutSessionExecutorcheckpoint references, unrelated to this.So the gap isn't in one place - it's that requiredness is a per-attribute schema choice, flow composition is fully open-ended, and nothing sits between the two asking "will a user who goes through this flow, with this schema, actually be able to sign in again?"
There's a real design decision under the practical issue, and I'd rather get input than pick one silently,
Where should the guarantee live? Schema validation (a credential attribute can't be
Required: falseunless some other org-level authenticator is guaranteed available)? Flow validation (a flow that creates entities must include a credential/authenticator step before it can be published)? A runtime check at the end of provisioning (reject completion if the resulting entity has zero authenticators and the org has no fallback)? Some combination?Is this actually password-specific, or bigger? The same
Requiredflag exists on other credential-type attributes (passkey is the other one defined today -user/constants.go). If an org's only authenticator is set optional and nobody configured a fallback, the same dead end applies regardless of which credential type it is. Worth framing this as "an entity must end up with at least one authenticator," not "password must be required."What's the right failure mode? Block the schema from saving with password optional and no fallback configured (fails loud, early, for the admin)? Block flow publishing? Block flow execution at the point registration would otherwise complete (fails loud, late, for the invited user - worse)? Something else?
Related
#5227 is about verifying an existing password before a self-service change - it assumes the account already has one. This is upstream of that: how an account can end up with none in the first place, and what should stop it.
All reactions