mirror of
https://github.com/zitadel/zitadel.git
synced 2026-11-02 20:30:51 -06:00
# 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)