Files
zitadel/internal/command
Max PeintnerandGitHub 11912ac749 fix: allow invite codes for users whose auth methods were all removed (#12453)
# Which Problems Are Solved

When a user has no primary auth method (no password, passkey, or IDP
link), the login app routes them to the verify page and lets them
(re)send an invite code. But clicking **Resend** failed with
`Errors.User.AlreadyInitialised` (surfaced in the login UI as the
misleading "User is already verified!").

The cause was in the invite write model (`UserV2InviteWriteModel`): its
`AuthMethodSet` flag was **sticky**. It was set to `true` the first time
a user ever got a password, passkey, or IDP link, and was never cleared
— the removal events weren't even loaded by the query. So a user who
*once* had an auth method that was later removed was permanently treated
as "initialized," even though `ListUserAuthMethodTypes` (what the login
app checks) correctly reported zero methods. That disagreement blocked
invite creation/resend for legitimately method-less users.

# How the Problems Are Solved

Track the user's auth methods as the **current set** instead of a sticky
flag:
- Replaced the `AuthMethodSet bool` field with an `authMethods` set,
keyed uniquely per method (password / IDP link / passkey).
- Reduce now also handles the removal events (`UserIDPLinkRemoved`,
`UserIDPLinkCascadeRemoved`, `HumanPasswordlessTokenRemoved`), and these
event types were added to the write model's query filter so they're
loaded.
- `AuthMethodSet()` is now simply "does the user currently have ≥1 auth
method," so `CreationAllowed()` reflects reality.

The security guard is unchanged: a user who still has any auth method is
refused. The only behavior change is that a user with **no current**
auth method (including one whose methods were all removed) can again
receive an invite code — matching what the login app already assumes. No
extra queries (same single event filter, a few more event types), and no
data migration (pure re-derivation from existing events).

Added tests covering both an initialized user (still refused) and invite
creation succeeding after all auth methods are removed.
2026-08-12 06:24:28 +00:00
..
2026-06-15 15:36:14 +02:00
2026-03-17 12:54:27 +01:00
2026-03-17 12:54:27 +01:00
2026-03-17 12:54:27 +01:00
2024-11-04 10:44:51 +00:00
2026-07-29 05:46:27 +02:00
2026-03-17 12:54:27 +01:00
2026-06-16 15:19:56 +02:00
2024-09-11 10:53:55 +00:00
2026-06-15 15:36:14 +02:00
2026-06-15 15:27:47 +02:00
2024-04-11 09:16:10 +02:00
2024-01-17 10:16:48 +00:00
2024-01-17 10:16:48 +00:00
2026-06-16 15:19:56 +02:00
2026-06-16 15:19:56 +02:00
2026-07-09 13:28:09 +02:00
2025-07-15 13:38:00 +02:00
2025-07-15 13:38:00 +02:00
2025-10-29 10:07:35 +01:00
2025-10-29 10:07:35 +01:00
2026-06-15 15:36:14 +02:00
2026-06-15 15:36:14 +02:00
2026-06-15 15:36:14 +02:00
2026-06-15 15:36:14 +02:00
2026-03-11 08:25:21 +01:00
2026-07-09 13:28:09 +02:00
2026-07-09 13:28:09 +02:00
2025-10-29 10:07:35 +01:00
2025-10-29 10:07:35 +01:00
2026-06-08 16:41:08 +02:00
2026-06-08 16:41:08 +02:00
2026-06-08 16:41:08 +02:00
2026-06-08 16:41:08 +02:00
2026-03-11 08:25:21 +01:00
2026-03-11 08:25:21 +01:00
2026-06-08 16:41:08 +02:00
2026-06-08 16:41:08 +02:00