Merge commit from fork

* fix: block Login V2 auth for users in deactivated organizations

Enforce organization state on session creation, OIDC token issuance/refresh,
and SAML session creation so deactivated org users cannot authenticate.

Co-authored-by: Cursor <[email protected]>

* fix: reject claim serving for users in deactivated organizations

Require an active resource-owner org in OIDC userinfo and SAML attribute
paths, and use distinct error IDs for inactive user vs inactive org at
token issuance.

Co-authored-by: Cursor <[email protected]>

* fix: drop sessions and tokens when an organization is deactivated

Mirror OrgRemoved cleanup for OrgDeactivated in the V2 session projection
and V1 auth user_session, token, and refresh_token handlers. Also delete
V2 sessions on OrgRemoved, which does not emit per-user removal events.

Co-authored-by: Cursor <[email protected]>

* fix: reject API tokens from deactivated organizations

Check the caller's resource-owner org state in authz middleware via a
cached OrgByID lookup, so already-issued tokens lose ZITADEL API access
when their organization is deactivated. Return unauthenticated (401).
Target org remains unrestricted so instance admins can still manage
deactivated orgs.

Co-authored-by: Cursor <[email protected]>

* fix: invalidate OIDC refresh tokens after org deactivation

Reject refresh exchange if the user's organization was deactivated
after the refresh token was issued, so grants stay dead after reactivate.

Co-authored-by: Cursor <[email protected]>

* fix: invalidate V2 access tokens after org deactivation

Treat OrgDeactivated after the token position as session termination in
ActiveAccessTokenByToken, so issued ATs stay dead after reactivation.

Co-authored-by: Cursor <[email protected]>

