feat(oauth/oidc): move token exchange from beta to GA (#11475)

# Which Problems Are Solved

This PR marks the OAuth2 Token Exchange as general available (GA).

# How the Problems Are Solved

- API:
- deprecated the feature toggle (to prevent breaking changes) in v2beta
and v2 API
- removed all related event logic and updated the projection interation
  - removed the toggle usage for token exchange
  - removed related translations
- Management Console:
  - removed the feature toggle and its translations
- Docs:
  - removed all beta labels and feature toggle notes

# Additional Changes

- removed unused `Errors.WebKey.FeatureDisabled` translations

# Additional Context

- closes #11114

---------

Co-authored-by: Marco A. <[email protected]>
This commit is contained in:
Livio Spring
2026-02-02 09:47:56 +00:00
committed by GitHub
co-authored by Marco A.
parent 2700286ae7
commit 09cf7cf0ae
80 changed files with 104 additions and 319 deletions
@@ -106,7 +106,6 @@ no additional parameters required
#### Response modes
ZITADEL supports the following `response_mode` values. When no response mode is requested, the response mode is chosen based on the configured Response Type of the application.
ZITADEL supports the following `response_mode` values. When no response mode is requested, the response mode is chosen based on the configured Response Type of the application.
As per [OpenID Connect Core 1.0, Section 3.1.2.1](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest):
@@ -391,10 +390,6 @@ curl --request POST \
The Token Exchange grant implements [RFC 8693, OAuth 2.0 Token Exchange](https://www.rfc-editor.org/rfc/rfc8693) and can be used to exchange tokens to a different scope, audience or subject. Changing the subject of an authenticated token is called impersonation or delegation. ZITADEL also provides a [token exchange guide](/guides/integrate/token-exchange) with more details on using the Token Exchange Grant.
<Callout>
Token Exchange is currently an experimental [beta](https://help.zitadel.com/zitadel-software-release-cycle#beta) feature. Be sure to enable it on the [feature API](/guides/integrate/token-exchange#feature-api) before using it.
</Callout>
#### Request parameters
<TokenExchangeRequest components={props.components} />
@@ -1,6 +1,6 @@
---
title: Impersonation and delegation using Token Exchange
sidebar_label: Token Exchange [Beta]
sidebar_label: Token Exchange
---
import TokenExchangeTypes from "../../apis/openidoauth/_token_exchange_types.mdx";
@@ -9,12 +9,6 @@ import TokenExchangeResponse from "../../apis/openidoauth/_token_exchange_respon
The Token Exchange grant implements [RFC 8693, OAuth 2.0 Token Exchange](https://www.rfc-editor.org/rfc/rfc8693) and can be used to exchange tokens to a different scope, audience or subject. Changing the subject of an authenticated token is called impersonation or delegation. This guide will explain how token exchange is implemented inside ZITADEL and gives some usage examples.
<Callout type="info">
Token Exchange is currently an [experimental beta](https://help.zitadel.com/zitadel-software-release-cycle#beta) feature. Be sure to enable it on the [feature API](#feature-api) before using it.
Test the feature and add improvement or bug reports directly to the [github repository](https://github.com/zitadel/zitadel) or let us know your general feedback in the [discord thread](https://discord.com/channels/927474939156643850/1333448892083208262)!
</Callout>
In this guide we assume that the application performing the token exchange is already in possession of tokens. You should already have a good understanding on the following topics before starting with this guide:
- Integrate your app with the [OIDC flow](/guides/integrate/login/oidc/login-users) to obtain tokens
@@ -184,22 +178,6 @@ First we will cover "simple" Token Exchange which only involves exchanging the `
These preparation steps are needed for all Token Exchange interaction, including impersonation.
#### Feature API
As Token Exchange is still a beta feature, the feature needs to be enabled for your instance by an `IAM_OWNER` first:
```bash
curl -L -X PUT 'https://${CUSTOM_DOMAIN}/v2/features/instance' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <IAM_OWNER_TOKEN>' \
--data-raw '{
"oidcTokenExchange": true
}'
```
If you are self-hosting, you can also enable the feature for the complete system (all instances) using the [set system level features](/reference/api/feature/zitadel.feature.v2.FeatureService.SetSystemFeatures) endpoint.
#### Application
Next we need to select an application that is allowed to perform Token Exchange. As with the other grant types, we need to enable the `urn:ietf:params:oauth:grant-type:token-exchange` grant type.
@@ -33,7 +33,6 @@ const FEATURE_KEYS = [
// 'improvedPerformance',
'loginDefaultOrg',
'oidcSingleV1SessionTermination',
'oidcTokenExchange',
'permissionCheckV2',
'userSchema',
'enableRelationalTables',
-2
View File
@@ -1631,8 +1631,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "تسجيل الدخول للمنظمة الافتراضية",
"LOGINDEFAULTORG_DESCRIPTION": "ستستخدم واجهة تسجيل الدخول إعدادات المنظمة الافتراضية (وليس من المثيل) إذا لم يتم تعيين سياق منظمة",
"OIDCTOKENEXCHANGE": "تبادل رموز OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "تمكين نوع المنح التجريبي urn:ietf:params:oauth:grant-type:token-exchange لنقطة نهاية رمز OIDC. يمكن استخدام تبادل الرموز لطلب رموز بنطاق أقل أو انتحال شخصية مستخدمين آخرين. انظر سياسة الأمان للسماح بالانتحال على مثيل.",
"USERSCHEMA": "مخطط المستخدم",
"USERSCHEMA_DESCRIPTION": "تسمح مخططات المستخدم بإدارة مخططات بيانات المستخدم. إذا تم تمكين العلامة، فستتمكن من استخدام API الجديد وميزاته.",
"ACTIONS": "الإجراءات",
-2
View File
@@ -1637,8 +1637,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Организация по подразбиране за влизане",
"LOGINDEFAULTORG_DESCRIPTION": "Потребителският интерфейс за влизане ще използва настройките на организацията по подразбиране (а не на инстанцията), ако не е зададен контекст на организация.",
"OIDCTOKENEXCHANGE": "Обмяна на токени OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Активиране на експерименталния тип на дарение urn:ietf:params:oauth:grant-type:token-exchange за краен пункт на токен OIDC. Обменът на токени може да се използва за заявка на токени с по-малък обхват или за имперсонализиране на други потребители. Вижте политиката за сигурност, за да разрешите имперсонализацията на инстанция.",
"USERSCHEMA": "Потребителска схема",
"USERSCHEMA_DESCRIPTION": "Потребителските схеми позволяват управление на данните за схемите на потребителите. Ако е активиран флагът, ще можете да използвате новото API и неговите функции.",
"ACTIONS": "Действия",
-2
View File
@@ -1635,8 +1635,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Výchozí organizace pro přihlášení",
"LOGINDEFAULTORG_DESCRIPTION": "Přihlašovací rozhraní použije nastavení výchozí organizace (a ne z instance), pokud není nastaven žádný kontext organizace.",
"OIDCTOKENEXCHANGE": "Výměna tokenů OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Povolit experimentální typ udělení urn:ietf:params:oauth:grant-type:token-exchange pro bod tokenového bodu OIDC. Výměna tokenů lze použít k žádosti o tokeny s menším rozsahem nebo k impersonaci jiných uživatelů. Podívejte se na bezpečnostní politiku, abyste umožnili impersonaci na instanci.",
"USERSCHEMA": "Schéma uživatele",
"USERSCHEMA_DESCRIPTION": "Schémata uživatelů umožňují spravovat datová schémata uživatelů. Pokud je příznak povolen, budete moci používat nové API a jeho funkce.",
"ACTIONS": "Akce",
-2
View File
@@ -1635,8 +1635,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Standardorganisation für die Anmeldung",
"LOGINDEFAULTORG_DESCRIPTION": "Die Anmelde-Benutzeroberfläche verwendet die Einstellungen der Standardorganisation (und nicht von der Instanz), wenn kein Organisationskontext festgelegt ist.",
"OIDCTOKENEXCHANGE": "OIDC Token-Austausch",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Aktivieren Sie den experimentellen urn:ietf:params:oauth:grant-type:token-exchange-Grant-Typ für den OIDC-Token-Endpunkt. Der Token-Austausch kann verwendet werden, um Token mit einem geringeren Umfang anzufordern oder andere Benutzer zu impersonieren. Siehe die Sicherheitsrichtlinie, um die Impersonation auf einer Instanz zu erlauben.",
"USERSCHEMA": "Benutzerschema",
"USERSCHEMA_DESCRIPTION": "Benutzerschemata ermöglichen das Verwalten von Datenschemata von Benutzern. Wenn die Flagge aktiviert ist, können Sie die neue API und ihre Funktionen verwenden.",
"ACTIONS": "Aktionen",
-2
View File
@@ -1639,8 +1639,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Login Default Org",
"LOGINDEFAULTORG_DESCRIPTION": "The login UI will use the settings of the default org (and not from the instance) if no organization context is set",
"OIDCTOKENEXCHANGE": "OIDC Token Exchange",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Enable the experimental urn:ietf:params:oauth:grant-type:token-exchange grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.",
"USERSCHEMA": "User Schema",
"USERSCHEMA_DESCRIPTION": "User Schemas allow to manage data schemas of user. If the flag is enabled, you'll be able to use the new API and its features.",
"ACTIONS": "Actions",
-2
View File
@@ -1636,8 +1636,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Organización predeterminada de inicio de sesión",
"LOGINDEFAULTORG_DESCRIPTION": "La interfaz de inicio de sesión utilizará la configuración de la organización predeterminada (y no de la instancia) si no se establece ningún contexto de organización.",
"OIDCTOKENEXCHANGE": "Intercambio de tokens OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Habilita el tipo de concesión experimental urn:ietf:params:oauth:grant-type:token-exchange para el punto de extremo de token OIDC. El intercambio de tokens se puede utilizar para solicitar tokens con un alcance menor o suplantar a otros usuarios. Consulta la política de seguridad para permitir la suplantación en una instancia.",
"USERSCHEMA": "Esquema de usuario",
"USERSCHEMA_DESCRIPTION": "Los esquemas de usuario permiten gestionar los esquemas de datos de los usuarios. Si se activa la bandera, podrás utilizar la nueva API y sus funciones.",
"ACTIONS": "Acciones",
-2
View File
@@ -1635,8 +1635,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Organisation par défaut de connexion",
"LOGINDEFAULTORG_DESCRIPTION": "L'interface de connexion utilisera les paramètres de l'organisation par défaut (et non de l'instance) si aucun contexte d'organisation n'est défini.",
"OIDCTOKENEXCHANGE": "Échange de jetons OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Activez le type d'octroi expérimental urn:ietf:params:oauth:grant-type:token-exchange pour le point de terminaison de jeton OIDC. L'échange de jetons peut être utilisé pour demander des jetons avec une portée moindre ou pour usurper d'autres utilisateurs. Consultez la politique de sécurité pour autoriser l'usurpation sur une instance.",
"USERSCHEMA": "Schéma utilisateur",
"USERSCHEMA_DESCRIPTION": "Les schémas utilisateur permettent de gérer les schémas de données des utilisateurs. Si le drapeau est activé, vous pourrez utiliser la nouvelle API et ses fonctionnalités.",
"ACTIONS": "Actions",
-2
View File
@@ -1633,8 +1633,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Alapértelmezett Org bejelentkezés",
"LOGINDEFAULTORG_DESCRIPTION": "A bejelentkezési felület az alapértelmezett org beállításait fogja használni (és nem az instance-tól), ha nincs megadva szervezeti kontextus",
"OIDCTOKENEXCHANGE": "OIDC Token Exchange",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Engedélyezd a kísérleti urn:ietf:params:oauth:grant-type:token-exchange támogatását az OIDC token végpont számára. A token csere használható kisebb hatókörű tokenek kérésére vagy más felhasználók megszemélyesítésére. Tekintsd meg a biztonsági irányelvet az impersonáció engedélyezéséhez egy példányon.",
"USERSCHEMA": "Felhasználói Séma",
"USERSCHEMA_DESCRIPTION": "A Felhasználói Sémák lehetővé teszik a felhasználói adat sémák kezelését. Ha az opció engedélyezve van, használhatod az új API-t és annak funkcióit.",
"ACTIONS": "Műveletek",
-2
View File
@@ -1635,8 +1635,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Masuk Organisasi Default",
"LOGINDEFAULTORG_DESCRIPTION": "UI login akan menggunakan pengaturan organisasi default (dan bukan dari instance) jika tidak ada konteks organisasi yang ditetapkan",
"OIDCTOKENEXCHANGE": "Pertukaran Token OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Aktifkan jenis pemberian urn:ietf:params:oauth:grant-type:token-exchange eksperimental untuk titik akhir token OIDC. Pertukaran token dapat digunakan untuk meminta token dengan cakupan yang lebih kecil atau menyamar sebagai pengguna lain. Lihat kebijakan keamanan untuk mengizinkan peniruan identitas pada sebuah instans.",
"USERSCHEMA": "Skema Pengguna",
"USERSCHEMA_DESCRIPTION": "Skema Pengguna memungkinkan untuk mengelola skema data pengguna. Jika tanda ini diaktifkan, Anda akan dapat menggunakan API baru dan fitur-fiturnya.",
"ACTIONS": "Tindakan",
-2
View File
@@ -1635,8 +1635,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Organizzazione predefinita per l'accesso",
"LOGINDEFAULTORG_DESCRIPTION": "L'interfaccia di accesso utilizzerà le impostazioni dell'organizzazione predefinita (e non dell'istanza) se non è impostato alcun contesto organizzativo.",
"OIDCTOKENEXCHANGE": "Scambio token OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Abilita il tipo di concessione sperimentale urn:ietf:params:oauth:grant-type:token-exchange per il punto finale del token OIDC. Lo scambio di token può essere utilizzato per richiedere token con uno scopo inferiore o impersonare altri utenti. Consultare la policy di sicurezza per consentire l'impersonificazione su un'istanza.",
"USERSCHEMA": "Schema utente",
"USERSCHEMA_DESCRIPTION": "Gli schemi utente consentono di gestire gli schemi di dati degli utenti. Se la flag è attivata, sarà possibile utilizzare la nuova API e le sue funzionalità.",
"ACTIONS": "Azioni",
-2
View File
@@ -1635,8 +1635,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "ログイン時の既定組織",
"LOGINDEFAULTORG_DESCRIPTION": "組織コンテキストが設定されていない場合、ログイン UI は既定の組織の設定を使用します (インスタンスの設定ではなく)",
"OIDCTOKENEXCHANGE": "OIDC トークン交換",
"OIDCTOKENEXCHANGE_DESCRIPTION": "OIDC トークン エンドポイント用に実験的な urn:ietf:params:oauth:grant-type:token-exchange 付与タイプを有効にします。トークン交換は、より少ないスコープを持つトークンを要求するか、他のユーザーになりすますために使用できます。インスタンスでのなりすましを許可するには、セキュリティポリシーを参照してください。",
"USERSCHEMA": "ユーザー スキーマ",
"USERSCHEMA_DESCRIPTION": "ユーザー スキーマを使用すると、ユーザーのデータスキーマを管理できます。フラグが有効になっている場合、新しい APIとその機能を使用できます。",
"ACTIONS": "アクション",
-2
View File
@@ -1635,8 +1635,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "로그인 기본 조직",
"LOGINDEFAULTORG_DESCRIPTION": "조직 컨텍스트가 설정되지 않은 경우 로그인 UI가 기본 조직의 설정을 사용합니다 (인스턴스에서 설정되지 않음).",
"OIDCTOKENEXCHANGE": "OIDC 토큰 교환",
"OIDCTOKENEXCHANGE_DESCRIPTION": "OIDC 토큰 엔드포인트의 실험적 urn:ietf:params:oauth:grant-type:token-exchange 허용을 활성화합니다. 토큰 교환을 통해 범위가 좁은 토큰을 요청하거나 다른 사용자를 가장할 수 있습니다. 인스턴스에서 가장을 허용하는 보안 정책을 확인하세요.",
"USERSCHEMA": "사용자 스키마",
"USERSCHEMA_DESCRIPTION": "사용자 스키마를 통해 사용자의 데이터 스키마를 관리할 수 있습니다. 플래그가 활성화되면 새 API 및 기능을 사용할 수 있습니다.",
"ACTIONS": "액션",
-2
View File
@@ -1636,8 +1636,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Најава Стандардна организација",
"LOGINDEFAULTORG_DESCRIPTION": "Интерфејсот за најавување ќе ги користи поставките на стандардната организација (а не од примерот) ако не е поставен контекст на организацијата",
"OIDCTOKENEXCHANGE": "Размена на токени OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Овозможете го експерименталниот тип на грант urn:ietf:params:oauth:grant-type:token-exchange за крајната точка на токенот OIDC. Размената на токени може да се користи за барање токени со помал опсег или имитирање на други корисници. Погледнете ја безбедносната политика за да дозволите имитирање на пример.",
"USERSCHEMA": "Корисничка шема",
"USERSCHEMA_DESCRIPTION": "Корисничките шеми овозможуваат управување со податоци шеми на корисникот. Ако знамето е овозможено, ќе можете да го користите новиот API и неговите функции.",
"ACTIONS": "Акции",
-2
View File
@@ -1635,8 +1635,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Standaard inlogorganisatie",
"LOGINDEFAULTORG_DESCRIPTION": "Als er geen organisatiecontext is ingesteld, gebruikt de inlog-UI de instellingen van de standaardorganisatie (en niet van de instantie)",
"OIDCTOKENEXCHANGE": "OIDC-tokenuitwisseling",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Schakel het experimentele type verlening urn:ietf:params:oauth:grant-type:token-exchange in voor het OIDC-tokenendpoint. Tokenuitwisseling kan worden gebruikt om tokens met een kleinere scope op te vragen of om zich voor te doen als andere gebruikers. Raadpleeg het beveiligingsbeleid om impersonation op een instantie toe te staan.",
"USERSCHEMA": "Gebruikerschema",
"USERSCHEMA_DESCRIPTION": "Met gebruikerschema's kunt u de dataschema's van gebruikers beheren. Als de vlag is ingeschakeld, kunt u de nieuwe API en zijn functies gebruiken.",
"ACTIONS": "Acties",
-2
View File
@@ -1634,8 +1634,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Domyślna Organizacja Logowania",
"LOGINDEFAULTORG_DESCRIPTION": "Jeśli nie ustawiono kontekstu organizacji, interfejs logowania będzie używać ustawień domyślnej organizacji (a nie instancji)",
"OIDCTOKENEXCHANGE": "Wymiana Tokenów OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Włącz eksperymentalny typ grantu urn:ietf:params:oauth:grant-type:token-exchange dla punktu końcowego tokena OIDC. Wymiana tokenów może być używana do żądania tokenów o mniejszym zakresie lub podszywania się za innych użytkowników. Aby zezwolić na podszywanie się na instancji, zapoznaj się z polityką bezpieczeństwa.",
"USERSCHEMA": "Schemat Użytkownika",
"USERSCHEMA_DESCRIPTION": "Schematy użytkowników umożliwiają zarządzanie schematami danych użytkowników. Jeśli flaga jest włączona, będziesz mógł korzystać z nowego interfejsu API i jego funkcji.",
"ACTIONS": "Akcje",
-2
View File
@@ -1636,8 +1636,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Organização Padrão de Login",
"LOGINDEFAULTORG_DESCRIPTION": "A interface de login utilizará as configurações da organização padrão (e não da instância) se nenhum contexto de organização estiver definido",
"OIDCTOKENEXCHANGE": "Troca de Token OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Habilita o tipo de concessão experimental urn:ietf:params:oauth:grant-type:token-exchange para o endpoint de token OIDC. A troca de token pode ser usada para solicitar tokens com escopo menor ou personificar outros usuários. Consulte a política de segurança para permitir a personificação em uma instância.",
"USERSCHEMA": "Esquema de Usuário",
"USERSCHEMAS_DESCRIPTION": "Esquemas de Usuário permitem gerenciar esquemas de dados do usuário. Se o sinalizador estiver ativado, você poderá usar a nova API e seus recursos.",
"ACTIONS": "Ações",
-2
View File
@@ -1633,8 +1633,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Organizație implicită de conectare",
"LOGINDEFAULTORG_DESCRIPTION": "UI-ul de conectare va utiliza setările organizației implicite (și nu din instanță) dacă nu este setat niciun context de organizație",
"OIDCTOKENEXCHANGE": "Schimb de token OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Activați tipul de grant experimental urn:ietf:params:oauth:grant-type:token-exchange pentru endpointul token OIDC. Schimbul de tokenuri poate fi utilizat pentru a solicita tokenuri cu o rază de acțiune mai mică sau pentru a impersona alți utilizatori. Consultați politica de securitate pentru a permite impersonarea pe o instanță.",
"USERSCHEMA": "Schema de utilizator",
"USERSCHEMA_DESCRIPTION": "Schemele de utilizator permit gestionarea schemelor de date ale utilizatorului. Dacă indicatorul este activat, veți putea utiliza noul API și caracteristicile sale.",
"ACTIONS": "Acțiuni",
-2
View File
@@ -1687,8 +1687,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Организация по умолчанию для входа",
"LOGINDEFAULTORG_DESCRIPTION": "Если контекст организации не установлен, пользовательский интерфейс входа будет использовать настройки организации по умолчанию (а не экземпляра)",
"OIDCTOKENEXCHANGE": "Обмен токенами OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Включите экспериментальный тип гранта urn:ietf:params:oauth:grant-type:token-exchange для конечной точки токена OIDC. Обмен токенами можно использовать для запроса токенов с меньшей областью действия или для impersonation (выдачи себя за) других пользователей. Информацию о разрешении impersonation на экземпляре см. в политике безопасности.",
"USERSCHEMA": "Схема пользователя",
"USERSCHEMA_DESCRIPTION": "Схемы пользователей позволяют управлять схемами данных пользователей. Если флаг включен, вы сможете использовать новый API и его функции.",
"ACTIONS": "Действия",
-2
View File
@@ -1639,8 +1639,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Standardorganisation för inloggning",
"LOGINDEFAULTORG_DESCRIPTION": "Inloggningsgränssnittet kommer att använda inställningarna för standardorganisationen (och inte från instansen) om ingen organisationskontext är inställd",
"OIDCTOKENEXCHANGE": "OIDC Token Exchange",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Aktivera den experimentella urn:ietf:params:oauth:grant-type:token-exchange grant-typen för OIDC-tokenändpunkten. Tokenutbyte kan användas för att begära tokens med en mindre omfattning eller impersonera andra användare. Se säkerhetspolicyn för att tillåta impersonation på en instans.",
"USERSCHEMA": "Användarschema",
"USERSCHEMA_DESCRIPTION": "Användarscheman tillåter att hantera datascheman för användare. Om flaggan är aktiverad kommer du att kunna använda det nya API:et och dess funktioner.",
"ACTIONS": "Åtgärder",
-2
View File
@@ -1638,8 +1638,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Giriş Varsayılan Org",
"LOGINDEFAULTORG_DESCRIPTION": "Organizasyon bağlamı ayarlanmadıysa, giriş UI'ı varsayılan org'un ayarlarını (örnektekini değil) kullanacaktır",
"OIDCTOKENEXCHANGE": "OIDC Token Exchange",
"OIDCTOKENEXCHANGE_DESCRIPTION": "OIDC token uç noktası için deneysel urn:ietf:params:oauth:grant-type:token-exchange grant türünü etkinleştirin. Token değişimi, daha az kapsamlı token'lar talep etmek veya diğer kullanıcıların kimliğine bürünmek için kullanılabilir. Bir örnekte kimliğe bürünmeye izin vermek için güvenlik politikasına bakın.",
"USERSCHEMA": "Kullanıcı Şeması",
"USERSCHEMA_DESCRIPTION": "Kullanıcı Şemaları, kullanıcının veri şemalarını yönetmeye izin verir. Bayrak etkinleştirilirse, yeni API'yi ve özelliklerini kullanabileceksiniz.",
"ACTIONS": "Eylemler",
-2
View File
@@ -1639,8 +1639,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "Організація входу за замовчуванням",
"LOGINDEFAULTORG_DESCRIPTION": "Інтерфейс входу використовуватиме налаштування організації за замовчуванням (а не з екземпляра), якщо контекст організації не встановлено",
"OIDCTOKENEXCHANGE": "Обмін токенів OIDC",
"OIDCTOKENEXCHANGE_DESCRIPTION": "Увімкнути експериментальний тип надання urn:ietf:params:oauth:grant-type:token-exchange для кінцевої точки токенів OIDC. Обмін токенів може використовуватися для запиту токенів з меншою областю дії або імітації інших користувачів. Див. політику безпеки для дозволу імітації в екземплярі.",
"USERSCHEMA": "Схема користувача",
"USERSCHEMA_DESCRIPTION": "Схеми користувачів дозволяють керувати схемами даних користувача. Якщо прапорець увімкнено, ви зможете використовувати новий API та його можливості.",
"ACTIONS": "Дії",
-2
View File
@@ -1638,8 +1638,6 @@
"FEATURES": {
"LOGINDEFAULTORG": "登录默认组织",
"LOGINDEFAULTORG_DESCRIPTION": "如果没有设置组织上下文,登录界面将使用默认组织的设置(而不是实例的设置)",
"OIDCTOKENEXCHANGE": "OIDC 令牌交换",
"OIDCTOKENEXCHANGE_DESCRIPTION": "启用 OIDC 令牌端点的实验性 urn:ietf:params:oauth:grant-type:token-exchange 授权类型。令牌交换可用于请求具有较少范围的令牌或模拟其他用户。请参阅安全策略以允许在实例上模拟。",
"USERSCHEMA": "用户架构",
"USERSCHEMA_DESCRIPTION": "用户架构允许管理用户的数据架构。如果启用此标志,您将可以使用新的 API 及其功能。",
"ACTIONS": "操作",
+8 -4
View File
@@ -20,7 +20,6 @@ func systemFeaturesToCommand(req *feature_pb.SetSystemFeaturesRequest) (*command
return &command.SystemFeatures{
LoginDefaultOrg: req.LoginDefaultOrg,
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
OIDCSingleV1SessionTermination: req.OidcSingleV1SessionTermination,
EnableBackChannelLogout: req.EnableBackChannelLogout,
@@ -35,7 +34,10 @@ func systemFeaturesToPb(f *query.SystemFeatures) *feature_pb.GetSystemFeaturesRe
Details: object.DomainToDetailsPb(f.Details),
LoginDefaultOrg: featureSourceToFlagPb(&f.LoginDefaultOrg),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
OidcTokenExchange: &feature_pb.FeatureFlag{ // TODO: remove in next major version
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
OidcSingleV1SessionTermination: featureSourceToFlagPb(&f.OIDCSingleV1SessionTermination),
EnableBackChannelLogout: featureSourceToFlagPb(&f.EnableBackChannelLogout),
@@ -53,7 +55,6 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) (*com
return &command.InstanceFeatures{
LoginDefaultOrg: req.LoginDefaultOrg,
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
DebugOIDCParentError: req.DebugOidcParentError,
OIDCSingleV1SessionTermination: req.OidcSingleV1SessionTermination,
@@ -70,7 +71,10 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
Details: object.DomainToDetailsPb(f.Details),
LoginDefaultOrg: featureSourceToFlagPb(&f.LoginDefaultOrg),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
OidcTokenExchange: &feature_pb.FeatureFlag{ // TODO: remove in next major version
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
DebugOidcParentError: featureSourceToFlagPb(&f.DebugOIDCParentError),
OidcSingleV1SessionTermination: featureSourceToFlagPb(&f.OIDCSingleV1SessionTermination),
+2 -14
View File
@@ -23,7 +23,6 @@ func Test_systemFeaturesToCommand(t *testing.T) {
arg := &feature_pb.SetSystemFeaturesRequest{
LoginDefaultOrg: gu.Ptr(true),
UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
OidcSingleV1SessionTermination: gu.Ptr(true),
LoginV2: &feature_pb.LoginV2{
@@ -37,7 +36,6 @@ func Test_systemFeaturesToCommand(t *testing.T) {
want := &command.SystemFeatures{
LoginDefaultOrg: gu.Ptr(true),
UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
OIDCSingleV1SessionTermination: gu.Ptr(true),
LoginV2: &feature.LoginV2{
@@ -75,10 +73,6 @@ func Test_systemFeaturesToPb(t *testing.T) {
Level: feature.LevelSystem,
Value: true,
},
TokenExchange: query.FeatureSource[bool]{
Level: feature.LevelSystem,
Value: false,
},
ImprovedPerformance: query.FeatureSource[[]feature.ImprovedPerformanceType]{
Level: feature.LevelSystem,
Value: []feature.ImprovedPerformanceType{feature.ImprovedPerformanceTypeOrgDomainVerified},
@@ -122,7 +116,7 @@ func Test_systemFeaturesToPb(t *testing.T) {
Source: feature_pb.Source_SOURCE_SYSTEM,
},
OidcTokenExchange: &feature_pb.FeatureFlag{
Enabled: false,
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
ImprovedPerformance: &feature_pb.ImprovedPerformanceFeatureFlag{
@@ -165,7 +159,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
arg := &feature_pb.SetInstanceFeaturesRequest{
LoginDefaultOrg: gu.Ptr(true),
UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
DebugOidcParentError: gu.Ptr(true),
OidcSingleV1SessionTermination: gu.Ptr(true),
@@ -181,7 +174,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
want := &command.InstanceFeatures{
LoginDefaultOrg: gu.Ptr(true),
UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
DebugOIDCParentError: gu.Ptr(true),
OIDCSingleV1SessionTermination: gu.Ptr(true),
@@ -220,10 +212,6 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Level: feature.LevelInstance,
Value: true,
},
TokenExchange: query.FeatureSource[bool]{
Level: feature.LevelSystem,
Value: false,
},
ImprovedPerformance: query.FeatureSource[[]feature.ImprovedPerformanceType]{
Level: feature.LevelSystem,
Value: []feature.ImprovedPerformanceType{feature.ImprovedPerformanceTypeOrgDomainVerified},
@@ -271,7 +259,7 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Source: feature_pb.Source_SOURCE_INSTANCE,
},
OidcTokenExchange: &feature_pb.FeatureFlag{
Enabled: false,
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
ImprovedPerformance: &feature_pb.ImprovedPerformanceFeatureFlag{
@@ -12,7 +12,6 @@ func systemFeaturesToCommand(req *feature_pb.SetSystemFeaturesRequest) *command.
return &command.SystemFeatures{
LoginDefaultOrg: req.LoginDefaultOrg,
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
OIDCSingleV1SessionTermination: req.OidcSingleV1SessionTermination,
}
@@ -23,7 +22,10 @@ func systemFeaturesToPb(f *query.SystemFeatures) *feature_pb.GetSystemFeaturesRe
Details: object.DomainToDetailsPb(f.Details),
LoginDefaultOrg: featureSourceToFlagPb(&f.LoginDefaultOrg),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
OidcTokenExchange: &feature_pb.FeatureFlag{ // TODO: remove in next major version
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
OidcSingleV1SessionTermination: featureSourceToFlagPb(&f.OIDCSingleV1SessionTermination),
}
@@ -33,7 +35,6 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm
return &command.InstanceFeatures{
LoginDefaultOrg: req.LoginDefaultOrg,
UserSchema: req.UserSchema,
TokenExchange: req.OidcTokenExchange,
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
DebugOIDCParentError: req.DebugOidcParentError,
OIDCSingleV1SessionTermination: req.OidcSingleV1SessionTermination,
@@ -45,7 +46,10 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
Details: object.DomainToDetailsPb(f.Details),
LoginDefaultOrg: featureSourceToFlagPb(&f.LoginDefaultOrg),
UserSchema: featureSourceToFlagPb(&f.UserSchema),
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
OidcTokenExchange: &feature_pb.FeatureFlag{ // TODO: remove in next major version
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
DebugOidcParentError: featureSourceToFlagPb(&f.DebugOIDCParentError),
OidcSingleV1SessionTermination: featureSourceToFlagPb(&f.OIDCSingleV1SessionTermination),
@@ -20,14 +20,12 @@ func Test_systemFeaturesToCommand(t *testing.T) {
arg := &feature_pb.SetSystemFeaturesRequest{
LoginDefaultOrg: gu.Ptr(true),
UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
OidcSingleV1SessionTermination: gu.Ptr(true),
}
want := &command.SystemFeatures{
LoginDefaultOrg: gu.Ptr(true),
UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
OIDCSingleV1SessionTermination: gu.Ptr(true),
}
@@ -50,10 +48,6 @@ func Test_systemFeaturesToPb(t *testing.T) {
Level: feature.LevelSystem,
Value: true,
},
TokenExchange: query.FeatureSource[bool]{
Level: feature.LevelSystem,
Value: false,
},
ImprovedPerformance: query.FeatureSource[[]feature.ImprovedPerformanceType]{
Level: feature.LevelSystem,
Value: []feature.ImprovedPerformanceType{feature.ImprovedPerformanceTypeOrgDomainVerified},
@@ -78,7 +72,7 @@ func Test_systemFeaturesToPb(t *testing.T) {
Source: feature_pb.Source_SOURCE_SYSTEM,
},
OidcTokenExchange: &feature_pb.FeatureFlag{
Enabled: false,
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
ImprovedPerformance: &feature_pb.ImprovedPerformanceFeatureFlag{
@@ -98,14 +92,12 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
arg := &feature_pb.SetInstanceFeaturesRequest{
LoginDefaultOrg: gu.Ptr(true),
UserSchema: gu.Ptr(true),
OidcTokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
OidcSingleV1SessionTermination: gu.Ptr(true),
}
want := &command.InstanceFeatures{
LoginDefaultOrg: gu.Ptr(true),
UserSchema: gu.Ptr(true),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: nil,
OIDCSingleV1SessionTermination: gu.Ptr(true),
}
@@ -128,10 +120,6 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Level: feature.LevelInstance,
Value: true,
},
TokenExchange: query.FeatureSource[bool]{
Level: feature.LevelSystem,
Value: false,
},
ImprovedPerformance: query.FeatureSource[[]feature.ImprovedPerformanceType]{
Level: feature.LevelSystem,
Value: []feature.ImprovedPerformanceType{feature.ImprovedPerformanceTypeOrgDomainVerified},
@@ -156,7 +144,7 @@ func Test_instanceFeaturesToPb(t *testing.T) {
Source: feature_pb.Source_SOURCE_INSTANCE,
},
OidcTokenExchange: &feature_pb.FeatureFlag{
Enabled: false,
Enabled: true,
Source: feature_pb.Source_SOURCE_SYSTEM,
},
ImprovedPerformance: &feature_pb.ImprovedPerformanceFeatureFlag{
@@ -17,41 +17,12 @@ import (
"github.com/zitadel/oidc/v3/pkg/oidc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
oidc_api "github.com/zitadel/zitadel/internal/api/oidc"
"github.com/zitadel/zitadel/internal/integration"
"github.com/zitadel/zitadel/pkg/grpc/admin"
"github.com/zitadel/zitadel/pkg/grpc/feature/v2"
)
func setTokenExchangeFeature(t *testing.T, instance *integration.Instance, value bool) {
iamCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
_, err := instance.Client.FeatureV2.SetInstanceFeatures(iamCTX, &feature.SetInstanceFeaturesRequest{
OidcTokenExchange: proto.Bool(value),
})
require.NoError(t, err)
retryDuration := time.Minute
if ctxDeadline, ok := iamCTX.Deadline(); ok {
retryDuration = time.Until(ctxDeadline)
}
require.EventuallyWithT(t,
func(ttt *assert.CollectT) {
f, err := instance.Client.FeatureV2.GetInstanceFeatures(iamCTX, &feature.GetInstanceFeaturesRequest{
Inheritance: true,
})
assert.NoError(ttt, err)
if f.OidcTokenExchange.GetEnabled() {
return
}
},
retryDuration,
time.Second,
"timed out waiting for ensuring instance feature")
time.Sleep(time.Second)
}
func setImpersonationPolicy(t *testing.T, instance *integration.Instance, value bool) {
iamCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
@@ -150,11 +121,7 @@ func TestServer_TokenExchange(t *testing.T) {
_, orgImpersonatorPAT := createMachineUserPATWithMembership(ctx, t, instance, "ORG_ADMIN_IMPERSONATOR")
serviceUserID, noPermPAT := createMachineUserPATWithMembership(ctx, t, instance)
// test that feature is disabled per default
teResp, err := tokenexchange.ExchangeToken(ctx, exchanger, noPermPAT, oidc.AccessTokenType, "", "", nil, nil, nil, oidc.AccessTokenType)
require.Error(t, err)
setTokenExchangeFeature(t, instance, true)
teResp, err = tokenexchange.ExchangeToken(ctx, exchanger, noPermPAT, oidc.AccessTokenType, "", "", nil, nil, nil, oidc.AccessTokenType)
require.NoError(t, err)
patScopes := oidc.SpaceDelimitedArray{"openid", "profile", "urn:zitadel:iam:user:metadata", "urn:zitadel:iam:user:resourceowner"}
@@ -361,7 +328,6 @@ func TestServer_TokenExchangeImpersonation(t *testing.T) {
userResp := instance.CreateHumanUser(ctx)
// exchange some tokens for later use
setTokenExchangeFeature(t, instance, true)
setImpersonationPolicy(t, instance, true)
client, keyData, err := instance.CreateOIDCTokenExchangeClient(ctx, t)
@@ -593,7 +559,6 @@ func TestImpersonation_API_Call(t *testing.T) {
resourceServer, err := instance.CreateResourceServerJWTProfile(ctx, keyData)
require.NoError(t, err)
setTokenExchangeFeature(t, instance, true)
setImpersonationPolicy(t, instance, true)
iamUserID, iamImpersonatorPAT := createMachineUserPATWithMembership(ctx, t, instance, "IAM_ADMIN_IMPERSONATOR")
-3
View File
@@ -41,9 +41,6 @@ func (s *Server) tokenExchange(ctx context.Context, r *op.ClientRequest[oidc.Tok
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
if !authz.GetFeatures(ctx).TokenExchange {
return nil, zerrors.ThrowPreconditionFailed(nil, "OIDC-oan4I", "Errors.TokenExchange.FeatureDisabled")
}
if len(r.Data.Resource) > 0 {
return nil, oidc.ErrInvalidTarget().WithDescription("resource parameter not supported")
}
-2
View File
@@ -133,7 +133,6 @@ type InstanceSetup struct {
type InstanceSetupFeatures struct {
LoginDefaultOrg *bool
UserSchema *bool
TokenExchange *bool
ImprovedPerformance []feature.ImprovedPerformanceType
DebugOIDCParentError *bool
OIDCSingleV1SessionTermination *bool
@@ -167,7 +166,6 @@ func (f *InstanceSetupFeatures) ToInstanceFeatures() (_ *InstanceFeatures, err e
return &InstanceFeatures{
LoginDefaultOrg: f.LoginDefaultOrg,
UserSchema: f.UserSchema,
TokenExchange: f.TokenExchange,
ImprovedPerformance: f.ImprovedPerformance,
DebugOIDCParentError: f.DebugOIDCParentError,
OIDCSingleV1SessionTermination: f.OIDCSingleV1SessionTermination,
-2
View File
@@ -15,7 +15,6 @@ import (
type InstanceFeatures struct {
LoginDefaultOrg *bool
UserSchema *bool
TokenExchange *bool
ImprovedPerformance []feature.ImprovedPerformanceType
DebugOIDCParentError *bool
OIDCSingleV1SessionTermination *bool
@@ -29,7 +28,6 @@ type InstanceFeatures struct {
func (m *InstanceFeatures) isEmpty() bool {
return m == nil || (m.LoginDefaultOrg == nil &&
m.UserSchema == nil &&
m.TokenExchange == nil &&
// nil check to allow unset improvements
m.ImprovedPerformance == nil &&
m.DebugOIDCParentError == nil &&
@@ -68,7 +68,6 @@ func (m *InstanceFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceResetEventType,
feature_v2.InstanceLoginDefaultOrgEventType,
feature_v2.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceImprovedPerformanceEventType,
feature_v2.InstanceDebugOIDCParentErrorEventType,
feature_v2.InstanceOIDCSingleV1SessionTerminationEventType,
@@ -92,9 +91,6 @@ func reduceInstanceFeature(features *InstanceFeatures, key feature.Key, value an
case feature.KeyLoginDefaultOrg:
v := value.(bool)
features.LoginDefaultOrg = &v
case feature.KeyTokenExchange:
v := value.(bool)
features.TokenExchange = &v
case feature.KeyUserSchema:
v := value.(bool)
features.UserSchema = &v
@@ -128,7 +124,6 @@ func (wm *InstanceFeaturesWriteModel) setCommands(ctx context.Context, f *Instan
aggregate := feature_v2.NewAggregate(wm.AggregateID, wm.ResourceOwner)
cmds := make([]eventstore.Command, 0, len(feature.KeyValues())-1)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.LoginDefaultOrg, f.LoginDefaultOrg, feature_v2.InstanceLoginDefaultOrgEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TokenExchange, f.TokenExchange, feature_v2.InstanceTokenExchangeEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.UserSchema, f.UserSchema, feature_v2.InstanceUserSchemaEventType)
cmds = appendFeatureSliceUpdate(ctx, cmds, aggregate, wm.ImprovedPerformance, f.ImprovedPerformance, feature_v2.InstanceImprovedPerformanceEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.DebugOIDCParentError, f.DebugOIDCParentError, feature_v2.InstanceDebugOIDCParentErrorEventType)
@@ -38,15 +38,6 @@ func Test_reduceInstanceFeature(t *testing.T) {
},
expected: &InstanceFeatures{LoginDefaultOrg: gu.Ptr(true)},
},
{
name: "token exchange",
args: args{
features: &InstanceFeatures{},
key: feature.KeyTokenExchange,
value: true,
},
expected: &InstanceFeatures{TokenExchange: gu.Ptr(true)},
},
{
name: "user schema",
args: args{
@@ -335,13 +335,6 @@ func TestInstanceFeatures_isEmpty(t *testing.T) {
},
want: false,
},
{
name: "TokenExchange set",
features: &InstanceFeatures{
TokenExchange: gu.Ptr(true),
},
want: false,
},
{
name: "ImprovedPerformance set",
features: &InstanceFeatures{
-4
View File
@@ -1776,7 +1776,6 @@ func TestInstanceSetupFeatures_ToInstanceFeatures(t *testing.T) {
type fields struct {
LoginDefaultOrg *bool
UserSchema *bool
TokenExchange *bool
ImprovedPerformance []feature.ImprovedPerformanceType
DebugOIDCParentError *bool
OIDCSingleV1SessionTermination *bool
@@ -1806,7 +1805,6 @@ func TestInstanceSetupFeatures_ToInstanceFeatures(t *testing.T) {
fields: fields{
LoginDefaultOrg: gu.Ptr(true),
UserSchema: gu.Ptr(false),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: []feature.ImprovedPerformanceType{feature.ImprovedPerformanceTypeOrgDomainVerified},
DebugOIDCParentError: gu.Ptr(true),
OIDCSingleV1SessionTermination: gu.Ptr(false),
@@ -1818,7 +1816,6 @@ func TestInstanceSetupFeatures_ToInstanceFeatures(t *testing.T) {
want: &InstanceFeatures{
LoginDefaultOrg: gu.Ptr(true),
UserSchema: gu.Ptr(false),
TokenExchange: gu.Ptr(true),
ImprovedPerformance: []feature.ImprovedPerformanceType{feature.ImprovedPerformanceTypeOrgDomainVerified},
DebugOIDCParentError: gu.Ptr(true),
OIDCSingleV1SessionTermination: gu.Ptr(false),
@@ -1875,7 +1872,6 @@ func TestInstanceSetupFeatures_ToInstanceFeatures(t *testing.T) {
f := &InstanceSetupFeatures{
LoginDefaultOrg: tc.fields.LoginDefaultOrg,
UserSchema: tc.fields.UserSchema,
TokenExchange: tc.fields.TokenExchange,
ImprovedPerformance: tc.fields.ImprovedPerformance,
DebugOIDCParentError: tc.fields.DebugOIDCParentError,
OIDCSingleV1SessionTermination: tc.fields.OIDCSingleV1SessionTermination,
-2
View File
@@ -11,7 +11,6 @@ import (
type SystemFeatures struct {
LoginDefaultOrg *bool
TokenExchange *bool
UserSchema *bool
ImprovedPerformance []feature.ImprovedPerformanceType
OIDCSingleV1SessionTermination *bool
@@ -24,7 +23,6 @@ type SystemFeatures struct {
func (m *SystemFeatures) isEmpty() bool {
return m == nil || (m.LoginDefaultOrg == nil &&
m.UserSchema == nil &&
m.TokenExchange == nil &&
// nil check to allow unset improvements
m.ImprovedPerformance == nil &&
m.OIDCSingleV1SessionTermination == nil &&
@@ -61,7 +61,6 @@ func (m *SystemFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemResetEventType,
feature_v2.SystemLoginDefaultOrgEventType,
feature_v2.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemImprovedPerformanceEventType,
feature_v2.SystemOIDCSingleV1SessionTerminationEventType,
feature_v2.SystemEnableBackChannelLogout,
@@ -86,9 +85,6 @@ func reduceSystemFeature(features *SystemFeatures, key feature.Key, value any) {
case feature.KeyUserSchema:
v := value.(bool)
features.UserSchema = &v
case feature.KeyTokenExchange:
v := value.(bool)
features.TokenExchange = &v
case feature.KeyImprovedPerformance:
features.ImprovedPerformance = value.([]feature.ImprovedPerformanceType)
case feature.KeyOIDCSingleV1SessionTermination:
@@ -113,7 +109,6 @@ func (wm *SystemFeaturesWriteModel) setCommands(ctx context.Context, f *SystemFe
cmds := make([]eventstore.Command, 0, len(feature.KeyValues())-1)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.LoginDefaultOrg, f.LoginDefaultOrg, feature_v2.SystemLoginDefaultOrgEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.UserSchema, f.UserSchema, feature_v2.SystemUserSchemaEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TokenExchange, f.TokenExchange, feature_v2.SystemTokenExchangeEventType)
cmds = appendFeatureSliceUpdate(ctx, cmds, aggregate, wm.ImprovedPerformance, f.ImprovedPerformance, feature_v2.SystemImprovedPerformanceEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.OIDCSingleV1SessionTermination, f.OIDCSingleV1SessionTermination, feature_v2.SystemOIDCSingleV1SessionTerminationEventType)
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.EnableBackChannelLogout, f.EnableBackChannelLogout, feature_v2.SystemEnableBackChannelLogout)
-1
View File
@@ -289,7 +289,6 @@ func TestSystemFeatures_isEmpty(t *testing.T) {
{name: "empty features", sysFeatures: &SystemFeatures{}, want: true},
{name: "LoginDefaultOrg set", sysFeatures: &SystemFeatures{LoginDefaultOrg: gu.Ptr(true)}, want: false},
{name: "UserSchema set", sysFeatures: &SystemFeatures{UserSchema: gu.Ptr(true)}, want: false},
{name: "TokenExchange set", sysFeatures: &SystemFeatures{TokenExchange: gu.Ptr(true)}, want: false},
{name: "ImprovedPerformance set", sysFeatures: &SystemFeatures{ImprovedPerformance: []feature.ImprovedPerformanceType{}}, want: false},
{name: "OIDCSingleV1SessionTermination set", sysFeatures: &SystemFeatures{OIDCSingleV1SessionTermination: gu.Ptr(true)}, want: false},
{name: "EnableBackChannelLogout set", sysFeatures: &SystemFeatures{EnableBackChannelLogout: gu.Ptr(true)}, want: false},
+1 -3
View File
@@ -9,12 +9,11 @@ import (
type Key int
const (
// Reserved: 2, 3, 6, 8, 11
// Reserved: 2, 3, 5, 6, 8, 11
KeyUnspecified Key = 0
KeyLoginDefaultOrg Key = 1
KeyUserSchema Key = 4
KeyTokenExchange Key = 5
KeyImprovedPerformance Key = 7
KeyDebugOIDCParentError Key = 9
KeyOIDCSingleV1SessionTermination Key = 10
@@ -41,7 +40,6 @@ const (
type Features struct {
LoginDefaultOrg bool `json:"login_default_org,omitempty"`
UserSchema bool `json:"user_schema,omitempty"`
TokenExchange bool `json:"token_exchange,omitempty"`
ImprovedPerformance []ImprovedPerformanceType `json:"improved_performance,omitempty"`
DebugOIDCParentError bool `json:"debug_oidc_parent_error,omitempty"`
OIDCSingleV1SessionTermination bool `json:"oidc_single_v1_session_termination,omitempty"`
+6 -11
View File
@@ -10,8 +10,8 @@ import (
const (
_KeyName_0 = "unspecifiedlogin_default_org"
_KeyLowerName_0 = "unspecifiedlogin_default_org"
_KeyName_1 = "user_schematoken_exchange"
_KeyLowerName_1 = "user_schematoken_exchange"
_KeyName_1 = "user_schema"
_KeyLowerName_1 = "user_schema"
_KeyName_2 = "improved_performance"
_KeyLowerName_2 = "improved_performance"
_KeyName_3 = "debug_oidc_parent_erroroidc_single_v1_session_termination"
@@ -22,7 +22,7 @@ const (
var (
_KeyIndex_0 = [...]uint8{0, 11, 28}
_KeyIndex_1 = [...]uint8{0, 11, 25}
_KeyIndex_1 = [...]uint8{0, 11}
_KeyIndex_2 = [...]uint8{0, 20}
_KeyIndex_3 = [...]uint8{0, 23, 57}
_KeyIndex_4 = [...]uint8{0, 26, 34, 53, 87, 111}
@@ -32,9 +32,8 @@ func (i Key) String() string {
switch {
case 0 <= i && i <= 1:
return _KeyName_0[_KeyIndex_0[i]:_KeyIndex_0[i+1]]
case 4 <= i && i <= 5:
i -= 4
return _KeyName_1[_KeyIndex_1[i]:_KeyIndex_1[i+1]]
case i == 4:
return _KeyName_1
case i == 7:
return _KeyName_2
case 9 <= i && i <= 10:
@@ -55,7 +54,6 @@ func _KeyNoOp() {
_ = x[KeyUnspecified-(0)]
_ = x[KeyLoginDefaultOrg-(1)]
_ = x[KeyUserSchema-(4)]
_ = x[KeyTokenExchange-(5)]
_ = x[KeyImprovedPerformance-(7)]
_ = x[KeyDebugOIDCParentError-(9)]
_ = x[KeyOIDCSingleV1SessionTermination-(10)]
@@ -66,7 +64,7 @@ func _KeyNoOp() {
_ = x[KeyEnableRelationalTables-(16)]
}
var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyUserSchema, KeyTokenExchange, KeyImprovedPerformance, KeyDebugOIDCParentError, KeyOIDCSingleV1SessionTermination, KeyEnableBackChannelLogout, KeyLoginV2, KeyPermissionCheckV2, KeyManagementConsoleUseV2UserApi, KeyEnableRelationalTables}
var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyUserSchema, KeyImprovedPerformance, KeyDebugOIDCParentError, KeyOIDCSingleV1SessionTermination, KeyEnableBackChannelLogout, KeyLoginV2, KeyPermissionCheckV2, KeyManagementConsoleUseV2UserApi, KeyEnableRelationalTables}
var _KeyNameToValueMap = map[string]Key{
_KeyName_0[0:11]: KeyUnspecified,
@@ -75,8 +73,6 @@ var _KeyNameToValueMap = map[string]Key{
_KeyLowerName_0[11:28]: KeyLoginDefaultOrg,
_KeyName_1[0:11]: KeyUserSchema,
_KeyLowerName_1[0:11]: KeyUserSchema,
_KeyName_1[11:25]: KeyTokenExchange,
_KeyLowerName_1[11:25]: KeyTokenExchange,
_KeyName_2[0:20]: KeyImprovedPerformance,
_KeyLowerName_2[0:20]: KeyImprovedPerformance,
_KeyName_3[0:23]: KeyDebugOIDCParentError,
@@ -99,7 +95,6 @@ var _KeyNames = []string{
_KeyName_0[0:11],
_KeyName_0[11:28],
_KeyName_1[0:11],
_KeyName_1[11:25],
_KeyName_2[0:20],
_KeyName_3[0:23],
_KeyName_3[23:57],
+2 -2
View File
@@ -6,14 +6,14 @@ with domain as (
), instance_features as (
select i.*
from domain d
join projections.instance_features3 i on d.instance_id = i.instance_id
join projections.instance_features4 i on d.instance_id = i.instance_id
), features as (
select instance_id, json_object_agg(
coalesce(i.key, s.key),
coalesce(i.value, s.value)
) features
from domain d
cross join projections.system_features2 s
cross join projections.system_features3 s
full outer join instance_features i using (instance_id, key)
group by instance_id
), external_domains as (
+2 -2
View File
@@ -4,8 +4,8 @@ with features as (
coalesce(i.value, s.value)
) features
from (select $1::text instance_id) x
cross join projections.system_features2 s
full outer join projections.instance_features3 i using (key, instance_id)
cross join projections.system_features3 s
full outer join projections.instance_features4 i using (key, instance_id)
group by instance_id
), external_domains as (
select instance_id, array_agg(domain) as domains
-1
View File
@@ -11,7 +11,6 @@ type InstanceFeatures struct {
Details *domain.ObjectDetails
LoginDefaultOrg FeatureSource[bool]
UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool]
ImprovedPerformance FeatureSource[[]feature.ImprovedPerformanceType]
DebugOIDCParentError FeatureSource[bool]
OIDCSingleV1SessionTermination FeatureSource[bool]
@@ -64,7 +64,6 @@ func (m *InstanceFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.InstanceResetEventType,
feature_v2.InstanceLoginDefaultOrgEventType,
feature_v2.InstanceUserSchemaEventType,
feature_v2.InstanceTokenExchangeEventType,
feature_v2.InstanceImprovedPerformanceEventType,
feature_v2.InstanceDebugOIDCParentErrorEventType,
feature_v2.InstanceOIDCSingleV1SessionTerminationEventType,
@@ -92,7 +91,6 @@ func (m *InstanceFeaturesReadModel) populateFromSystem() bool {
}
m.instance.LoginDefaultOrg = m.system.LoginDefaultOrg
m.instance.UserSchema = m.system.UserSchema
m.instance.TokenExchange = m.system.TokenExchange
m.instance.ImprovedPerformance = m.system.ImprovedPerformance
m.instance.OIDCSingleV1SessionTermination = m.system.OIDCSingleV1SessionTermination
m.instance.EnableBackChannelLogout = m.system.EnableBackChannelLogout
@@ -112,8 +110,6 @@ func reduceInstanceFeatureSet[T any](features *InstanceFeatures, event *feature_
features.LoginDefaultOrg.set(level, event.Value)
case feature.KeyUserSchema:
features.UserSchema.set(level, event.Value)
case feature.KeyTokenExchange:
features.TokenExchange.set(level, event.Value)
case feature.KeyImprovedPerformance:
features.ImprovedPerformance.set(level, event.Value)
case feature.KeyDebugOIDCParentError:
@@ -14,7 +14,7 @@ import (
)
const (
InstanceFeatureTable = "projections.instance_features3"
InstanceFeatureTable = "projections.instance_features4"
InstanceFeatureInstanceIDCol = "instance_id"
InstanceFeatureKeyCol = "key"
@@ -68,10 +68,6 @@ func (*instanceFeatureProjection) Reducers() []handler.AggregateReducer {
Event: feature_v2.InstanceUserSchemaEventType,
Reduce: reduceInstanceSetFeature[bool],
},
{
Event: feature_v2.InstanceTokenExchangeEventType,
Reduce: reduceInstanceSetFeature[bool],
},
{
Event: feature_v2.InstanceImprovedPerformanceEventType,
Reduce: reduceInstanceSetFeature[[]feature.ImprovedPerformanceType],
@@ -38,7 +38,7 @@ func TestInstanceFeaturesProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.instance_features3 (instance_id, key, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (instance_id, key) DO UPDATE SET (creation_date, change_date, sequence, value) = (projections.instance_features3.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)",
expectedStmt: "INSERT INTO projections.instance_features4 (instance_id, key, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (instance_id, key) DO UPDATE SET (creation_date, change_date, sequence, value) = (projections.instance_features4.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)",
expectedArgs: []interface{}{
"agg-id",
"user_schema",
@@ -69,7 +69,7 @@ func TestInstanceFeaturesProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.instance_features3 (instance_id, key, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (instance_id, key) DO UPDATE SET (creation_date, change_date, sequence, value) = (projections.instance_features3.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)",
expectedStmt: "INSERT INTO projections.instance_features4 (instance_id, key, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (instance_id, key) DO UPDATE SET (creation_date, change_date, sequence, value) = (projections.instance_features4.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)",
expectedArgs: []interface{}{
"instance-id",
"login_default_org",
@@ -100,7 +100,7 @@ func TestInstanceFeaturesProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.instance_features3 WHERE (instance_id = $1)",
expectedStmt: "DELETE FROM projections.instance_features4 WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},
@@ -126,7 +126,7 @@ func TestInstanceFeaturesProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.instance_features3 WHERE (instance_id = $1)",
expectedStmt: "DELETE FROM projections.instance_features4 WHERE (instance_id = $1)",
expectedArgs: []interface{}{
"agg-id",
},
+1 -5
View File
@@ -12,7 +12,7 @@ import (
)
const (
SystemFeatureTable = "projections.system_features2"
SystemFeatureTable = "projections.system_features3"
SystemFeatureKeyCol = "key"
SystemFeatureCreationDateCol = "creation_date"
@@ -60,10 +60,6 @@ func (*systemFeatureProjection) Reducers() []handler.AggregateReducer {
Event: feature_v2.SystemUserSchemaEventType,
Reduce: reduceSystemSetFeature[bool],
},
{
Event: feature_v2.SystemTokenExchangeEventType,
Reduce: reduceSystemSetFeature[bool],
},
{
Event: feature_v2.SystemImprovedPerformanceEventType,
Reduce: reduceSystemSetFeature[[]feature.ImprovedPerformanceType],
@@ -36,7 +36,7 @@ func TestSystemFeaturesProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "INSERT INTO projections.system_features2 (key, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (key) DO UPDATE SET (creation_date, change_date, sequence, value) = (projections.system_features2.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)",
expectedStmt: "INSERT INTO projections.system_features3 (key, creation_date, change_date, sequence, value) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (key) DO UPDATE SET (creation_date, change_date, sequence, value) = (projections.system_features3.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.value)",
expectedArgs: []interface{}{
"user_schema",
anyArg{},
@@ -66,7 +66,7 @@ func TestSystemFeaturesProjection_reduces(t *testing.T) {
executer: &testExecuter{
executions: []execution{
{
expectedStmt: "DELETE FROM projections.system_features2 WHERE (key IS NOT NULL)",
expectedStmt: "DELETE FROM projections.system_features3 WHERE (key IS NOT NULL)",
expectedArgs: []interface{}{},
},
},
-1
View File
@@ -22,7 +22,6 @@ type SystemFeatures struct {
LoginDefaultOrg FeatureSource[bool]
UserSchema FeatureSource[bool]
TokenExchange FeatureSource[bool]
ImprovedPerformance FeatureSource[[]feature.ImprovedPerformanceType]
OIDCSingleV1SessionTermination FeatureSource[bool]
EnableBackChannelLogout FeatureSource[bool]
-3
View File
@@ -57,7 +57,6 @@ func (m *SystemFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
feature_v2.SystemResetEventType,
feature_v2.SystemLoginDefaultOrgEventType,
feature_v2.SystemUserSchemaEventType,
feature_v2.SystemTokenExchangeEventType,
feature_v2.SystemImprovedPerformanceEventType,
feature_v2.SystemOIDCSingleV1SessionTerminationEventType,
feature_v2.SystemEnableBackChannelLogout,
@@ -85,8 +84,6 @@ func reduceSystemFeatureSet[T any](features *SystemFeatures, event *feature_v2.S
features.LoginDefaultOrg.set(level, event.Value)
case feature.KeyUserSchema:
features.UserSchema.set(level, event.Value)
case feature.KeyTokenExchange:
features.TokenExchange.set(level, event.Value)
case feature.KeyImprovedPerformance:
features.ImprovedPerformance.set(level, event.Value)
case feature.KeyOIDCSingleV1SessionTermination:
@@ -9,7 +9,6 @@ func init() {
eventstore.RegisterFilterEventMapper(AggregateType, SystemResetEventType, eventstore.GenericEventMapper[ResetEvent])
eventstore.RegisterFilterEventMapper(AggregateType, SystemLoginDefaultOrgEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemUserSchemaEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemTokenExchangeEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemImprovedPerformanceEventType, eventstore.GenericEventMapper[SetEvent[[]feature.ImprovedPerformanceType]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemOIDCSingleV1SessionTerminationEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, SystemEnableBackChannelLogout, eventstore.GenericEventMapper[SetEvent[bool]])
@@ -20,7 +19,6 @@ func init() {
eventstore.RegisterFilterEventMapper(AggregateType, InstanceResetEventType, eventstore.GenericEventMapper[ResetEvent])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceLoginDefaultOrgEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceUserSchemaEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceTokenExchangeEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceImprovedPerformanceEventType, eventstore.GenericEventMapper[SetEvent[[]feature.ImprovedPerformanceType]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceDebugOIDCParentErrorEventType, eventstore.GenericEventMapper[SetEvent[bool]])
eventstore.RegisterFilterEventMapper(AggregateType, InstanceOIDCSingleV1SessionTerminationEventType, eventstore.GenericEventMapper[SetEvent[bool]])
@@ -14,7 +14,6 @@ var (
SystemResetEventType = resetEventTypeFromFeature(feature.LevelSystem)
SystemLoginDefaultOrgEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyLoginDefaultOrg)
SystemUserSchemaEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyUserSchema)
SystemTokenExchangeEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyTokenExchange)
SystemImprovedPerformanceEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyImprovedPerformance)
SystemOIDCSingleV1SessionTerminationEventType = setEventTypeFromFeature(feature.LevelSystem, feature.KeyOIDCSingleV1SessionTermination)
SystemEnableBackChannelLogout = setEventTypeFromFeature(feature.LevelSystem, feature.KeyEnableBackChannelLogout)
@@ -25,7 +24,6 @@ var (
InstanceResetEventType = resetEventTypeFromFeature(feature.LevelInstance)
InstanceLoginDefaultOrgEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyLoginDefaultOrg)
InstanceUserSchemaEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyUserSchema)
InstanceTokenExchangeEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyTokenExchange)
InstanceImprovedPerformanceEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyImprovedPerformance)
InstanceDebugOIDCParentErrorEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyDebugOIDCParentError)
InstanceOIDCSingleV1SessionTerminationEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyOIDCSingleV1SessionTermination)
-2
View File
@@ -600,7 +600,6 @@ Errors:
Data:
Invalid: البيانات غير صالحة لمخطط المستخدم
TokenExchange:
FeatureDisabled: ميزة تبادل الرموز معطلة للمثيل الخاص بك. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: الرمز مفقود
Invalid: الرمز غير صالح
@@ -614,7 +613,6 @@ Errors:
ActiveDelete: لا يمكن حذف مفتاح ويب نشط
Config: تكوين مفتاح الويب غير صالح
Duplicate: معرف مفتاح الويب ليس فريداً
FeatureDisabled: ميزة مفتاح الويب معطلة
NoActive: لم يتم العثور على مفتاح ويب نشط
NotFound: مفتاح الويب غير موجود
-2
View File
@@ -622,7 +622,6 @@ Errors:
Data:
Invalid: Невалидни данни за потребителска схема
TokenExchange:
FeatureDisabled: Функцията Token Exchange е деактивирана за вашето копие. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Токенът липсва
Invalid: Токенът е невалиден
@@ -636,7 +635,6 @@ Errors:
ActiveDelete: Не може да се изтрие активен уеб ключ
Config: Невалидна конфигурация на уеб ключ
Duplicate: ID на уеб ключ не е уникален
FeatureDisabled: Ключовата уеб функция е деактивирана
NoActive: Не е намерен активен уеб ключ
NotFound: Уеб ключът не е намерен
-2
View File
@@ -602,7 +602,6 @@ Errors:
Data:
Invalid: Data neplatná pro uživatelské schéma
TokenExchange:
FeatureDisabled: Funkce Token Exchange je pro vaši instanci zakázána. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Token chybí
Invalid: Token je neplatný
@@ -616,7 +615,6 @@ Errors:
ActiveDelete: Aktivní webový klíč nelze smazat
Config: Neplatná konfigurace webového klíče
Duplicate: ID webového klíče není jedinečné
FeatureDisabled: Funkce webového klíče je zakázána
NoActive: Nebyl nalezen žádný aktivní webový klíč
NotFound: Webový klíč nebyl nalezen
-2
View File
@@ -604,7 +604,6 @@ Errors:
Data:
Invalid: Daten für Benutzerschema ungültig
TokenExchange:
FeatureDisabled: Die Token-Austauschfunktion ist für Ihre Instanz deaktiviert. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Token fehlt
Invalid: Token ist ungültig
@@ -618,7 +617,6 @@ Errors:
ActiveDelete: Aktiver Webschlüssel kann nicht gelöscht werden
Config: Ungültige Webschlüsselkonfiguration
Duplicate: Webschlüssel-ID nicht eindeutig
FeatureDisabled: Webschlüsselfunktion deaktiviert
NoActive: Kein aktiver Webschlüssel gefunden
NotFound: Webschlüssel nicht gefunden
-2
View File
@@ -605,7 +605,6 @@ Errors:
Data:
Invalid: Data invalid for User Schema
TokenExchange:
FeatureDisabled: Token Exchange feature is disabled for your instance. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Token is missing
Invalid: Token is invalid
@@ -619,7 +618,6 @@ Errors:
ActiveDelete: Cannot delete active web key
Config: Invalid web key config
Duplicate: Web key ID not unique
FeatureDisabled: Web key feature disabled
NoActive: No active web key found
NotFound: Web key not found
-2
View File
@@ -604,7 +604,6 @@ Errors:
Data:
Invalid: Datos no válidos para el esquema de usuario
TokenExchange:
FeatureDisabled: La función de intercambio de tokens está deshabilitada para su instancia. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Falta la ficha
Invalid: El token no es válido
@@ -618,7 +617,6 @@ Errors:
ActiveDelete: No se puede eliminar la clave web activa
Config: Configuración de clave web no válida
Duplicate: ID de clave web no único
FeatureDisabled: Función de clave web deshabilitada
NoActive: No se encontró ninguna clave web activa
NotFound: Clave web no encontrada
-2
View File
@@ -604,7 +604,6 @@ Errors:
Data:
Invalid: Données non valides pour le schéma utilisateur
TokenExchange:
FeatureDisabled: La fonctionnalité Token Exchange est désactivée pour votre instance. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Le jeton est manquant
Invalid: Le jeton n'est pas valide
@@ -618,7 +617,6 @@ Errors:
ActiveDelete: Impossible de supprimer la clé Web active
Config: Configuration de clé Web non valide
Duplicate: L'ID de clé Web n'est pas unique
FeatureDisabled: Fonctionnalité de clé Web désactivée
NoActive: Aucune clé Web active trouvée
NotFound: Clé Web introuvable
-2
View File
@@ -604,7 +604,6 @@ Errors:
Data:
Invalid: Érvénytelen adat a User Schema-hoz
TokenExchange:
FeatureDisabled: A Token Exchange funkció le van tiltva az példányod esetében. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: A token hiányzik
Invalid: A token érvénytelen
@@ -618,7 +617,6 @@ Errors:
ActiveDelete: Az aktív webkulcs nem törölhető
Config: Érvénytelen webkulcs konfiguráció
Duplicate: A webkulcs azonosító nem egyedi
FeatureDisabled: A webkulcs funkció le van tiltva
NoActive: Aktív web kulcs nem található
NotFound: Web kulcs nem található
-2
View File
@@ -599,7 +599,6 @@ Errors:
NotInactive: Skema Pengguna tidak aktif
NotExists: Skema Pengguna tidak ada
TokenExchange:
FeatureDisabled: 'Fitur Token Exchange dinonaktifkan untuk instance Anda. '
Token:
Missing: Tokennya hilang
Invalid: Token tidak valid
@@ -613,7 +612,6 @@ Errors:
ActiveDelete: Tidak dapat menghapus kunci web yang aktif
Config: Konfigurasi kunci web tidak valid
Duplicate: ID kunci web tidak unik
FeatureDisabled: Fitur kunci web dinonaktifkan
NoActive: Tidak ditemukan kunci web aktif
NotFound: Kunci web tidak ditemukan
-2
View File
@@ -604,7 +604,6 @@ Errors:
Data:
Invalid: Dati non validi per lo schema utente
TokenExchange:
FeatureDisabled: La funzionalità di scambio token è disabilitata per la tua istanza. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Manca il gettone
Invalid: Il token non è valido
@@ -618,7 +617,6 @@ Errors:
ActiveDelete: Impossibile eliminare la chiave Web attiva
Config: Configurazione chiave Web non valida
Duplicate: ID chiave Web non univoco
FeatureDisabled: Funzione chiave Web disabilitata
NoActive: Nessuna chiave Web attiva trovata
NotFound: Chiave Web non trovata
-2
View File
@@ -605,7 +605,6 @@ Errors:
Data:
Invalid: ユーザー スキーマのデータが無効です
TokenExchange:
FeatureDisabled: インスタンスではトークン交換機能が無効になっています。 https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: トークンがありません
Invalid: トークンが無効です
@@ -619,7 +618,6 @@ Errors:
ActiveDelete: アクティブな Web キーを削除できません
Config: 無効な Web キー設定
Duplicate: Web キー ID が一意ではありません
FeatureDisabled: Web キー機能が無効です
NoActive: アクティブな Web キーが見つかりません
NotFound: Web キーが見つかりません
-2
View File
@@ -605,7 +605,6 @@ Errors:
Data:
Invalid: 사용자 스키마에 대한 데이터가 유효하지 않습니다
TokenExchange:
FeatureDisabled: 토큰 교환 기능이 인스턴스에서 비활성화되어 있습니다. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: 토큰이 누락되었습니다
Invalid: 토큰이 유효하지 않습니다
@@ -619,7 +618,6 @@ Errors:
ActiveDelete: 활성 웹 키를 삭제할 수 없습니다
Config: 웹 키 설정이 유효하지 않습니다
Duplicate: 웹 키 ID가 고유하지 않습니다
FeatureDisabled: 웹 키 기능이 비활성화되었습니다
NoActive: 활성 웹 키가 없습니다
NotFound: 웹 키를 찾을 수 없습니다
-2
View File
@@ -603,7 +603,6 @@ Errors:
Data:
Invalid: Податоците не се валидни за корисничка шема
TokenExchange:
FeatureDisabled: Функцијата за размена на токени е оневозможена на вашиот пример. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Недостасува токен
Invalid: Токенот е неважечки
@@ -617,7 +616,6 @@ Errors:
ActiveDelete: Не може да се избрише активниот веб-клуч
Config: Неважечка конфигурација на веб-клуч
Duplicate: ID на веб-клучот не е единствен
FeatureDisabled: Функцијата за веб-клуч е оневозможена
NoActive: Не е пронајден активен веб-клуч
NotFound: Веб-клучот не е пронајден
-2
View File
@@ -604,7 +604,6 @@ Errors:
Data:
Invalid: Податоците не се валидни за корисничка шема
TokenExchange:
FeatureDisabled: De Token Exchange-functie is uitgeschakeld voor uw instantie. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Token ontbreekt
Invalid: Token is ongeldig
@@ -618,7 +617,6 @@ Errors:
ActiveDelete: Kan actieve websleutel niet verwijderen
Config: Ongeldige websleutelconfiguratie
Duplicate: Websleutel-ID niet uniek
FeatureDisabled: Websleutelfunctie uitgeschakeld
NoActive: Geen actieve websleutel gevonden
NotFound: Websleutel niet gevonden
-2
View File
@@ -604,7 +604,6 @@ Errors:
Data:
Invalid: Nieprawidłowe dane dla schematu użytkownika
TokenExchange:
FeatureDisabled: Funkcja wymiany tokenów jest wyłączona dla Twojej instancji. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Brak tokena
Invalid: Token jest nieprawidłowy
@@ -618,7 +617,6 @@ Errors:
ActiveDelete: Nie można usunąć aktywnego klucza internetowego
Config: Nieprawidłowa konfiguracja klucza internetowego
Duplicate: Identyfikator klucza internetowego nie jest unikalny
FeatureDisabled: Funkcja klucza internetowego jest wyłączona
NoActive: Nie znaleziono aktywnego klucza internetowego
NotFound: Nie znaleziono klucza internetowego
-2
View File
@@ -603,7 +603,6 @@ Errors:
Data:
Invalid: Dados inválidos para o esquema do utilizador
TokenExchange:
FeatureDisabled: O recurso Token Exchange está desabilitado para sua instância. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: O token está faltando
Invalid: O token é inválido
@@ -617,7 +616,6 @@ Errors:
ActiveDelete: Não é possível eliminar a chave web ativa
Config: Configuração de chave web inválida
Duplicate: ID da chave Web não exclusivo
FeatureDisabled: Recurso chave da Web desativado
NoActive: Nenhuma chave web ativa encontrada
NotFound: Chave Web não encontrada
-2
View File
@@ -600,7 +600,6 @@ Errors:
Data:
Invalid: Datele sunt invalide pentru schema de utilizator
TokenExchange:
FeatureDisabled: Caracteristica Token Exchange este dezactivată pentru instanța dvs. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Token-ul lipsește
Invalid: Token-ul este invalid
@@ -614,7 +613,6 @@ Errors:
ActiveDelete: Nu se poate șterge o cheie web activă
Config: Configurație cheie web invalidă
Duplicate: ID-ul cheii web nu este unic
FeatureDisabled: Caracteristica cheie web este dezactivată
NoActive: Nu a fost găsită nicio cheie web activă
NotFound: Cheia web nu a fost găsită
-2
View File
@@ -593,7 +593,6 @@ Errors:
Data:
Invalid: Данные недействительны для схемы пользователя
TokenExchange:
FeatureDisabled: Функция обмена токенами отключена для вашего экземпляра. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Токен отсутствует
Invalid: Токен недействителен
@@ -607,7 +606,6 @@ Errors:
ActiveDelete: Невозможно удалить активный веб-ключ
Config: Неверная конфигурация веб-ключа
Duplicate: Идентификатор веб-ключа не уникален
FeatureDisabled: Функция веб-ключа отключена
NoActive: Активный веб-ключ не найден
NotFound: Веб-ключ не найден
-2
View File
@@ -604,7 +604,6 @@ Errors:
Data:
Invalid: Data ogiltig för användarschema
TokenExchange:
FeatureDisabled: Token Exchange-funktionen är inaktiverad för din instans. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Token saknas
Invalid: Token är ogiltig
@@ -618,7 +617,6 @@ Errors:
ActiveDelete: Det går inte att ta bort aktiv webbnyckel
Config: Ogiltig webbnyckelkonfiguration
Duplicate: Webnyckel-ID är inte unikt
FeatureDisabled: Webnyckelfunktion inaktiverad
NoActive: Ingen aktiv webbnyckel hittades
NotFound: Webnyckel hittades inte
-2
View File
@@ -605,7 +605,6 @@ Errors:
Data:
Invalid: Kullanıcı Şeması için veri geçersiz
TokenExchange:
FeatureDisabled: Token Exchange özelliği instance'ınız için devre dışı. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Token eksik
Invalid: Token geçersiz
@@ -619,7 +618,6 @@ Errors:
ActiveDelete: Aktif web anahtarı silinemez
Config: Geçersiz web anahtarı yapılandırması
Duplicate: Web anahtarı ID benzersiz değil
FeatureDisabled: Web anahtarı özelliği devre dışı
NoActive: Aktif web anahtarı bulunamadı
NotFound: Web anahtarı bulunamadı
-2
View File
@@ -599,7 +599,6 @@ Errors:
Data:
Invalid: Дані недійсні для схеми користувача
TokenExchange:
FeatureDisabled: Функція обміну токенів вимкнена для вашого інстансу. https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: Токен відсутній
Invalid: Токен недійсний
@@ -613,7 +612,6 @@ Errors:
ActiveDelete: Неможливо видалити активний веб-ключ
Config: Недійсна конфігурація веб-ключа
Duplicate: Ідентифікатор веб-ключа не унікальний
FeatureDisabled: Функція веб-ключа вимкнена
NoActive: Активний веб-ключ не знайдено
NotFound: Веб-ключ не знайдено
-2
View File
@@ -605,7 +605,6 @@ Errors:
Data:
Invalid: 用户架构的数据无效
TokenExchange:
FeatureDisabled: 您的实例已禁用令牌交换功能。 https://zitadel.com/docs/apis/resources/feature_service_v2/feature-service-set-instance-features
Token:
Missing: 令牌丢失
Invalid: 令牌无效
@@ -619,7 +618,6 @@ Errors:
ActiveDelete: 无法删除活动 Web 密钥
Config: 无效的 Web 密钥配置
Duplicate: Web 密钥 ID 不唯一
FeatureDisabled: Web 密钥功能已禁用
NoActive: 未找到活动 Web 密钥
NotFound: 未找到 Web 密钥
+13 -8
View File
@@ -28,11 +28,14 @@ message SetInstanceFeaturesRequest{
}
];
// Deprecated: the flag has been removed and `urn:ietf:params:oauth:grant-type:token-exchange`
// grant type for the OIDC token endpoint is enabled by default.
// Token exchange can be used to request tokens with a lesser scope or impersonate other users.
// See the security policy to allow impersonation on an instance.
// This field is only kept for backward compatibility and will be removed in the next major version of Zitadel.
// Setting the field will have no effect.
optional bool oidc_token_exchange = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
}
deprecated = true
];
repeated ImprovedPerformance improved_performance = 7 [
@@ -131,11 +134,13 @@ message GetInstanceFeaturesResponse {
}
];
// Deprecated: the flag has been removed and `urn:ietf:params:oauth:grant-type:token-exchange`
// grant type for the OIDC token endpoint is enabled by default.
// Token exchange can be used to request tokens with a lesser scope or impersonate other users.
// See the security policy to allow impersonation on an instance.
// This field is only kept for backward compatibility and will be removed in the next major version of Zitadel.
FeatureFlag oidc_token_exchange = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
}
deprecated = true
];
ImprovedPerformanceFeatureFlag improved_performance = 8 [
+13 -8
View File
@@ -28,11 +28,14 @@ message SetSystemFeaturesRequest{
}
];
// Deprecated: the flag has been removed and `urn:ietf:params:oauth:grant-type:token-exchange`
// grant type for the OIDC token endpoint is enabled by default.
// Token exchange can be used to request tokens with a lesser scope or impersonate other users.
// See the security policy to allow impersonation on an instance.
// This field is only kept for backward compatibility and will be removed in the next major version of Zitadel.
// Setting the field will have no effect.
optional bool oidc_token_exchange = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
}
deprecated = true
];
repeated ImprovedPerformance improved_performance = 7 [
@@ -111,11 +114,13 @@ message GetSystemFeaturesResponse {
}
];
// Deprecated: the flag has been removed and `urn:ietf:params:oauth:grant-type:token-exchange`
// grant type for the OIDC token endpoint is enabled by default.
// Token exchange can be used to request tokens with a lesser scope or impersonate other users.
// See the security policy to allow impersonation on an instance.
// This field is only kept for backward compatibility and will be removed in the next major version of Zitadel.
FeatureFlag oidc_token_exchange = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
}
deprecated = true
];
ImprovedPerformanceFeatureFlag improved_performance = 8 [
+13 -8
View File
@@ -27,11 +27,14 @@ message SetInstanceFeaturesRequest{
}
];
// Deprecated: the flag has been removed and `urn:ietf:params:oauth:grant-type:token-exchange`
// grant type for the OIDC token endpoint is enabled by default.
// Token exchange can be used to request tokens with a lesser scope or impersonate other users.
// See the security policy to allow impersonation on an instance.
// This field is only kept for backward compatibility and will be removed in the next major version of Zitadel.
// Setting the field will have no effect.
optional bool oidc_token_exchange = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
}
deprecated = true
];
repeated ImprovedPerformance improved_performance = 7 [
@@ -95,11 +98,13 @@ message GetInstanceFeaturesResponse {
}
];
// Deprecated: the flag has been removed and `urn:ietf:params:oauth:grant-type:token-exchange`
// grant type for the OIDC token endpoint is enabled by default.
// Token exchange can be used to request tokens with a lesser scope or impersonate other users.
// See the security policy to allow impersonation on an instance.
// This field is only kept for backward compatibility and will be removed in the next major version of Zitadel.
FeatureFlag oidc_token_exchange = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
}
deprecated = true
];
ImprovedPerformanceFeatureFlag improved_performance = 8 [
+13 -8
View File
@@ -27,11 +27,14 @@ message SetSystemFeaturesRequest{
}
];
// Deprecated: the flag has been removed and `urn:ietf:params:oauth:grant-type:token-exchange`
// grant type for the OIDC token endpoint is enabled by default.
// Token exchange can be used to request tokens with a lesser scope or impersonate other users.
// See the security policy to allow impersonation on an instance.
// This field is only kept for backward compatibility and will be removed in the next major version of Zitadel.
// Setting the field will have no effect.
optional bool oidc_token_exchange = 5 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
}
deprecated = true
];
repeated ImprovedPerformance improved_performance = 7 [
@@ -81,11 +84,13 @@ message GetSystemFeaturesResponse {
}
];
// Deprecated: the flag has been removed and `urn:ietf:params:oauth:grant-type:token-exchange`
// grant type for the OIDC token endpoint is enabled by default.
// Token exchange can be used to request tokens with a lesser scope or impersonate other users.
// See the security policy to allow impersonation on an instance.
// This field is only kept for backward compatibility and will be removed in the next major version of Zitadel.
FeatureFlag oidc_token_exchange = 6 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "true";
description: "Enable the experimental `urn:ietf:params:oauth:grant-type:token-exchange` grant type for the OIDC token endpoint. Token exchange can be used to request tokens with a lesser scope or impersonate other users. See the security policy to allow impersonation on an instance.";
}
deprecated = true
];
ImprovedPerformanceFeatureFlag improved_performance = 8 [