Files
zitadel/internal/api/saml
Livio Spring a9311b8c70 fix: block Login V2 auth for users in deactivated organizations
# Which Problems Are Solved

- Deactivating an organization did not prevent its users from authenticating via Login V2 (session creation, OIDC token issuance/refresh, SAML session creation).
- Only user-level state was checked on the Login V2 path; organization state was ignored.
- That contradicted documented and in-product behavior.
- Already-issued sessions, refresh tokens, V2 access tokens, claim-serving paths, and ZITADEL API calls from the deactivated org also continued to work.

# How the Problems Are Solved

- Shared auth guard: user and org state before Login V2 session bind, OIDC issue/refresh, and SAML session create.
- Claim serving: active resource-owner org required in OIDC userinfo and SAML attributes.
- Cleanup on `OrgDeactivated`: drop V2 sessions and V1 user sessions / tokens / refresh tokens (same pattern as `OrgRemoved`). Also drop V2 sessions on `OrgRemoved`.
- Authz: `CheckOrgActive` on the caller’s `resourceOwner` (cached `OrgByID`). Inactive caller org returns 401 Unauthenticated. Target org (`x-zitadel-orgid`) is not gated so instance admins can still reactivate.
- Durable refresh: reject exchange if `OrgDeactivated` occurred after `RefreshTokenIssuedAt` (stays invalid after reactivate).
- Durable V2 AT: `OrgDeactivated` after token position is treated as session termination in `checkSessionNotTerminatedAfter` / `ActiveAccessTokenByToken`.

# Additional Changes

- `OrgState.IsActive()` helper.
- Distinct error IDs for inactive user vs inactive org.
- `Errors.Org.NotActive` i18n.
- Unit and integration coverage for mint, claims, authz, refresh, and AT paths.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 260446f91f)
2026-08-14 07:00:05 +02:00
..