---------

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Livio Spring
2026-08-14 06:12:45 +02:00
committed by GitHub
co-authored by Cursor
parent a4266fa7fc
commit 260446f91f
52 changed files with 854 additions and 20 deletions
+1
View File
@@ -205,6 +205,7 @@ Errors:
AlreadyActive: "المنظمة نشطة بالفعل"
Empty: "المنظمة فارغة"
NotFound: "المنظمة غير موجودة"
NotActive: "المنظمة غير نشطة"
NotChanged: "المنظمة لم تتغير"
DefaultOrgNotDeletable: "لا يجب حذف المنظمة الافتراضية"
ZitadelOrgNotDeletable: "المنظمة التي تحتوي على مشروع ZITADEL لا يجب حذفها"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "Организацията вече е активна"
Empty: "Организацията е празна"
NotFound: "Организацията не е намерена"
NotActive: "Организацията не е активна"
NotChanged: "Организацията не е променена"
DefaultOrgNotDeletable: "Организацията по подразбиране не трябва да се изтрива"
ZitadelOrgNotDeletable: "Организация с проект Zitadel не трябва да се изтрива"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "Organizace je již aktivní"
Empty: "Organizace je prázdná"
NotFound: "Organizace nenalezena"
NotActive: "Organizace není aktivní"
NotChanged: "Organizace nezměněna"
DefaultOrgNotDeletable: "Výchozí organizace nesmí být smazána"
ZitadelOrgNotDeletable: "Organizaci s projektem Zitadel nelze smazat"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "Organisation ist bereits aktiv"
Empty: "Organisation ist leer"
NotFound: "Organisation konnte nicht gefunden werden"
NotActive: "Organisation ist nicht aktiv"
NotChanged: "Organisation wurde nicht verändert"
DefaultOrgNotDeletable: "Default Organisation kann nicht gelöscht werden"
ZitadelOrgNotDeletable: "Organisation mit Zitadel Projekt kann nicht gelöscht werden"
+1
View File
@@ -207,6 +207,7 @@ Errors:
AlreadyActive: "Organisation is already active"
Empty: "Organisation is empty"
NotFound: "Organisation not found"
NotActive: "Organisation is not active"
NotChanged: "Organisation not changed"
DefaultOrgNotDeletable: "Default Organisation must not be deleted"
ZitadelOrgNotDeletable: "Organisation with Zitadel project must not be deleted"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "La organización ya está activada"
Empty: "La organización está vacía"
NotFound: "Organización no encontrada"
NotActive: "La organización no está activa"
NotChanged: "La organización no ha cambiado"
DefaultOrgNotDeletable: "La organización por defecto no debe borrarse"
ZitadelOrgNotDeletable: "La organización que contiene el proyecto Zitadel no debe borrarse"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "L'organisation est déjà active"
Empty: "L'organisation est vide"
NotFound: "Organisation non trouvée"
NotActive: "L'organisation n'est pas active"
NotChanged: "L'organisation n'a pas changé"
DefaultOrgNotDeletable: "L'organisation par défault ne doit pas être supprimée"
ZitadelOrgNotDeletable: "L'organisation avec Zitadel project ne doit pas être supprimée"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "A szervezet már aktív"
Empty: "A szervezet üres"
NotFound: "Szervezet nem található"
NotActive: "A szervezet nem aktív"
NotChanged: "A szervezet nem változott"
DefaultOrgNotDeletable: "Az alapértelmezett szervezetet nem szabad törölni"
ZitadelOrgNotDeletable: "A Zitadel projekttel rendelkező szervezetet nem szabad törölni"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "Organisasi sudah aktif"
Empty: "Organisasi kosong"
NotFound: "Organisasi tidak ditemukan"
NotActive: "Organisasi tidak aktif"
NotChanged: "Organisasi tidak berubah"
DefaultOrgNotDeletable: "Organisasi Default tidak boleh dihapus"
ZitadelOrgNotDeletable: "Organisasi dengan proyek Zitadel tidak boleh dihapus"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "L'organizzazione è già attiva"
Empty: "L'organizzazione è vuota"
NotFound: "Organizzazione non trovata"
NotActive: "L'organizzazione non è attiva"
NotChanged: "Organizzazione non cambiata"
DefaultOrgNotDeletable: "L'organizzazione predefinita non deve essere cancellata"
ZitadelOrgNotDeletable: "L'organizzazione con il progetto Zitadel non deve essere cancellata"
+1
View File
@@ -205,6 +205,7 @@ Errors:
AlreadyActive: "組織はすでにアクティブです"
Empty: "組織は空です"
NotFound: "組織が見つかりません"
NotActive: "組織はアクティブではありません"
NotChanged: "組織は変更されていません"
DefaultOrgNotDeletable: "デフォルトの組織は削除できません"
ZitadelOrgNotDeletable: "Zitadelプロジェクトの組織は削除できません"
+1
View File
@@ -205,6 +205,7 @@ Errors:
AlreadyActive: "조직이 이미 활성화되었습니다"
Empty: "조직이 비어 있습니다"
NotFound: "조직을 찾을 수 없습니다"
NotActive: "조직이 활성 상태가 아닙니다"
NotChanged: "조직이 변경되지 않았습니다"
DefaultOrgNotDeletable: "기본 조직은 삭제할 수 없습니다"
ZitadelOrgNotDeletable: "Zitadel 프로젝트가 포함된 조직은 삭제할 수 없습니다"
+1
View File
@@ -203,6 +203,7 @@ Errors:
AlreadyActive: "Организацијата е веќе активна"
Empty: "Организацијата е празна"
NotFound: "Организацијата не е пронајдена"
NotActive: "Организацијата не е активна"
NotChanged: "Организацијата не е променета"
DefaultOrgNotDeletable: "Стандардната организација не смее да биде избришана"
ZitadelOrgNotDeletable: "Организацијата со Zitadel проект не смее да биде избришана"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "Organisatie is al actief"
Empty: "Organisatie is leeg"
NotFound: "Organisatie niet gevonden"
NotActive: "Organisatie is niet actief"
NotChanged: "Organisatie is niet veranderd"
DefaultOrgNotDeletable: "Standaard organisatie kan niet worden verwijderd"
ZitadelOrgNotDeletable: "Organisatie met Zitadel-project kan niet worden verwijderd"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "Organizacja jest już aktywna"
Empty: "Organizacja jest pusta"
NotFound: "Organizacja nie znaleziona"
NotActive: "Organizacja nie jest aktywna"
NotChanged: "Organizacja nie zmieniona"
DefaultOrgNotDeletable: "Domyślna organizacja nie może być usunięta"
ZitadelOrgNotDeletable: "Organizacja z projektem Zitadel nie może być usunięta"
+1
View File
@@ -203,6 +203,7 @@ Errors:
AlreadyActive: "Organização já está ativa"
Empty: "Organização está vazia"
NotFound: "Organização não encontrada"
NotActive: "A organização não está ativa"
NotChanged: "Organização não alterada"
DefaultOrgNotDeletable: "A organização padrão não pode ser excluída"
ZitadelOrgNotDeletable: "A organização com o projeto Zitadel não pode ser excluída"
+1
View File
@@ -205,6 +205,7 @@ Errors:
AlreadyActive: "Organizația este deja activă"
Empty: "Organizația este goală"
NotFound: "Organizația nu a fost găsită"
NotActive: "Organizația nu este activă"
NotChanged: "Organizația nu a fost schimbată"
DefaultOrgNotDeletable: "Organizația implicită nu trebuie să fie ștearsă"
ZitadelOrgNotDeletable: "Organizația cu proiectul Zitadel nu trebuie să fie ștearsă"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "Организация уже активна"
Empty: "Организация не заполнена"
NotFound: "Организация не найдена"
NotActive: "Организация неактивна"
NotChanged: "Организация не изменена"
DefaultOrgNotDeletable: "Организация по умолчанию не может быть удалена"
ZitadelOrgNotDeletable: "Невозможно удалить организацию с проектом Zitadel"
+1
View File
@@ -204,6 +204,7 @@ Errors:
AlreadyActive: "Organisationen är redan aktiv"
Empty: "Organisationen är tom"
NotFound: "Organisationen hittades inte"
NotActive: "Organisationen är inte aktiv"
NotChanged: "Organisationen ändrades inte"
DefaultOrgNotDeletable: "Standardorganisationen får inte raderas"
ZitadelOrgNotDeletable: "Organisationen med Zitadel-projekt får inte raderas"
+1
View File
@@ -205,6 +205,7 @@ Errors:
AlreadyActive: "Organizasyon zaten aktif"
Empty: "Organizasyon boş"
NotFound: "Organizasyon bulunamadı"
NotActive: "Organizasyon aktif değil"
NotChanged: "Organizasyon değişmedi"
DefaultOrgNotDeletable: "Varsayılan Organizasyon silinmemeli"
ZitadelOrgNotDeletable: "Zitadel projesi olan organizasyon silinmemeli"
+1
View File
@@ -199,6 +199,7 @@ Errors:
AlreadyActive: "Організація вже активна"
Empty: "Організація порожня"
NotFound: "Організація не знайдена"
NotActive: "Організація неактивна"
NotChanged: "Організація не змінена"
DefaultOrgNotDeletable: "Організація за замовчуванням не може бути видалена"
ZitadelOrgNotDeletable: "Організація з проектом Zitadel не може бути видалена"
+1
View File
@@ -205,6 +205,7 @@ Errors:
AlreadyActive: "组织已处于启用状态"
Empty: "组织为空"
NotFound: "未找到组织"
NotActive: "组织未激活"
NotChanged: "组织信息未改变"
DefaultOrgNotDeletable: "默认组织不应删除"
ZitadelOrgNotDeletable: "不得删除与Zitadel项目有关的组织"