From 929a65c1b54326a701bda9550a7662298d5ef12a Mon Sep 17 00:00:00 2001 From: Connor Peshek Date: Wed, 10 Jun 2026 21:32:15 -0500 Subject: [PATCH 01/20] website/integrations: dokuwiki: add post logout and logout urls (#22984) * docs/integrations: update dokuwiki with post logout and logout url * update oauth config screenshot * Optimised images with calibre/image-actions --------- Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> --- .../dokuwiki/dokuwiki_oauth_generic.png | Bin 35178 -> 163554 bytes .../documentation/dokuwiki/index.md | 5 ++++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/website/integrations/documentation/dokuwiki/dokuwiki_oauth_generic.png b/website/integrations/documentation/dokuwiki/dokuwiki_oauth_generic.png index 6141ebf41909bfa80454d8a8afc8fe711e36fe13..623096900293741a40fce9191b9ec9756b86dfe4 100644 GIT binary patch literal 163554 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�ciLz*a;6WkJ@dgGb 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�=ofw;glvY83 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 BsL}uc diff --git a/website/integrations/documentation/dokuwiki/index.md b/website/integrations/documentation/dokuwiki/index.md index 349507c5aa..2dd3bc1cb0 100644 --- a/website/integrations/documentation/dokuwiki/index.md +++ b/website/integrations/documentation/dokuwiki/index.md @@ -35,7 +35,8 @@ To support the integration of DokuWiki with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://dokuwiki.company/doku.php`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://dokuwiki.company/doku.php`. + - Add a **Redirect URI** of type `Strict` `Post Logout` as `https://dokuwiki.company/doku.php`. - Select any available signing key. - Under **Advanced protocol settings**, add the following OAuth mapping under **Scopes**: `authentik default OAuth Mapping: OpenID 'offline_access'` - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. @@ -68,6 +69,7 @@ For **oauthgeneric**: - Set `plugin»oauthgeneric»authurl` to `https://authentik.company/application/o/authorize/` - Set `plugin»oauthgeneric»tokenurl` to `https://authentik.company/application/o/token/` - Set `plugin»oauthgeneric»userurl` to `https://authentik.company/application/o/userinfo/` +- Set `plugin»oauthgeneric»logouturl` to `https://authentik.company/application/o/end-session/` - Set `plugin»oauthgeneric»authmethod` to `Bearer Header` - Set `plugin»oauthgeneric»scopes` to `email, openid, profile, offline_access` - Select `plugin»oauthgeneric»needs-state` @@ -75,6 +77,7 @@ For **oauthgeneric**: - Set `plugin»oauthgeneric»json-name` to `name` - Set `plugin»oauthgeneric»json-mail` to `email` - Set `plugin»oauthgeneric»json-grps` to`groups` +- Set `plugin»oauthgeneric»color ` to `#fd4b2d` ![](./dokuwiki_oauth_generic.png) From 8554427d3f84c4da39f1c9b6503b538b25ab8c3a Mon Sep 17 00:00:00 2001 From: "authentik-automation[bot]" <135050075+authentik-automation[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 05:35:35 +0200 Subject: [PATCH 02/20] core, web: update translations (#22983) Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> --- locale/en/LC_MESSAGES/django.po | 10 +--------- web/xliff/cs-CZ.xlf | 4 ---- web/xliff/de-DE.xlf | 4 ---- web/xliff/en.xlf | 3 --- web/xliff/es-ES.xlf | 4 ---- web/xliff/fi-FI.xlf | 4 ---- web/xliff/fr-FR.xlf | 4 ---- web/xliff/it-IT.xlf | 4 ---- web/xliff/ja-JP.xlf | 4 ---- web/xliff/ko-KR.xlf | 4 ---- web/xliff/nl-NL.xlf | 3 --- web/xliff/pl-PL.xlf | 4 ---- web/xliff/pt-BR.xlf | 4 ---- web/xliff/ru-RU.xlf | 4 ---- web/xliff/tr-TR.xlf | 4 ---- web/xliff/zh-Hans.xlf | 4 ---- web/xliff/zh-Hant.xlf | 3 --- 17 files changed, 1 insertion(+), 70 deletions(-) diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index ec23cf2ce9..6f636c5735 100644 --- a/locale/en/LC_MESSAGES/django.po +++ b/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-05-22 00:36+0000\n" +"POT-Creation-Date: 2026-06-11 00:42+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -3399,14 +3399,6 @@ msgstr "" msgid "Google OAuth Sources" msgstr "" -#: authentik/sources/oauth/models.py -msgid "Azure AD OAuth Source" -msgstr "" - -#: authentik/sources/oauth/models.py -msgid "Azure AD OAuth Sources" -msgstr "" - #: authentik/sources/oauth/models.py msgid "Entra ID OAuth Source" msgstr "" diff --git a/web/xliff/cs-CZ.xlf b/web/xliff/cs-CZ.xlf index 5515cebdbf..e0b633b284 100644 --- a/web/xliff/cs-CZ.xlf +++ b/web/xliff/cs-CZ.xlf @@ -6187,10 +6187,6 @@ neprojde, když jedna nebo obě z vybraných možností jsou rovny nebo nad prah Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. Volitelně omezte, které typy zařízení WebAuthn mohou být použity. Pokud nejsou vybrány žádné typy zařízení, jsou povolena všechna zařízení. - - This restriction only applies to devices created in authentik 2024.4 or later. - Toto omezení se vztahuje pouze na zařízení vytvořená v authentik 2024.4 nebo novějších verzích. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). Krok použitý k nastavení WebAuthn autentizátoru (např. Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/de-DE.xlf b/web/xliff/de-DE.xlf index e07cd9f2c7..7d7b38120e 100644 --- a/web/xliff/de-DE.xlf +++ b/web/xliff/de-DE.xlf @@ -6213,10 +6213,6 @@ Beim Erstellen eines festen Auswahlfelds aktiviere „Als Ausdruck interpretiere Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. Optional kannst du einschränken, welche WebAuthn-Gerätetypen verwendet werden dürfen. Wenn keine Gerätetypen ausgewählt sind, sind alle Geräte erlaubt. - - This restriction only applies to devices created in authentik 2024.4 or later. - Diese Beschränkung gilt nur für Geräte, die in authentik 2024.4 oder neuer erstellt wurden. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). Stage zur Konfiguration eines WebAuthn-Authenticators (z. B. Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/en.xlf b/web/xliff/en.xlf index 53c95b2ad2..299855a203 100644 --- a/web/xliff/en.xlf +++ b/web/xliff/en.xlf @@ -4781,9 +4781,6 @@ doesn't pass when either or both of the selected options are equal or above the Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. - - This restriction only applies to devices created in authentik 2024.4 or later. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/es-ES.xlf b/web/xliff/es-ES.xlf index 2d8e26c5f6..57a0f06b07 100644 --- a/web/xliff/es-ES.xlf +++ b/web/xliff/es-ES.xlf @@ -6153,10 +6153,6 @@ El valor de este campo se compara con el atributo de pertenencia del usuario.Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. Opcionalmente, restrinja los tipos de dispositivos WebAuthn que se pueden usar. Si no se selecciona ningún tipo de dispositivo, se permiten todos. - - This restriction only applies to devices created in authentik 2024.4 or later. - Esta restricción solo se aplica a dispositivos creados en authentik 2024.4 o posterior. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). Etapa utilizada para configurar un autenticador WebAuthn (es decir, Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/fi-FI.xlf b/web/xliff/fi-FI.xlf index 908b56d2af..64c19da239 100644 --- a/web/xliff/fi-FI.xlf +++ b/web/xliff/fi-FI.xlf @@ -6328,10 +6328,6 @@ läpäisy estyy kun jompi kumpi tai molemmat vaihtoehdot ylittävät raja-arvon. Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. Valinnaisesti voit rajoittaa, mitä WebAuthn-laitetyyppejä voidaan käyttää. Jos mitään tyyppiä ei ole valittu, kaiken tyyppiset laitteet sallitaan. - - This restriction only applies to devices created in authentik 2024.4 or later. - Tämä rajoitus koskee vain laitteita, jotka on luotu authentik 2024.4 tai uudemmalla versiolla. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). Vaihe, jolla määritellään WebAuthn-todentaja (esim. Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/fr-FR.xlf b/web/xliff/fr-FR.xlf index d0b4174309..831b3d0501 100644 --- a/web/xliff/fr-FR.xlf +++ b/web/xliff/fr-FR.xlf @@ -6318,10 +6318,6 @@ doesn't pass when either or both of the selected options are equal or above the Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. Optionnel, restreindre quels types d'appareil WebAuthn peuvent être utilisés. Lorsqu'aucun type d'appareil n'est sélectionné, tout les appareils sont autorisés. - - This restriction only applies to devices created in authentik 2024.4 or later. - Les restrictions ne s'appliquent qu'aux appareils créés dans authentik 2024.4 ou ultérieur. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). Étape de configuration d'un authentificateur WebAuthn (Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/it-IT.xlf b/web/xliff/it-IT.xlf index ae785e0830..70bea2cf10 100644 --- a/web/xliff/it-IT.xlf +++ b/web/xliff/it-IT.xlf @@ -6110,10 +6110,6 @@ doesn't pass when either or both of the selected options are equal or above the Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. Facoltativamente limitare quali tipi di dispositivi WebAuthn possono essere utilizzati. Quando non vengono selezionati tipi di dispositivi, tutti i dispositivi sono consentiti. - - This restriction only applies to devices created in authentik 2024.4 or later. - Questa restrizione si applica solo ai dispositivi creati in authentik 2024.4 o versione successiva. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). Fase utilizzato per configurare un autenticatore WebAuthn (ovvero Yubikey, FaceId/Windows Hello). diff --git a/web/xliff/ja-JP.xlf b/web/xliff/ja-JP.xlf index c050ecbbe8..938133e8c1 100644 --- a/web/xliff/ja-JP.xlf +++ b/web/xliff/ja-JP.xlf @@ -6322,10 +6322,6 @@ doesn't pass when either or both of the selected options are equal or above the Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. どの WebAuthn デバイスタイプを使用できるかをオプションで制限します。デバイスタイプが選択されていない場合、すべてのデバイスが許可されます。 - - This restriction only applies to devices created in authentik 2024.4 or later. - この制限は authentik 2024.4 以降で作成されたデバイスにのみ適用されます。 - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). WebAuthn 認証器を設定するために使用されるステージ(例:Yubikey、FaceID/Windows Hello)。 diff --git a/web/xliff/ko-KR.xlf b/web/xliff/ko-KR.xlf index 4c3f600733..f8d0affac6 100644 --- a/web/xliff/ko-KR.xlf +++ b/web/xliff/ko-KR.xlf @@ -5880,10 +5880,6 @@ doesn't pass when either or both of the selected options are equal or above the Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. - - This restriction only applies to devices created in authentik 2024.4 or later. - 이 제한은 authentik 2024.4 또는 이후에 등록된 기기에만 적용됩니다. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). WebAuthn 인증기를 구성하는 데 사용되는 스테이지(예: Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/nl-NL.xlf b/web/xliff/nl-NL.xlf index d47029f2d6..35dcea3012 100644 --- a/web/xliff/nl-NL.xlf +++ b/web/xliff/nl-NL.xlf @@ -5665,9 +5665,6 @@ slaagt niet wanneer een of beide geselecteerde opties gelijk zijn aan of boven d Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. - - This restriction only applies to devices created in authentik 2024.4 or later. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/pl-PL.xlf b/web/xliff/pl-PL.xlf index 55bf4aab79..b9082faea9 100644 --- a/web/xliff/pl-PL.xlf +++ b/web/xliff/pl-PL.xlf @@ -5896,10 +5896,6 @@ Można tu używać tylko zasad, ponieważ dostęp jest sprawdzany przed uwierzyt Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. Opcjonalnie ogranicza, które typy urządzeń WebAuthn mogą być używane. Jeśli nie wybrano żadnego typu urządzenia, wszystkie urządzenia są dozwolone. - - This restriction only applies to devices created in authentik 2024.4 or later. - To ograniczenie dotyczy tylko urządzeń utworzonych w wersji authentik 2024.4 lub nowszej. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). Etap używany do konfiguracji uwierzytelniacza WebAuthn (np. Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/pt-BR.xlf b/web/xliff/pt-BR.xlf index e9454e0fc0..345b3dbad6 100644 --- a/web/xliff/pt-BR.xlf +++ b/web/xliff/pt-BR.xlf @@ -6322,10 +6322,6 @@ retorne uma lista para fornecer várias opções padrão. Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. Opcionalmente restrinja quais tipos de dispositivos WebAuthn podem ser usados. Quando nenhum tipo de dispositivo é selecionado, todos os dispositivos são permitidos. - - This restriction only applies to devices created in authentik 2024.4 or later. - Essa restrição se aplica apenas a dispositivos criados no authentik 2024.4 ou posterior. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). Etapa usada para configurar um autenticador WebAuthn (ex.: Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/ru-RU.xlf b/web/xliff/ru-RU.xlf index e685331bb5..87eb455407 100644 --- a/web/xliff/ru-RU.xlf +++ b/web/xliff/ru-RU.xlf @@ -5946,10 +5946,6 @@ doesn't pass when either or both of the selected options are equal or above the Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. Опционально ограничьте типы устройств WebAuthn, которые могут быть использованы. Если типы устройств не выбраны, разрешены все устройства. - - This restriction only applies to devices created in authentik 2024.4 or later. - Это ограничение распространяется только на устройства, созданные в authentik 2024.4 или более поздней версии. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). Этап, используемый для настройки аутентификатора WebAuthn (например, Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/tr-TR.xlf b/web/xliff/tr-TR.xlf index 150b9b802c..e30d5d4895 100644 --- a/web/xliff/tr-TR.xlf +++ b/web/xliff/tr-TR.xlf @@ -5944,10 +5944,6 @@ Belirlenen seçeneklerden biri veya her ikisi de eşiğe eşit veya eşiğin üz Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. İsteğe bağlı olarak, hangi WebAuthn cihaz türlerinin kullanılabileceğini kısıtlayın. Hiçbir cihaz türü seçilmediğinde, tüm cihazlara izin verilir. - - This restriction only applies to devices created in authentik 2024.4 or later. - Bu kısıtlama yalnızca authentik 2024.4 veya sonraki sürümlerde oluşturulan cihazlar için geçerlidir. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). Bir WebAuthn kimlik doğrulayıcısını yapılandırmak için kullanılan sahne alanı (ör. Yubikey, FaceID/Windows Hello). diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index c2c7379fed..f686ae61eb 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -6379,10 +6379,6 @@ doesn't pass when either or both of the selected options are equal or above the Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. 可选的 WebAuthn 可用设备类型限制。如果未选择设备类型,则允许所有设备。 - - This restriction only applies to devices created in authentik 2024.4 or later. - 此限制仅适用于在 authentik 2024.4 或更新版本中创建的设备。 - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). 用来配置 WebAuthn 身份验证器(即 Yubikey、FaceID/Windows Hello)的阶段。 diff --git a/web/xliff/zh-Hant.xlf b/web/xliff/zh-Hant.xlf index 569e92981a..7cbccaf305 100644 --- a/web/xliff/zh-Hant.xlf +++ b/web/xliff/zh-Hant.xlf @@ -5707,9 +5707,6 @@ doesn't pass when either or both of the selected options are equal or above the Optionally restrict which WebAuthn device types may be used. When no device types are selected, all devices are allowed. - - This restriction only applies to devices created in authentik 2024.4 or later. - Stage used to configure a WebAuthn authenticator (i.e. Yubikey, FaceID/Windows Hello). 用於設定 WebAuthn 身份認證器的階段(例如 Yubikey、FaceID/Windows Hello)。 From 269a89708cc884d2a2a48d73bbc0045b3f4a6afb Mon Sep 17 00:00:00 2001 From: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com> Date: Thu, 11 Jun 2026 06:10:36 +0200 Subject: [PATCH 03/20] web/elements: extract mermaid runtime, modernize `` (#22980) * web: Clean up diagram behavior. * Add accessor. * Fix import. * Fix theme colors, consistent patternfly colors. * Fix spelling. --- web/package-lock.json | 20 +++ web/package.json | 25 +-- web/src/admin/flows/FlowDiagram.ts | 15 +- .../admin/sources/oauth/OAuthSourceDiagram.ts | 24 ++- web/src/common/theme.ts | 13 +- web/src/elements/Diagram.ts | 103 ----------- web/src/elements/Diagram/ak-diagram.css | 4 + web/src/elements/Diagram/ak-diagram.ts | 88 ++++++++++ web/src/elements/ak-mdx/ak-mdx.tsx | 10 +- web/src/elements/ak-mdx/styles.css | 27 --- web/src/elements/mermaid/mermaid.css | 59 +++++++ web/src/elements/mermaid/theme.ts | 164 ++++++++++++++++++ web/src/elements/mermaid/utils.ts | 76 ++++++++ 13 files changed, 462 insertions(+), 166 deletions(-) delete mode 100644 web/src/elements/Diagram.ts create mode 100644 web/src/elements/Diagram/ak-diagram.css create mode 100644 web/src/elements/Diagram/ak-diagram.ts create mode 100644 web/src/elements/mermaid/mermaid.css create mode 100644 web/src/elements/mermaid/theme.ts create mode 100644 web/src/elements/mermaid/utils.ts diff --git a/web/package-lock.json b/web/package-lock.json index 5ce5d55e2f..3c30a7932e 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -37,6 +37,7 @@ "@lit/reactive-element": "^2.1.2", "@lit/task": "^1.0.3", "@mdx-js/mdx": "^3.1.1", + "@mermaid-js/layout-elk": "^0.2.1", "@mrmarble/djangoql-completion": "^0.8.3", "@open-wc/lit-helpers": "^0.7.0", "@openlayers-elements/core": "^0.4.0", @@ -2037,6 +2038,19 @@ "react": ">=16" } }, + "node_modules/@mermaid-js/layout-elk": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/layout-elk/-/layout-elk-0.2.1.tgz", + "integrity": "sha512-MX9jwhMyd5zDcFsYcl3duDUkKhjVRUCGEQrdCeNV5hCIR6+3FuDDbRbFmvVbAu15K1+juzsYGG+K8MDvCY1Amg==", + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "elkjs": "^0.9.3" + }, + "peerDependencies": { + "mermaid": "^11.0.2" + } + }, "node_modules/@mermaid-js/parser": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.1.tgz", @@ -9387,6 +9401,12 @@ "integrity": "sha512-PwfIw7WQSt3xX7yOf5OE/unLzsK9CaN2f/FvV3WjPR1Knoc1T9vePRVV4W1EM301JzzysK51K7FNKcusCr0zYA==", "license": "ISC" }, + "node_modules/elkjs": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.9.3.tgz", + "integrity": "sha512-f/ZeWvW/BCXbhGEf1Ujp29EASo/lk1FDnETgNKwJrsVvGZhUWCZyg3xLJjAsxfOmt8KjswHmI5EwCQcPMpOYhQ==", + "license": "EPL-2.0" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", diff --git a/web/package.json b/web/package.json index 39563a776b..b873955a52 100644 --- a/web/package.json +++ b/web/package.json @@ -112,6 +112,7 @@ "@lit/reactive-element": "^2.1.2", "@lit/task": "^1.0.3", "@mdx-js/mdx": "^3.1.1", + "@mermaid-js/layout-elk": "^0.2.1", "@mrmarble/djangoql-completion": "^0.8.3", "@open-wc/lit-helpers": "^0.7.0", "@openlayers-elements/core": "^0.4.0", @@ -212,14 +213,10 @@ ], "wireit": { "build": { - "#comment": [ - "`npm run build` and `npm run watch` are the most common ", - "commands you should be using when working on the front end", - "The files and output spec here expect you to use `npm run build --watch` ", - "instead of `npm run watch`. The former is more comprehensive, but ", - "the latter is faster." - ], "command": "${NODE_RUNNER} scripts/build-web.mjs", + "dependencies": [ + "build-locales" + ], "files": [ "src/**/*.{css,jpg,png,ts,js,json}", "!src/**/*.stories.ts", @@ -239,8 +236,12 @@ "./dist/poly-*.js.map", "./dist/styles/**" ], - "dependencies": [ - "build-locales" + "#comment": [ + "`npm run build` and `npm run watch` are the most common ", + "commands you should be using when working on the front end", + "The files and output spec here expect you to use `npm run build --watch` ", + "instead of `npm run watch`. The former is more comprehensive, but ", + "the latter is faster." ], "env": { "NODE_RUNNER": { @@ -255,9 +256,6 @@ "build-locales" ] }, - "locales:repair": { - "command": "prettier --write ./src/locale-codes.ts" - }, "lint:components": { "command": "lit-analyzer src" }, @@ -270,6 +268,9 @@ "lit-analyse": { "command": "lit-analyzer src" }, + "locales:repair": { + "command": "prettier --write ./src/locale-codes.ts" + }, "precommit": { "command": "prettier --write .", "dependencies": [ diff --git a/web/src/admin/flows/FlowDiagram.ts b/web/src/admin/flows/FlowDiagram.ts index f2e93d7650..dcd08329a7 100644 --- a/web/src/admin/flows/FlowDiagram.ts +++ b/web/src/admin/flows/FlowDiagram.ts @@ -2,28 +2,29 @@ import "#elements/EmptyState"; import { aki } from "#common/api/client"; -import { Diagram } from "#elements/Diagram"; +import { Diagram } from "#elements/Diagram/ak-diagram"; import { FlowsApi } from "@goauthentik/api"; +import { observes } from "@patternfly/pfe-core/decorators/observes.js"; + import { customElement, property } from "lit/decorators.js"; @customElement("ak-flow-diagram") export class FlowDiagram extends Diagram { - @property() - flowSlug?: string; + @property({ type: String, useDefault: true }) + public flowSlug: string | null = null; - refreshHandler = (): void => { - this.diagram = undefined; + @observes("flowSlug") + protected refresh(): void { aki(FlowsApi) .flowsInstancesDiagramRetrieve({ slug: this.flowSlug || "", }) .then((data) => { this.diagram = data.diagram; - this.requestUpdate(); }); - }; + } } declare global { diff --git a/web/src/admin/sources/oauth/OAuthSourceDiagram.ts b/web/src/admin/sources/oauth/OAuthSourceDiagram.ts index a1151ffa61..ec5008999a 100644 --- a/web/src/admin/sources/oauth/OAuthSourceDiagram.ts +++ b/web/src/admin/sources/oauth/OAuthSourceDiagram.ts @@ -1,4 +1,4 @@ -import { Diagram } from "#elements/Diagram"; +import { Diagram } from "#elements/Diagram/ak-diagram"; import { UserMatchingModeToLabel } from "#admin/sources/oauth/utils"; @@ -9,22 +9,28 @@ import { customElement, property } from "lit/decorators.js"; @customElement("ak-source-oauth-diagram") export class OAuthSourceDiagram extends Diagram { - @property({ attribute: false }) - source?: OAuthSource; + @property({ attribute: false, useDefault: true }) + public source: OAuthSource | null = null; - refreshHandler = (): void => { + protected override syncDiagramContent = (): void => { if (!this.source) return; - const graph = ["graph LR"]; - graph.push(`source[${msg(str`OAuth Source ${this.source.name}`)}]`); - graph.push( - `source --> flow_manager["${UserMatchingModeToLabel(this.source.userMatchingMode || UserMatchingModeEnum.Identifier)}"]`, - ); + + const graph = [ + "graph LR", + `source[${msg(str`OAuth Source ${this.source.name}`)}]`, + `source --> flow_manager["${UserMatchingModeToLabel( + this.source.userMatchingMode || UserMatchingModeEnum.Identifier, + )}"]`, + ]; + if (this.source.enrollmentFlow) { graph.push("flow_manager --> flow_enroll[Enrollment flow]"); } + if (this.source.authenticationFlow) { graph.push("flow_manager --> flow_auth[Authentication flow]"); } + this.diagram = graph.join("\n"); }; } diff --git a/web/src/common/theme.ts b/web/src/common/theme.ts index 6bc5717d79..6966c50111 100644 --- a/web/src/common/theme.ts +++ b/web/src/common/theme.ts @@ -261,26 +261,29 @@ declare global { * @param hint The color scheme hint to use. * @param doc The document to apply the theme to. */ -export const applyDocumentTheme = ((currentUITheme = resolveUITheme(), doc = document): void => { +export const applyDocumentTheme = (( + currentUITheme = resolveUITheme(), + ownerDocument = document, +): void => { console.debug(`authentik/theme (document): want to switch to ${currentUITheme} theme`); - const { themeChoice } = doc.documentElement.dataset; + const { themeChoice } = ownerDocument.documentElement.dataset; if (themeChoice && themeChoice !== "auto") { console.debug( `authentik/theme (document): skipping theme application due to explicit choice (${themeChoice})`, ); - doc.dispatchEvent(new ThemeChangeEvent(themeChoice)); + ownerDocument.dispatchEvent(new ThemeChangeEvent(themeChoice)); return; } - doc.documentElement.dataset.theme = currentUITheme; + ownerDocument.documentElement.dataset.theme = currentUITheme; console.debug(`authentik/theme (document): switching to ${currentUITheme} theme`); - doc.dispatchEvent(new ThemeChangeEvent(currentUITheme)); + ownerDocument.dispatchEvent(new ThemeChangeEvent(currentUITheme)); }) satisfies UIThemeListener; /** diff --git a/web/src/elements/Diagram.ts b/web/src/elements/Diagram.ts deleted file mode 100644 index 12b4fa686e..0000000000 --- a/web/src/elements/Diagram.ts +++ /dev/null @@ -1,103 +0,0 @@ -import "#elements/EmptyState"; - -import { EVENT_REFRESH } from "#common/constants"; -import { DOM_PURIFY_STRICT } from "#common/purify"; -import { ThemeChangeEvent } from "#common/theme"; - -import { AKElement } from "#elements/Base"; - -import { UiThemeEnum } from "@goauthentik/api"; - -import mermaid, { MermaidConfig } from "mermaid"; - -import { css, CSSResult, html, TemplateResult } from "lit"; -import { customElement, property } from "lit/decorators.js"; -import { unsafeHTML } from "lit/directives/unsafe-html.js"; -import { until } from "lit/directives/until.js"; - -@customElement("ak-diagram") -export class Diagram extends AKElement { - @property({ attribute: false }) - diagram?: string; - - refreshHandler = (): void => { - if (!this.textContent) return; - this.diagram = this.textContent; - }; - - handlerBound = false; - - static styles: CSSResult[] = [ - css` - :host { - display: flex; - justify-content: center; - } - `, - ]; - - config: MermaidConfig; - - constructor() { - super(); - this.config = { - // The type definition for this says number - // but the example use strings - // and numbers don't work - logLevel: "fatal", - startOnLoad: false, - flowchart: { - curve: "linear", - }, - htmlLabels: false, - securityLevel: "strict", - dompurifyConfig: DOM_PURIFY_STRICT, - }; - mermaid.initialize(this.config); - } - - firstUpdated(): void { - if (this.handlerBound) return; - window.addEventListener(EVENT_REFRESH, this.refreshHandler); - this.addEventListener(ThemeChangeEvent.eventName, ((ev: CustomEvent) => { - if (ev.detail === UiThemeEnum.Dark) { - this.config.theme = "dark"; - } else { - this.config.theme = "default"; - } - mermaid.initialize(this.config); - }) as EventListener); - this.handlerBound = true; - this.refreshHandler(); - } - - disconnectedCallback(): void { - super.disconnectedCallback(); - window.removeEventListener(EVENT_REFRESH, this.refreshHandler); - } - - render(): TemplateResult { - this.querySelectorAll("*").forEach((el) => { - try { - el.remove(); - } catch { - console.debug(`authentik/diagram: failed to remove element ${el}`); - } - }); - if (!this.diagram) { - return html``; - } - return html`${until( - mermaid.render("graph", this.diagram).then((r) => { - r.bindFunctions?.(this.shadowRoot as unknown as Element); - return unsafeHTML(r.svg); - }), - )}`; - } -} - -declare global { - interface HTMLElementTagNameMap { - "ak-diagram": Diagram; - } -} diff --git a/web/src/elements/Diagram/ak-diagram.css b/web/src/elements/Diagram/ak-diagram.css new file mode 100644 index 0000000000..f21bc9f9bb --- /dev/null +++ b/web/src/elements/Diagram/ak-diagram.css @@ -0,0 +1,4 @@ +:host { + display: flex; + justify-content: center; +} diff --git a/web/src/elements/Diagram/ak-diagram.ts b/web/src/elements/Diagram/ak-diagram.ts new file mode 100644 index 0000000000..a0ab870a79 --- /dev/null +++ b/web/src/elements/Diagram/ak-diagram.ts @@ -0,0 +1,88 @@ +import "#elements/EmptyState"; + +import { AKRefreshEvent } from "#common/events"; + +import { AKElement } from "#elements/Base"; +import { listen } from "#elements/decorators/listen"; +import Styles from "#elements/Diagram/ak-diagram.css"; +import { EmptyState } from "#elements/EmptyState"; +import MermaidStyles from "#elements/mermaid/mermaid.css"; +import { loadMermaid } from "#elements/mermaid/utils"; +import { SlottedTemplateResult } from "#elements/types"; + +import { CSSResult, PropertyValues } from "lit"; +import { guard } from "lit-html/directives/guard.js"; +import { customElement, property } from "lit/decorators.js"; +import { unsafeHTML } from "lit/directives/unsafe-html.js"; +import { until } from "lit/directives/until.js"; + +@customElement("ak-diagram") +export class Diagram extends AKElement { + static styles: CSSResult[] = [MermaidStyles, Styles]; + + #diagram = ""; + @property({ attribute: false, useDefault: true }) + public get diagram(): string { + return this.#diagram || this.textContent.trim() || ""; + } + + public set diagram(value: string) { + const previous = this.#diagram; + this.#diagram = value.trim(); + + this.requestUpdate("diagram", previous); + } + + @listen(AKRefreshEvent, { + target: window, + }) + protected syncDiagramContent = (): void => { + if (!this.textContent) return; + this.diagram = this.textContent; + }; + + loadingPlaceholder: EmptyState; + + constructor() { + super(); + this.loadingPlaceholder = new EmptyState(); + this.loadingPlaceholder.loading = true; + } + + protected firstUpdated(changedProperties: PropertyValues): void { + super.firstUpdated(changedProperties); + this.syncDiagramContent(); + } + + protected renderMermaid(): Promise { + return loadMermaid(this.activeTheme).then((mermaid) => { + if (!this.diagram) { + return null; + } + + return mermaid.render(`mermaid-svg-${this.localName}`, this.diagram).then((result) => { + result.bindFunctions?.(this.renderRoot as HTMLElement); + + return unsafeHTML(result.svg); + }); + }); + } + + protected override render(): SlottedTemplateResult { + const { diagram, loadingPlaceholder, activeTheme } = this; + + return guard([diagram, activeTheme], () => { + if (!diagram) { + return loadingPlaceholder; + } + + return until(this.renderMermaid(), loadingPlaceholder); + }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "ak-diagram": Diagram; + } +} diff --git a/web/src/elements/ak-mdx/ak-mdx.tsx b/web/src/elements/ak-mdx/ak-mdx.tsx index 94d100d833..cbc50c2dcc 100644 --- a/web/src/elements/ak-mdx/ak-mdx.tsx +++ b/web/src/elements/ak-mdx/ak-mdx.tsx @@ -11,12 +11,12 @@ import { remarkHeadings } from "#elements/ak-mdx/remark/remark-headings"; import { remarkLists } from "#elements/ak-mdx/remark/remark-lists"; import Styles from "#elements/ak-mdx/styles.css"; import { AKElement } from "#elements/Base"; +import MermaidStyles from "#elements/mermaid/mermaid.css"; +import { loadMermaid } from "#elements/mermaid/utils"; import { DistDirectoryName, StaticDirectoryName } from "#paths"; import OneDark from "#styles/atom/one-dark.css"; -import { UiThemeEnum } from "@goauthentik/api"; - import { compile as compileMDX, run as runMDX } from "@mdx-js/mdx"; import apacheGrammar from "highlight.js/lib/languages/apache"; import diffGrammar from "highlight.js/lib/languages/diff"; @@ -77,6 +77,7 @@ export class AKMDX extends AKElement { PFTable, PFContent, OneDark, + MermaidStyles, Styles, ]; @@ -113,6 +114,8 @@ export class AKMDX extends AKElement { mdxModule.content, ); + const { activeTheme } = this; + const mdx = await compileMDX(normalized, { outputFormat: "function-body", remarkPlugins: [ @@ -132,7 +135,8 @@ export class AKMDX extends AKElement { rehypeMermaid, { prefix: "mermaid-svg-", - colorScheme: this.activeTheme === UiThemeEnum.Dark ? "dark" : "light", + colorScheme: activeTheme, + mermaidConfig: await loadMermaid(activeTheme), } satisfies RehypeMermaidOptions, ], ], diff --git a/web/src/elements/ak-mdx/styles.css b/web/src/elements/ak-mdx/styles.css index 025074820d..7db3238078 100644 --- a/web/src/elements/ak-mdx/styles.css +++ b/web/src/elements/ak-mdx/styles.css @@ -59,21 +59,6 @@ pre:has(.hljs) { padding: var(--pf-global--spacer--md); } -svg[id^="mermaid-svg-"] { - .rect { - fill: var( - --ak-mermaid-box-background-color, - var(--pf-global--BackgroundColor--light-300) - ) !important; - } - - .messageText { - stroke-width: 4; - fill: var(--ak-mermaid-message-text) !important; - paint-order: stroke; - } -} - ak-alert + :is(h2, p) { padding-top: var(--pf-global--spacer--md); } @@ -81,19 +66,7 @@ ak-alert + :is(h2, p) { /* #region Dark Theme */ :host([theme="dark"]) { - --ak-mermaid-message-text: var(--ak-dark-foreground); - --ak-mermaid-box-background-color: var(--ak-dark-background-lighter); --ak-table-stripe-background: var(--pf-global--BackgroundColor--dark-200); - - svg[id^="mermaid-svg-"] { - line[class^="messageLine"] { - /* - Mermaid's support for dynamic palette changes leaves a lot to be desired. - This is a workaround to keep content readable while not breaking the rest of the theme. - */ - filter: invert(1) !important; - } - } } /* #endregion */ diff --git a/web/src/elements/mermaid/mermaid.css b/web/src/elements/mermaid/mermaid.css new file mode 100644 index 0000000000..4e66674c8a --- /dev/null +++ b/web/src/elements/mermaid/mermaid.css @@ -0,0 +1,59 @@ +/* svg[id^="mermaid-svg-"] { */ +/* &.flowchart { + .edgeLabel .label { + padding: 4px 10px; + border-radius: 4px; + background: rgba(0, 0, 0, 0.55); + color: var(--ak-foreground, #fff); + } + } */ + +.flowchart { + foreignObject:has(.edgeLabel) { + display: flex; + align-items: center; + justify-content: center; + overflow: visible; + } + + .edgeLabel, + .edgeLabel .labelBkg { + background-color: transparent; + display: flex !important; + } + + .edgeLabel > span, + .labelBkg > span.edgeLabel { + margin-inline: auto; + max-width: max-content; + padding: 3px 12px; + border-radius: 6px; + white-space: nowrap; + } + + .edgeLabel { + background-color: var(--pf-global--palette--gold-200) !important; + border: 1px solid var(--pf-global--palette--gold-500) !important; + } +} + +svg[id^="mermaid-svg-"] { + & > .rect { + fill: color-mix(var(--pf-global--palette--gold-100), transparent 95%); + stroke: var(--pf-global--palette--gold-100); + stroke-width: 1; + } + + .messageText { + fill: var(--pf-global--Color--100) !important; + } + + .messageLine0 { + stroke: var(--pf-global--palette--purple-300) !important; + } + + [id$="-arrowhead"] path { + fill: var(--pf-global--palette--purple-300) !important; + stroke: var(--pf-global--palette--purple-300) !important; + } +} diff --git a/web/src/elements/mermaid/theme.ts b/web/src/elements/mermaid/theme.ts new file mode 100644 index 0000000000..e2db5ae298 --- /dev/null +++ b/web/src/elements/mermaid/theme.ts @@ -0,0 +1,164 @@ +import type { MermaidConfig } from "mermaid"; + +/** + * Resolves PatternFly CSS custom properties into concrete hex colors and maps + * them onto Mermaid's `themeVariables` keyset. + * + * @remarks + * + * Colors are parsed through a 1x1 canvas so that any valid CSS color form + * (named, rgb/rgba, hsl, or a `var()` chain) collapses to a hex string Mermaid + * can consume. Fully transparent values resolve to `"transparent"`. + * + * PatternFly 4 handles light/dark theming at the token level, so a single token + * set resolves correctly under either theme — no per-theme branching needed. + */ +export class MermaidThemeAdapter { + canvas = new OffscreenCanvas(1, 1); + ctx = this.canvas.getContext("2d"); + + constructor(protected computedStyle: CSSStyleDeclaration) {} + + /** + * Resolve a CSS custom property to a hex color string. + * + * @param cssProperty The CSS custom property name to read. + * @param fallback Color used when the property is unset or empty. + * + * @returns A hex color code string, or `"transparent"` for fully transparent values. + */ + public readHexColorVariable = (cssProperty: string, fallback = "#ff0000"): string => { + if (!this.ctx) { + throw new Error("Could not create canvas context for color parsing"); + } + + this.ctx.clearRect(0, 0, 1, 1); + this.ctx.fillStyle = this.computedStyle.getPropertyValue(cssProperty).trim() || fallback; + this.ctx.fillRect(0, 0, 1, 1); + + const [r, g, b, a] = this.ctx.getImageData(0, 0, 1, 1).data; + + if (a === 0) { + return "transparent"; + } + + // eslint-disable-next-line no-bitwise + return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; + }; + + /** + * Read a surface color, substituting an opaque fallback when the token + * resolves to `transparent`. Node fills must never be see-through. + */ + protected readSurface = (cssProperty: string, fallback: string): string => { + const value = this.readHexColorVariable(cssProperty, fallback); + + return value === "transparent" ? fallback : value; + }; + + /** + * Map PatternFly tokens onto Mermaid's `themeVariables`. + * + * @remarks + * + * Requires `theme: "base"` in the Mermaid config — other built-in themes + * ignore most of these overrides. + */ + public toThemeVariables(darkMode?: boolean): MermaidConfig["themeVariables"] { + const { readHexColorVariable: read, readSurface } = this; + + const surface = readSurface("--pf-global--palette--purple-50", "#ffffff"); + const surfaceAlt = readSurface("--pf-global--palette--blue-50", surface); + const surfaceDark = readSurface("--pf-global--palette--black-200", surfaceAlt); + + const textBase = read("--pf-global--palette--purple-700"); + const textSecondary = read( + darkMode ? "--pf-global--palette--gold-100" : "--pf-global--palette--gold-400", + ); + const border = read( + darkMode ? "--pf-global--palette--purple-300" : "--pf-global--palette--purple-700", + ); + + const primaryBorder = read("--pf-global--palette--purple-400"); + const primaryAccent = read("--pf-global--palette--purple-100"); + const primaryAccentText = read("--pf-global--palette--purple-700"); + + const success = read("--pf-global--success-color--100"); + const danger = read("--pf-global--danger-color--100"); + const warning = read("--pf-global--warning-color--100"); + const info = read("--pf-global--info-color--100"); + + return { + // Base / canvas + background: surface, + mainBkg: surface, + fontFamily: "var(--ak-font-family-sans-serif)", + + // Primary node + primaryColor: surface, + primaryBorderColor: primaryBorder, + primaryTextColor: textBase, + + // Secondary node + secondaryColor: surfaceAlt, + secondaryBorderColor: border, + secondaryTextColor: textBase, + + // Tertiary node + tertiaryColor: surfaceDark, + tertiaryBorderColor: border, + tertiaryTextColor: textBase, + + // Edges / lines / labels + lineColor: textSecondary, + edgeLabelBackground: surface, + titleColor: textBase, + + // Generic node fallbacks + nodeBorder: border, + nodeTextColor: textBase, + + // Clusters / subgraphs + clusterBkg: surfaceDark, + clusterBorder: border, + + // Notes + noteBkgColor: warning, + noteTextColor: textBase, + noteBorderColor: border, + + // Brand accents (classDef / linkStyle) + primaryColorAccent: primaryAccent, + primaryTextColorAccent: primaryAccentText, + + // Status (state / git / quadrant diagrams) + successColor: success, + errorColor: danger, + warningColor: warning, + infoColor: info, + + // Sequence / state actors + actorBkg: surface, + actorBorder: border, + actorTextColor: textBase, + labelBoxBkgColor: surface, + labelTextColor: textBase, + }; + } + + /** + * Semantic accent colors for emitting `linkStyle` / `classDef` directives + * into diagram source (e.g. coloring policy pass/fail edges). + */ + public toAccents() { + const { readHexColorVariable: read } = this; + + return { + success: read("--pf-global--success-color--100"), + danger: read("--pf-global--danger-color--100"), + warning: read("--pf-global--warning-color--100"), + info: read("--pf-global--info-color--100"), + primary: read("--pf-global--palette--purple-100"), + }; + } +} diff --git a/web/src/elements/mermaid/utils.ts b/web/src/elements/mermaid/utils.ts new file mode 100644 index 0000000000..a6192cb826 --- /dev/null +++ b/web/src/elements/mermaid/utils.ts @@ -0,0 +1,76 @@ +import MermaidStyles from "./mermaid.css"; + +import { DOM_PURIFY_STRICT } from "#common/purify"; +import { ResolvedUITheme } from "#common/theme"; + +import { MermaidThemeAdapter } from "#elements/mermaid/theme"; + +import elkLayouts from "@mermaid-js/layout-elk"; +import type { Mermaid, MermaidConfig } from "mermaid"; + +export const DefaultMermaidConfig: Readonly = { + logLevel: "fatal", + startOnLoad: false, + htmlLabels: true, + fontFamily: "var(--ak-font-family-sans-serif)", + layout: "elk", + flowchart: { + curve: "linear", + + nodeSpacing: 25, + rankSpacing: 25, + wrappingWidth: 500, + }, + theme: "base", + securityLevel: "strict", + dompurifyConfig: DOM_PURIFY_STRICT, +}; + +let lastActiveTheme: ResolvedUITheme | null = null; +let mermaid: Mermaid | null = null; + +/** + * Load the Mermaid library and initialize it with the appropriate theme based + * on the provided UI theme. + * + * @remarks + * + * Mermaid is only loaded once and cached for subsequent calls. Note that + * Mermaid is a singleton and does not support multiple instances with different + * configurations. Re-initialization occurs only when the active theme changes. + * + * @param uiTheme The resolved UI theme to derive Mermaid colors from. + * @returns The initialized Mermaid singleton. + */ +export async function loadMermaid(uiTheme: ResolvedUITheme): Promise { + if (!mermaid) { + const mermaidModule = await import("mermaid"); + mermaid = mermaidModule.default; + mermaid.registerLayoutLoaders(elkLayouts); + } + + if (uiTheme && uiTheme === lastActiveTheme) { + return mermaid; + } + + await new Promise((resolve) => requestAnimationFrame(resolve)); + + const computedStyle = getComputedStyle(document.documentElement); + const darkMode = uiTheme === "dark"; + + const themeAdapter = new MermaidThemeAdapter(computedStyle); + const themeVariables = themeAdapter.toThemeVariables(darkMode); + + mermaid.initialize({ + ...DefaultMermaidConfig, + themeVariables: { + ...themeVariables, + }, + darkMode, + themeCSS: String(MermaidStyles), + }); + + lastActiveTheme = uiTheme; + + return mermaid; +} From 453a49d954f5ad28870296f7b7eacb3592a97984 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:54:14 +0200 Subject: [PATCH 04/20] ci: bump taiki-e/install-action from 2.81.7 to 2.81.8 in /.github/actions/setup (#22995) ci: bump taiki-e/install-action in /.github/actions/setup Bumps [taiki-e/install-action](https://github.com/taiki-e/install-action) from 2.81.7 to 2.81.8. - [Release notes](https://github.com/taiki-e/install-action/releases) - [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/install-action/compare/56545b37b57562edd73171cb6c62cc509db4c34e...0631aa6515c7d545823c67cfae7ef4fc7f490154) --- updated-dependencies: - dependency-name: taiki-e/install-action dependency-version: 2.81.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/actions/setup/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 6f49b82019..e14f69ac27 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -64,7 +64,7 @@ runs: rustflags: "" - name: Setup rust dependencies if: ${{ contains(inputs.dependencies, 'rust') }} - uses: taiki-e/install-action@56545b37b57562edd73171cb6c62cc509db4c34e # v2 + uses: taiki-e/install-action@0631aa6515c7d545823c67cfae7ef4fc7f490154 # v2 with: tool: cargo-deny cargo-machete cargo-llvm-cov nextest - name: Setup node (root, web) From bfe104bb69d44203718b3d7d78672fa9497a4c15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:54:18 +0200 Subject: [PATCH 05/20] core: bump which from 8.0.2 to 8.0.3 (#22994) Bumps [which](https://github.com/harryfei/which-rs) from 8.0.2 to 8.0.3. - [Release notes](https://github.com/harryfei/which-rs/releases) - [Changelog](https://github.com/harryfei/which-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/harryfei/which-rs/compare/8.0.2...8.0.3) --- updated-dependencies: - dependency-name: which dependency-version: 8.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b475976d63..4ec2a1c779 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4578,9 +4578,9 @@ dependencies = [ [[package]] name = "which" -version = "8.0.2" +version = "8.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459" +checksum = "c789537cf2f7f55be8e6192f92e464174ee55f91af622777f7f1ceb0dbccd03e" dependencies = [ "libc", ] diff --git a/Cargo.toml b/Cargo.toml index 02f085538f..520f596bac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -113,7 +113,7 @@ tracing-subscriber = { version = "= 0.3.23", features = [ ] } url = "= 2.5.8" uuid = { version = "= 1.23.2", features = ["serde", "v4"] } -which = "= 8.0.2" +which = "= 8.0.3" ak-axum = { package = "authentik-axum", version = "2026.8.0-rc1", path = "./packages/ak-axum" } ak-client = { package = "authentik-client", version = "2026.8.0-rc1", path = "./packages/client-rust" } From 4889d047f0041b84f34e67aad338fa13091475c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:54:22 +0200 Subject: [PATCH 06/20] core: bump uvicorn[standard] from 0.48.0 to 0.49.0 (#22993) Bumps [uvicorn[standard]](https://github.com/Kludex/uvicorn) from 0.48.0 to 0.49.0. - [Release notes](https://github.com/Kludex/uvicorn/releases) - [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md) - [Commits](https://github.com/Kludex/uvicorn/compare/0.48.0...0.49.0) --- updated-dependencies: - dependency-name: uvicorn[standard] dependency-version: 0.49.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pyproject.toml | 2 +- uv.lock | 33 ++++++++++++++++++++------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index aeca2ac862..11d4b94bf3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,7 +66,7 @@ dependencies = [ "ua-parser==1.0.2", "unidecode==1.4.0", "urllib3<3", - "uvicorn[standard]==0.48.0", + "uvicorn[standard]==0.49.0", "watchdog==6.0.0", "webauthn==2.7.1", "wsproto==1.3.2", diff --git a/uv.lock b/uv.lock index 78ff68f75f..c114a48104 100644 --- a/uv.lock +++ b/uv.lock @@ -422,7 +422,7 @@ requires-dist = [ { name = "ua-parser", specifier = "==1.0.2" }, { name = "unidecode", specifier = "==1.4.0" }, { name = "urllib3", specifier = "<3" }, - { name = "uvicorn", extras = ["standard"], specifier = "==0.48.0" }, + { name = "uvicorn", extras = ["standard"], specifier = "==0.49.0" }, { name = "watchdog", specifier = "==6.0.0" }, { name = "webauthn", specifier = "==2.7.1" }, { name = "wsproto", specifier = "==1.3.2" }, @@ -1812,17 +1812,24 @@ wheels = [ [[package]] name = "httptools" -version = "0.7.1" +version = "0.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/e5/d471fcb0e14523fe1c3f4ba58ca52480e7bd70ad7109a3846bc75892f7fb/httptools-0.8.0.tar.gz", hash = "sha256:6b2a32f18d97e16e90827d7a819ffa8dbd8cc245fc4e1fa9d1095b54ef4bd999", size = 271342, upload-time = "2026-05-25T22:17:48.841Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/50/9d095fcbb6de2d523e027a2f304d4551855c2f46e0b82befd718b8b20056/httptools-0.7.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c08fe65728b8d70b6923ce31e3956f859d5e1e8548e6f22ec520a962c6757270", size = 203619, upload-time = "2025-10-10T03:54:54.321Z" }, - { url = "https://files.pythonhosted.org/packages/07/f0/89720dc5139ae54b03f861b5e2c55a37dba9a5da7d51e1e824a1f343627f/httptools-0.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7aea2e3c3953521c3c51106ee11487a910d45586e351202474d45472db7d72d3", size = 108714, upload-time = "2025-10-10T03:54:55.163Z" }, - { url = "https://files.pythonhosted.org/packages/b3/cb/eea88506f191fb552c11787c23f9a405f4c7b0c5799bf73f2249cd4f5228/httptools-0.7.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0e68b8582f4ea9166be62926077a3334064d422cf08ab87d8b74664f8e9058e1", size = 472909, upload-time = "2025-10-10T03:54:56.056Z" }, - { url = "https://files.pythonhosted.org/packages/e0/4a/a548bdfae6369c0d078bab5769f7b66f17f1bfaa6fa28f81d6be6959066b/httptools-0.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df091cf961a3be783d6aebae963cc9b71e00d57fa6f149025075217bc6a55a7b", size = 470831, upload-time = "2025-10-10T03:54:57.219Z" }, - { url = "https://files.pythonhosted.org/packages/4d/31/14df99e1c43bd132eec921c2e7e11cda7852f65619bc0fc5bdc2d0cb126c/httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f084813239e1eb403ddacd06a30de3d3e09a9b76e7894dcda2b22f8a726e9c60", size = 452631, upload-time = "2025-10-10T03:54:58.219Z" }, - { url = "https://files.pythonhosted.org/packages/22/d2/b7e131f7be8d854d48cb6d048113c30f9a46dca0c9a8b08fcb3fcd588cdc/httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7347714368fb2b335e9063bc2b96f2f87a9ceffcd9758ac295f8bbcd3ffbc0ca", size = 452910, upload-time = "2025-10-10T03:54:59.366Z" }, - { url = "https://files.pythonhosted.org/packages/53/cf/878f3b91e4e6e011eff6d1fa9ca39f7eb17d19c9d7971b04873734112f30/httptools-0.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:cfabda2a5bb85aa2a904ce06d974a3f30fb36cc63d7feaddec05d2050acede96", size = 88205, upload-time = "2025-10-10T03:55:00.389Z" }, + { url = "https://files.pythonhosted.org/packages/1a/12/fa3fbf5f9517b273edea2dc982aa82a8c634091e67c590792b729017bc6f/httptools-0.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:de242a49b5d18e0a8776e654e9f6bf6d89f3875a5c35b425a0e7ce940feb3fd6", size = 206183, upload-time = "2026-05-25T22:17:24.004Z" }, + { url = "https://files.pythonhosted.org/packages/30/fc/5e7c4cb443370f2090a3aba0453a07384d29ff66b7435bb90e77e1037599/httptools-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:159e9ab5f701ccd42e555a12f1ad8ff69702910fc1c996cf2bb66e5fcb7a231b", size = 112079, upload-time = "2026-05-25T22:17:25.216Z" }, + { url = "https://files.pythonhosted.org/packages/ba/53/771bd891eb0f236f32145d6a1775777ec85745f3cc983a1f23d1a3b8ddfe/httptools-0.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c4a9f1707e4823d54dfec6c33fa3697d302aed536ed352a7ebb5a061ddb869d0", size = 481596, upload-time = "2026-05-25T22:17:26.186Z" }, + { url = "https://files.pythonhosted.org/packages/62/42/94e15bc68ce3d423243c45d7f1b0c7561f13844f97dc52ae23182fb65628/httptools-0.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d76ad7b951387e3632c8716a9bb03ac5b45c5f16119aa409db0459520887944e", size = 480865, upload-time = "2026-05-25T22:17:27.542Z" }, + { url = "https://files.pythonhosted.org/packages/1c/7c/fe2980fc03723272e30f135b62360b075f513dfe7cc73aef36c7f04012bd/httptools-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a3b7387147361c3fd47a0bde763c5c91b5b4cd4dc9989b8ece84ff436c99843b", size = 463189, upload-time = "2026-05-25T22:17:28.546Z" }, + { url = "https://files.pythonhosted.org/packages/15/1b/47fc5fff68acd1bfa20b4734059c9a06cadb88119dcd5258b5b0d21d91c8/httptools-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f256d6ce930c52ca1cb2a960b7da03548c454e7d28b06059ad41bfe789036ce0", size = 466610, upload-time = "2026-05-25T22:17:29.816Z" }, + { url = "https://files.pythonhosted.org/packages/60/bd/07b13c93ffd9bec9546e0d43f8e19378dd696dbd278511406bc07371ef1f/httptools-0.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:19d1ee275bb59ba2643ba9a3a1e51cc0c788caf2b8df506368e03f56fdd08527", size = 92705, upload-time = "2026-05-25T22:17:31.133Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c4/121648f68ce066d7bd762d6b6d97e620847642d38d54f3d90ff11d947629/httptools-0.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:de1ed58a974e75d56560acc7e7fed01a454994429456f65209789992e41f2568", size = 215023, upload-time = "2026-05-25T22:17:32.401Z" }, + { url = "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e93c227b595c6926c1acee96891dd9da4be338cfbe82e5cd3bb9d8dd7dc4ac0b", size = 117405, upload-time = "2026-05-25T22:17:33.742Z" }, + { url = "https://files.pythonhosted.org/packages/fc/37/fccd705f795386bb05bf413012fecff2a33e5aa8c2f069096de3e9fd8702/httptools-0.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2a021c3a8e65cc125390d72f59b968afca3bdcaff25bd67965e0a055a14946ca", size = 558497, upload-time = "2026-05-25T22:17:34.732Z" }, + { url = "https://files.pythonhosted.org/packages/bd/39/f172e8003576de35f5ba77ff417cf0e34429d35dc014deef15afa337a72c/httptools-0.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48774d39cbb70e2b1f71f88852a3087ae1d3a1eb80482bb48c13067ab080c14f", size = 571585, upload-time = "2026-05-25T22:17:35.813Z" }, + { url = "https://files.pythonhosted.org/packages/3e/b9/f5564760af99f3dbbf3f9104dc00e5da27e96cf433c6bdcf77617f70bf3f/httptools-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:88eead8ec8680a9f146c655bc88445a325bd7921cfd8194c7337e9467282427d", size = 543297, upload-time = "2026-05-25T22:17:37.08Z" }, + { url = "https://files.pythonhosted.org/packages/99/67/8d9f2c313618e161b82f3873188e7196126da1d6e29688df40eb3997c77a/httptools-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2c032fa028f46871ec7e1fc59fc15e8023eab3e6bbe6ece786a1611719a5d081", size = 539535, upload-time = "2026-05-25T22:17:38.032Z" }, + { url = "https://files.pythonhosted.org/packages/48/63/b906c01e53f50d432c0defe43ce52764a111dc1bdd028bafbeb54dcfd008/httptools-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:384c17174464c8e873398b7af24f0b1f44d992c820328413951a625323155d77", size = 108209, upload-time = "2026-05-25T22:17:39.473Z" }, ] [[package]] @@ -3853,15 +3860,15 @@ socks = [ [[package]] name = "uvicorn" -version = "0.48.0" +version = "0.49.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e6/bf/f6544ba992ddb9a6077343a576f9844f7f8f06ab819aefd00206e9255f18/uvicorn-0.48.0.tar.gz", hash = "sha256:a5504207195d08c2511bf9125ede5ac4a4b71725d519e758d01dcf0bc2d31c37", size = 91074, upload-time = "2026-05-24T12:08:41.925Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/1f/fa18009dea8469069cca78a4e877a008ab78f08b064bfc9ab891579077ff/uvicorn-0.49.0.tar.gz", hash = "sha256:ebf4271aa580d9de97f93192d4595176df6e91f9aae919ca73e4fc07df1e66a3", size = 91284, upload-time = "2026-06-03T22:01:30.448Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/be/72532be3da7acc5fdfbccdb95215cd04f995a0886532a5b423f929cda4cc/uvicorn-0.48.0-py3-none-any.whl", hash = "sha256:48097851328b87ec36117d3d575234519eb58c2b22d79666e9bbc6c49a761dad", size = 71410, upload-time = "2026-05-24T12:08:40.258Z" }, + { url = "https://files.pythonhosted.org/packages/88/fa/e1388bbcf24ef3274f45c0c1c7b501fd14971037c1b6ee23610553307497/uvicorn-0.49.0-py3-none-any.whl", hash = "sha256:ba3d14c3ee7e41c6c654c46c9eb489d33213cdd30aa1696eab1374337c13f68f", size = 71376, upload-time = "2026-06-03T22:01:29.037Z" }, ] [package.optional-dependencies] From 798bc77f427ce69d26d1cc70090136b92781e3e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:54:27 +0200 Subject: [PATCH 07/20] core: bump goauthentik/fips-python from `ede0a00` to `94d8805` in /lifecycle/container (#22992) core: bump goauthentik/fips-python in /lifecycle/container Bumps goauthentik/fips-python from `ede0a00` to `94d8805`. --- updated-dependencies: - dependency-name: goauthentik/fips-python dependency-version: 3.14.5-slim-trixie-fips dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- lifecycle/container/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lifecycle/container/Dockerfile b/lifecycle/container/Dockerfile index 3573c7d79c..8856c1b103 100644 --- a/lifecycle/container/Dockerfile +++ b/lifecycle/container/Dockerfile @@ -118,7 +118,7 @@ RUN cat /root/.rustup/settings.toml # Stage: Download uv FROM ghcr.io/astral-sh/uv:0.11.19@sha256:b46b03ddfcfbf8f547af7e9eaefdf8a39c8cebcba7c98858d3162bd28cf536f6 AS uv # Stage: Base python image -FROM ghcr.io/goauthentik/fips-python:3.14.5-slim-trixie-fips@sha256:ede0a006a873bfd3e66fd0e56827bc8e46ea75341e1a6a35dae6edd6ad6be691 AS python-base +FROM ghcr.io/goauthentik/fips-python:3.14.5-slim-trixie-fips@sha256:94d880542ff5e74bd50b874680fd68a04fe6bb34b7f25e8a081b62b7e1ae6dc3 AS python-base ENV VENV_PATH="/ak-root/.venv" \ PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \ From 4881c3f337c017974721ab7d09437878ebfab137 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:54:30 +0200 Subject: [PATCH 08/20] core: bump astral-sh/uv from 0.11.19 to 0.11.20 in /lifecycle/container (#22991) Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.11.19 to 0.11.20. - [Release notes](https://github.com/astral-sh/uv/releases) - [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/uv/compare/0.11.19...0.11.20) --- updated-dependencies: - dependency-name: astral-sh/uv dependency-version: 0.11.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- lifecycle/container/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lifecycle/container/Dockerfile b/lifecycle/container/Dockerfile index 8856c1b103..aaee9343f7 100644 --- a/lifecycle/container/Dockerfile +++ b/lifecycle/container/Dockerfile @@ -116,7 +116,7 @@ RUN --mount=type=bind,target=rust-toolchain.toml,src=rust-toolchain.toml \ RUN cat /root/.rustup/settings.toml # Stage: Download uv -FROM ghcr.io/astral-sh/uv:0.11.19@sha256:b46b03ddfcfbf8f547af7e9eaefdf8a39c8cebcba7c98858d3162bd28cf536f6 AS uv +FROM ghcr.io/astral-sh/uv:0.11.20@sha256:eaa5f1a3305307aaf9e67fe2bbba1d85ebbb2d8a63bce23af21797bfafbe0f8b AS uv # Stage: Base python image FROM ghcr.io/goauthentik/fips-python:3.14.5-slim-trixie-fips@sha256:94d880542ff5e74bd50b874680fd68a04fe6bb34b7f25e8a081b62b7e1ae6dc3 AS python-base From 9cc9cac13b083f554dae150b8257a3a909a2f11a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:54:35 +0200 Subject: [PATCH 09/20] lifecycle/aws: bump aws-cdk from 2.1125.0 to 2.1126.0 in /lifecycle/aws (#22990) Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1125.0 to 2.1126.0. - [Release notes](https://github.com/aws/aws-cdk-cli/releases) - [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1126.0/packages/aws-cdk) --- updated-dependencies: - dependency-name: aws-cdk dependency-version: 2.1126.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- lifecycle/aws/package-lock.json | 8 ++++---- lifecycle/aws/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lifecycle/aws/package-lock.json b/lifecycle/aws/package-lock.json index 6dc3577f04..26d15bcf21 100644 --- a/lifecycle/aws/package-lock.json +++ b/lifecycle/aws/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "license": "MIT", "devDependencies": { - "aws-cdk": "^2.1125.0", + "aws-cdk": "^2.1126.0", "cross-env": "^10.1.0" }, "engines": { @@ -25,9 +25,9 @@ "license": "MIT" }, "node_modules/aws-cdk": { - "version": "2.1125.0", - "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1125.0.tgz", - "integrity": "sha512-QAvsE2XQMcyNOjMMqAS7eDADR9t6vcFcMQvhOmtLfDqgfJXSyTkHvzM5zgwZCdJ4FNqWr5Y/zXvL1Cv5ECKXwQ==", + "version": "2.1126.0", + "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1126.0.tgz", + "integrity": "sha512-uNoocb3vCPiAT3j9+SwL6pn/VVggHWBsgC2XpxyhNvYQYt6cE9BM/149GWwtdcwnLrPjnwW1+CV/5nSSh5dV+w==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/lifecycle/aws/package.json b/lifecycle/aws/package.json index 51ec72589c..bc7a5ec52b 100644 --- a/lifecycle/aws/package.json +++ b/lifecycle/aws/package.json @@ -7,7 +7,7 @@ "aws-cfn": "cross-env CI=false cdk synth --version-reporting=false > template.yaml" }, "devDependencies": { - "aws-cdk": "^2.1125.0", + "aws-cdk": "^2.1126.0", "cross-env": "^10.1.0" }, "engines": { From f40c538034c28790ea100d4766c3e5e33927dcc2 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:54:39 +0200 Subject: [PATCH 10/20] translate: Updates for project authentik and language no_NO (#22988) translate: Translate django.po in no_NO 100% translated source file: 'django.po' on 'no_NO'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- locale/no_NO/LC_MESSAGES/django.po | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/locale/no_NO/LC_MESSAGES/django.po b/locale/no_NO/LC_MESSAGES/django.po index b329c081a9..3b01fb6a0f 100644 --- a/locale/no_NO/LC_MESSAGES/django.po +++ b/locale/no_NO/LC_MESSAGES/django.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-05-22 00:36+0000\n" +"POT-Creation-Date: 2026-06-11 00:42+0000\n" "PO-Revision-Date: 2025-12-01 19:09+0000\n" "Last-Translator: Raphael Cancelliere, 2026\n" "Language-Team: Norwegian (Norway) (https://app.transifex.com/authentik/teams/119923/no_NO/)\n" @@ -3692,14 +3692,6 @@ msgstr "Google OAuth-kilde" msgid "Google OAuth Sources" msgstr "Google OAuth-kilder" -#: authentik/sources/oauth/models.py -msgid "Azure AD OAuth Source" -msgstr "Azure AD OAuth-kilde" - -#: authentik/sources/oauth/models.py -msgid "Azure AD OAuth Sources" -msgstr "Azure AD OAuth-kilder" - #: authentik/sources/oauth/models.py msgid "Entra ID OAuth Source" msgstr "Entra ID OAuth-kilde" From 7767075b040177e8224379c4699fef695ceafce1 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:54:43 +0200 Subject: [PATCH 11/20] translate: Updates for project authentik and language hu_HU (#22987) translate: Translate django.po in hu_HU 100% translated source file: 'django.po' on 'hu_HU'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- locale/hu_HU/LC_MESSAGES/django.po | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/locale/hu_HU/LC_MESSAGES/django.po b/locale/hu_HU/LC_MESSAGES/django.po index 601b01c818..384418a924 100644 --- a/locale/hu_HU/LC_MESSAGES/django.po +++ b/locale/hu_HU/LC_MESSAGES/django.po @@ -12,7 +12,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-05-22 00:36+0000\n" +"POT-Creation-Date: 2026-06-11 00:42+0000\n" "PO-Revision-Date: 2025-12-01 19:09+0000\n" "Last-Translator: Gyula Kiss , 2026\n" "Language-Team: Hungarian (Hungary) (https://app.transifex.com/authentik/teams/119923/hu_HU/)\n" @@ -3780,14 +3780,6 @@ msgstr "Google OAuth forrás" msgid "Google OAuth Sources" msgstr "Google OAuth források" -#: authentik/sources/oauth/models.py -msgid "Azure AD OAuth Source" -msgstr "Azure AD OAuth forrás" - -#: authentik/sources/oauth/models.py -msgid "Azure AD OAuth Sources" -msgstr "Azure AD OAuth források" - #: authentik/sources/oauth/models.py msgid "Entra ID OAuth Source" msgstr "Entra ID OAuth forrás" From 21666c8c1c463ceea5e02a6eef44b292dc017304 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:54:48 +0200 Subject: [PATCH 12/20] translate: Updates for project authentik and language fr_FR (#22986) translate: Translate django.po in fr_FR 100% translated source file: 'django.po' on 'fr_FR'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- locale/fr_FR/LC_MESSAGES/django.po | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/locale/fr_FR/LC_MESSAGES/django.po b/locale/fr_FR/LC_MESSAGES/django.po index feb36304fe..55ecc2eab2 100644 --- a/locale/fr_FR/LC_MESSAGES/django.po +++ b/locale/fr_FR/LC_MESSAGES/django.po @@ -15,7 +15,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-05-22 00:36+0000\n" +"POT-Creation-Date: 2026-06-11 00:42+0000\n" "PO-Revision-Date: 2025-12-01 19:09+0000\n" "Last-Translator: Sp P, 2026\n" "Language-Team: French (France) (https://app.transifex.com/authentik/teams/119923/fr_FR/)\n" @@ -3790,14 +3790,6 @@ msgstr "Source d'OAuth Google" msgid "Google OAuth Sources" msgstr "Source d'OAuth Google" -#: authentik/sources/oauth/models.py -msgid "Azure AD OAuth Source" -msgstr "Source d'OAuth Azure AD" - -#: authentik/sources/oauth/models.py -msgid "Azure AD OAuth Sources" -msgstr "Source d'OAuth Azure AD" - #: authentik/sources/oauth/models.py msgid "Entra ID OAuth Source" msgstr "Source d'OAuth Entra ID" From 884904e16fc5424d1bf314c6794ad0c424a926e3 Mon Sep 17 00:00:00 2001 From: Dewi Roberts Date: Thu, 11 Jun 2026 15:29:43 +0100 Subject: [PATCH 13/20] website/docs: additional scim provider docs (#22135) * Add create scim provider doc, add info about oauth interactive mode, update sidebar * Spelling --------- Co-authored-by: Dominic R --- .../providers/scim/create-scim-provider.md | 71 +++++++++++++++++++ .../add-secure-apps/providers/scim/index.md | 20 ++---- website/docs/sidebar.mjs | 10 ++- 3 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 website/docs/add-secure-apps/providers/scim/create-scim-provider.md diff --git a/website/docs/add-secure-apps/providers/scim/create-scim-provider.md b/website/docs/add-secure-apps/providers/scim/create-scim-provider.md new file mode 100644 index 0000000000..7258c50f62 --- /dev/null +++ b/website/docs/add-secure-apps/providers/scim/create-scim-provider.md @@ -0,0 +1,71 @@ +--- +title: Create a SCIM provider +--- + +## Create a SCIM provider with token authentication + +To create a provider along with a corresponding application, navigate to **Applications** > **Applications** and click **New Application**. We recommend this combined approach for most common use cases. Alternatively, you can use the legacy method to solely create the provider by navigating to **Applications** > **Providers** and clicking **New Provider**. + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Applications** > **Applications** and click **New Application** to create an application and provider pair. +3. On the **Application** page, define the application settings, and then click **Next**. +4. Select **SCIM** as the **Provider Type**, and then click **Next**. +5. On the **Configure Provider** page, provide the configuration settings, and then click **Next**. +6. On the **Configure Bindings** page, click **Next**. +7. Click **Create** to create both the application and the provider. + +### Set the SCIM provider as a backchannel provider for the application + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Applications** > **Applications** and click the edit icon of the new SCIM application. +3. Click the plus icon (+) next to **Backchannel providers**. +4. Select the new SCIM provider, and then click **Confirm**. +5. Click **Save changes**. + +## Create a SCIM provider with OAuth authentication + +There are 3 required steps to creating a SCIM provider: + +1. [Create an OAuth source](#create-an-oauth-source) +2. [Create a SCIM application and provider](#create-a-scim-application-and-provider) +3. [Set the SCIM provider as a backchannel provider for the application](#set-the-scim-provider-as-a-backchannel-provider-for-the-application) + +If using OAuth (Interactive) mode, you will also need to: + +4. [Provide admin authorization](#provide-admin-authorization-oauth-interactive-mode-only) + +### Create an OAuth source + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Directory** > **Federation and Social login** and click **New Source**. +3. Select **OpenID OAuth Source** as the **Source type**. +4. On the **OpenID OAuth Source Details** page, provide the configuration settings provided by the SCIM endpoint that you are provisioning to, and then click **Create**. + +### Create a SCIM application and provider + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Applications** > **Applications** and click **New Application** to create an application and provider pair. +3. On the **Application** page, define the application settings, and then click **Next**. +4. Select **SCIM** as the **Provider Type**, and then click **Next**. +5. On the **Configure Provider** page, configure the required settings. Set **Authentication mode** to the desired OAuth option, select the **OAuth source** you created in the previous section, and then click **Next**. +6. On the **Configure Bindings** page, click **Next**. +7. Click **Create** to create both the application and the provider. + +### Set the SCIM provider as a backchannel provider for the application + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Applications** > **Applications** and click the edit icon of the new SCIM application. +3. Click the plus icon (+) next to **Backchannel providers**. +4. Select the new SCIM provider, and then click **Confirm**. +5. Click **Save changes**. + +### Provide admin authorization (OAuth Interactive mode only) + +If you selected **OAuth (Interactive)** as the **Authentication mode** for the SCIM provider, you will need to authorize the initial OAuth connection. + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Applications** > **Providers** and click the name of the new SCIM provider. +3. Next to **OAuth Status**, click **(Re-)Authenticate**. +4. You should be redirected to the SCIM endpoint that you are provisioning to for authentication. +5. Once authenticated, you should be redirected back to authentik. If successful, **OAuth Status** should now show as **Authenticated**. + This step is only required when initially configuring the SCIM provider; subsequent authentications will be automatic. diff --git a/website/docs/add-secure-apps/providers/scim/index.md b/website/docs/add-secure-apps/providers/scim/index.md index 0c516b745c..12f1ef9cc2 100644 --- a/website/docs/add-secure-apps/providers/scim/index.md +++ b/website/docs/add-secure-apps/providers/scim/index.md @@ -8,13 +8,7 @@ A SCIM provider requires a SCIM base URL for the endpoint and an authentication SCIM providers in authentik always serve as [backchannel providers](../../applications/manage_apps.mdx#backchannel-providers), which are used in addition to the main provider that supplies SSO authentication. A backchannel provider is used for an application that requires backend authentication, directory synchronization, or other additional authentication needs. -## Set up a SCIM provider - -Many applications use SCIM together with another SSO protocol such as OAuth/OIDC or SAML. For example, you can create an application and provider pair for Slack by using SAML for authentication and SCIM for provisioning. For this setup, use the following workflow: - -1. [Create](../../applications/manage_apps.mdx#create-an-application-and-provider-pair) the application and provider pair. -2. [Create](../../applications/manage_apps.mdx#backchannel-providers) the SCIM backchannel provider. -3. Edit the application, and in the **Backchannel Providers** field add the SCIM provider that you created. +For instructions on creating a SCIM provider, refer to the [Create a SCIM provider](./create-scim-provider.md) documentation. ## Authentication modes @@ -23,12 +17,6 @@ In authentik, there are two ways to authenticate SCIM requests: - **Static token** provided by the application. This is the default authentication mode. - **OAuth token** that authentik retrieves from a specified source and uses for authentication. -When you create a new SCIM provider, select the **Authentication Mode** that the application supports. - -![Creating a SCIM provider](./scim_oauth.png) - -For either mode, enter the SCIM base **URL** for the endpoint. - ### Static token When the authentication mode is set to **Static token**, authentik sends the token provided by the application with outgoing SCIM requests to authenticate each request. @@ -37,6 +25,12 @@ When the authentication mode is set to **Static token**, authentik sends the tok When you configure a SCIM provider to use OAuth for authentication, authentik generates short-lived tokens through an OAuth flow and sends them to the SCIM endpoint. This offers improved security and control compared with a static token. +authentik supports two types of SCIM OAuth authentication: + +- **Silent OAuth** – The system obtains or refreshes access tokens automatically, without any administrator interaction. This is the typical approach used for ongoing SCIM provisioning. + +- **Interactive OAuth** – During setup, an administrator is required to authorize the connection before the SCIM integration can obtain its initial token. authentik then stores a refresh token, and provisioning then runs in the background without further admin interaction. + You can also add additional token request parameters such as `grant_type`, `subject_token`, or `client_assertion`. **Example**: diff --git a/website/docs/sidebar.mjs b/website/docs/sidebar.mjs index 8ee5468744..d32fe47197 100644 --- a/website/docs/sidebar.mjs +++ b/website/docs/sidebar.mjs @@ -254,7 +254,15 @@ const items = [ "add-secure-apps/providers/saml/saml_single_logout", ], }, - "add-secure-apps/providers/scim/index", + { + type: "category", + label: "SCIM Provider", + link: { + type: "doc", + id: "add-secure-apps/providers/scim/index", + }, + items: ["add-secure-apps/providers/scim/create-scim-provider"], + }, { type: "category", label: "SSF Provider", From 978abbd734af6ac3e3a1beaf562fa91b028fba11 Mon Sep 17 00:00:00 2001 From: Connor Peshek Date: Thu, 11 Jun 2026 10:01:24 -0500 Subject: [PATCH 14/20] website/integrations: add post logout to audiobookshelf (#22999) website/integrations: add post logout to abs Co-authored-by: Dewi Roberts --- website/integrations/media/audiobookshelf/index.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/website/integrations/media/audiobookshelf/index.md b/website/integrations/media/audiobookshelf/index.md index eb85cec8c3..b99aeebec9 100644 --- a/website/integrations/media/audiobookshelf/index.md +++ b/website/integrations/media/audiobookshelf/index.md @@ -33,9 +33,10 @@ To support the integration of Audiobookshelf with authentik, you need to create - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Add two `Strict` redirect URIs: - - `https://audiobookshelf.company/auth/openid/callback` - - `https://audiobookshelf.company/auth/openid/mobile-redirect` + - Add three **Redirect URIs**: + - `Strict` `Authorization` `https://audiobookshelf.company/auth/openid/callback` + - `Strict` `Authorization` `https://audiobookshelf.company/auth/openid/mobile-redirect` + - `Strict` `Post Logout` `https://audiobookshelf.company/login` - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. @@ -53,6 +54,7 @@ To support the integration of Audiobookshelf with authentik, you need to create - **Token URL**: `https://authentik.company/application/o/token/` - **User Info URL**: `https://authentik.company/application/o/userinfo/` - **JWKS URL**: `https://authentik.company/application/o//jwks/` + - **Logout URL**: `https://auth.yoursite.com/application/o//end-session/` - **Signing Algorithm**: `RS256` - **Allow Mobile Redirect URLs**: `https://audiobookshelf.company/auth/openid/mobile-redirect` - **Match existing users by**: `username` From b12416a413609d4fe5a8f83aa240f66b484eb64b Mon Sep 17 00:00:00 2001 From: Connor Peshek Date: Thu, 11 Jun 2026 10:03:04 -0500 Subject: [PATCH 15/20] website/integrations: add kavita (#23000) * website/integrations: add kavita * add missing dashes * Update index.md Signed-off-by: Dewi Roberts --------- Signed-off-by: Dewi Roberts Co-authored-by: Dewi Roberts --- website/integrations/media/kavita/index.md | 65 ++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 website/integrations/media/kavita/index.md diff --git a/website/integrations/media/kavita/index.md b/website/integrations/media/kavita/index.md new file mode 100644 index 0000000000..84854af511 --- /dev/null +++ b/website/integrations/media/kavita/index.md @@ -0,0 +1,65 @@ +--- +title: Integrate with Kavita +sidebar_label: Kavita +support_level: community +--- + +## What is Kavita? + +> Kavita is a self-hosted digital library and reading server for manga, comics, books, and other digital media, with support for organizing collections and reading in the browser. +> +> -- https://www.kavitareader.com/ + +## Preparation + +The following placeholders are used in this guide: + +- `kavita.company` is the FQDN of the Kavita installation. +- `authentik.company` is the FQDN of the authentik installation. + +:::info +This documentation lists only the settings that you need to change from their default values. Be aware that any changes other than those explicitly mentioned in this guide could cause issues accessing your application. +::: + +## authentik configuration + +To support the integration of Kavita with authentik, you need to create an application/provider pair in authentik. + +### Create an application and provider in authentik + +1. Log in to authentik as an administrator and open the authentik Admin interface. +2. Navigate to **Applications** > **Applications** and click **New Application** to open the application wizard. + - **Application**: provide a descriptive name, an optional group for the type of application, the policy engine mode, and optional UI settings. + - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. + - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. + - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://kavita.company/signin-oidc` + - Add a **Redirect URI** of type `Strict` `Post Logout` as `https://kavita.company/signout-callback-oidc` + - **Logout URI**: `https://kavita.company/signout-oidc` + - **Logout Method**: `Front-channel` + - Select any available signing key. + - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. + +3. Click **Submit** to save the new application and provider. + +## Kavita configuration + +1. Log in to Kavita as an administrator. +2. Navigate to **Settings** > **OpenID Connect**. +3. Configure the following settings: + - **Authority**: `https://authentik.company/application/o//` + - **Client Id**: enter the Client ID from authentik. + - **Secret**: enter the Client Secret from authentik. + - **Provision Accounts**: enable this setting to automatically create Kavita accounts for users who log in through authentik. + - **Require Verified Emails**: disable this setting. +4. Click **Save**. + +Restart your Kavita instance for these changes to take effect. + +## Configuration verification + +To confirm that authentik is properly configured with Kavita, log out of Kavita and then log back in using the **Login with SSO** option. You should be redirected to authentik for authentication and then redirected back to Kavita as a logged-in user. + +## Resources + +- [Kavita OpenID Connect documentation](https://wiki.kavitareader.com/guides/admin-settings/open-id-connect/) From 80e7dd0c621e11fffa1046b3d082b53debffb6a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 17:43:07 +0200 Subject: [PATCH 16/20] web: bump @goauthentik/tsconfig from 1.0.9 to 2.0.0 in /web/packages/core in the goauthentik group across 1 directory (#22996) * web: bump @goauthentik/tsconfig Bumps the goauthentik group with 1 update in the /web/packages/core directory: [@goauthentik/tsconfig](https://github.com/goauthentik/authentik/tree/HEAD/packages/tsconfig). Updates `@goauthentik/tsconfig` from 1.0.9 to 2.0.0 - [Release notes](https://github.com/goauthentik/authentik/releases) - [Commits](https://github.com/goauthentik/authentik/commits/HEAD/packages/tsconfig) --- updated-dependencies: - dependency-name: "@goauthentik/tsconfig" dependency-version: 2.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: goauthentik ... Signed-off-by: dependabot[bot] * sigh Signed-off-by: Jens Langhammer --------- Signed-off-by: dependabot[bot] Signed-off-by: Jens Langhammer Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jens Langhammer --- web/package-lock.json | 12 +++++++++++- web/packages/core/package.json | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 3c30a7932e..a599d9befe 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -20936,7 +20936,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "@goauthentik/tsconfig": "^1.0.9", + "@goauthentik/tsconfig": "^2.0.0", "@types/node": "^25.7.0", "@types/semver": "^7.7.1", "semver": "^7.7.4", @@ -20947,6 +20947,16 @@ "npm": ">=11.14.1" } }, + "packages/core/node_modules/@goauthentik/tsconfig": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@goauthentik/tsconfig/-/tsconfig-2.0.0.tgz", + "integrity": "sha512-HiU/U9cO4Aaik3VjUHu/3PjD0m2nhIJXlENW1kbfVRFBaqAw//9UuHIel2E3vgwyua93fht36cBb8itZVsG1Vg==", + "license": "MIT", + "engines": { + "node": ">=24", + "npm": ">=11.14.1" + } + }, "packages/core/node_modules/semver": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", diff --git a/web/packages/core/package.json b/web/packages/core/package.json index df396010c1..5b734d756a 100644 --- a/web/packages/core/package.json +++ b/web/packages/core/package.json @@ -44,7 +44,7 @@ } }, "dependencies": { - "@goauthentik/tsconfig": "^1.0.9", + "@goauthentik/tsconfig": "^2.0.0", "@types/node": "^25.7.0", "@types/semver": "^7.7.1", "semver": "^7.7.4", From fc8424ac50cb92c36bede7c8a67b6981e7978f51 Mon Sep 17 00:00:00 2001 From: Dominic R Date: Thu, 11 Jun 2026 12:15:21 -0400 Subject: [PATCH 17/20] stages/captcha: add Cap and JSON verification support (#22373) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * stages/captcha: add Cap and JSON verification support Add a configurable verification request content type so CAPTCHA providers can use either form-encoded or JSON token verification. Add Cap as a preset and flow controller, including module-script loading, interactive widget handling, generated API/client types, tests, and docs. * web/admin: clarify Cap captcha configuration Treat the Cap endpoint as a form-only alias for the existing public key field and document Cap alongside the other CAPTCHA providers. Agent-thread: https://sdko.org/internal/threads/019e737a-314e-72d0-98ae-201cb855df3a A7k-product: product A7k-product-repo: 2 Co-authored-by: Agent * stages/captcha: prefer self-hosted Cap widget URL Default the Cap provider guidance to the self-hosted widget asset and keep CDN usage pinned to reviewed releases. Agent-thread: https://sdko.org/internal/thr/ak/019ead31-2435-7e12-b933-e873155d6894 A7k-product: product A7k-product-repo: 2 Co-authored-by: Agent * floating --------- Co-authored-by: Agent Co-authored-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com> --- authentik/stages/captcha/api.py | 1 + .../0005_captchastage_request_content_type.py | 24 +++ authentik/stages/captcha/models.py | 11 ++ authentik/stages/captcha/stage.py | 20 ++- authentik/stages/captcha/tests.py | 35 +++- blueprints/schema.json | 8 + packages/client-ts/src/models/CaptchaStage.ts | 16 ++ .../src/models/CaptchaStageRequest.ts | 17 ++ .../src/models/PatchedCaptchaStageRequest.ts | 17 ++ .../src/models/RequestContentTypeEnum.ts | 58 +++++++ packages/client-ts/src/models/index.ts | 1 + schema.yml | 11 ++ .../admin/stages/captcha/CaptchaStageForm.ts | 149 ++++++++++++++---- web/src/admin/stages/captcha/shared.ts | 85 ++++++++++ web/src/flow/stages/captcha/CaptchaStage.css | 5 + web/src/flow/stages/captcha/CaptchaStage.ts | 26 ++- .../captcha/controllers/CaptchaController.ts | 19 ++- .../flow/stages/captcha/controllers/cap.ts | 61 +++++++ web/src/flow/stages/captcha/shared.ts | 15 +- .../controllers/CaptchaDisplayController.ts | 6 + .../flows-stages/stages/captcha/index.md | 22 ++- 21 files changed, 563 insertions(+), 44 deletions(-) create mode 100644 authentik/stages/captcha/migrations/0005_captchastage_request_content_type.py create mode 100644 packages/client-ts/src/models/RequestContentTypeEnum.ts create mode 100644 web/src/flow/stages/captcha/controllers/cap.ts diff --git a/authentik/stages/captcha/api.py b/authentik/stages/captcha/api.py index cb33ff4d2c..959d30df00 100644 --- a/authentik/stages/captcha/api.py +++ b/authentik/stages/captcha/api.py @@ -17,6 +17,7 @@ class CaptchaStageSerializer(StageSerializer): "private_key", "js_url", "api_url", + "request_content_type", "interactive", "score_min_threshold", "score_max_threshold", diff --git a/authentik/stages/captcha/migrations/0005_captchastage_request_content_type.py b/authentik/stages/captcha/migrations/0005_captchastage_request_content_type.py new file mode 100644 index 0000000000..6c7d24dbe7 --- /dev/null +++ b/authentik/stages/captcha/migrations/0005_captchastage_request_content_type.py @@ -0,0 +1,24 @@ +# Generated by Django 5.2.14 on 2026-05-14 23:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_stages_captcha", "0004_captchastage_interactive"), + ] + + operations = [ + migrations.AddField( + model_name="captchastage", + name="request_content_type", + field=models.TextField( + choices=[ + ("application/x-www-form-urlencoded", "Form encoded"), + ("application/json", "JSON"), + ], + default="application/x-www-form-urlencoded", + ), + ), + ] diff --git a/authentik/stages/captcha/models.py b/authentik/stages/captcha/models.py index fb5a6dac28..776911b91e 100644 --- a/authentik/stages/captcha/models.py +++ b/authentik/stages/captcha/models.py @@ -8,6 +8,13 @@ from rest_framework.serializers import BaseSerializer from authentik.flows.models import Stage +class CaptchaRequestContentType(models.TextChoices): + """Supported request content types for CAPTCHA verification.""" + + FORM = "application/x-www-form-urlencoded", _("Form encoded") + JSON = "application/json", _("JSON") + + class CaptchaStage(Stage): """Verify the user is human using Google's reCaptcha/other compatible CAPTCHA solutions.""" @@ -30,6 +37,10 @@ class CaptchaStage(Stage): js_url = models.TextField(default="https://www.recaptcha.net/recaptcha/api.js") api_url = models.TextField(default="https://www.recaptcha.net/recaptcha/api/siteverify") + request_content_type = models.TextField( + choices=CaptchaRequestContentType.choices, + default=CaptchaRequestContentType.FORM, + ) @property def serializer(self) -> type[BaseSerializer]: diff --git a/authentik/stages/captcha/stage.py b/authentik/stages/captcha/stage.py index 9e582e5614..66b823e7a7 100644 --- a/authentik/stages/captcha/stage.py +++ b/authentik/stages/captcha/stage.py @@ -15,7 +15,7 @@ from authentik.flows.challenge import ( from authentik.flows.stage import ChallengeStageView from authentik.lib.utils.http import get_http_session from authentik.root.middleware import ClientIPMiddleware -from authentik.stages.captcha.models import CaptchaStage +from authentik.stages.captcha.models import CaptchaRequestContentType, CaptchaStage LOGGER = get_logger() PLAN_CONTEXT_CAPTCHA = "captcha" @@ -35,17 +35,23 @@ class CaptchaChallenge(WithUserInfoChallenge): def verify_captcha_token(stage: CaptchaStage, token: str, remote_ip: str, key: str | None = None): """Validate captcha token""" + payload = { + "secret": key or stage.private_key, + "response": token, + "remoteip": remote_ip, + } + body_kwargs = ( + {"json": payload} + if stage.request_content_type == CaptchaRequestContentType.JSON + else {"data": payload} + ) try: response = get_http_session().post( stage.api_url, headers={ - "Content-type": "application/x-www-form-urlencoded", - }, - data={ - "secret": key or stage.private_key, - "response": token, - "remoteip": remote_ip, + "Content-Type": stage.request_content_type, }, + **body_kwargs, ) response.raise_for_status() data = response.json() diff --git a/authentik/stages/captcha/tests.py b/authentik/stages/captcha/tests.py index 41bceb9f43..39a7b4a32e 100644 --- a/authentik/stages/captcha/tests.py +++ b/authentik/stages/captcha/tests.py @@ -10,7 +10,7 @@ from authentik.flows.planner import FlowPlan from authentik.flows.tests import FlowTestCase from authentik.flows.views.executor import SESSION_KEY_PLAN from authentik.lib.generators import generate_id -from authentik.stages.captcha.models import CaptchaStage +from authentik.stages.captcha.models import CaptchaRequestContentType, CaptchaStage from authentik.stages.captcha.stage import ( PLAN_CONTEXT_CAPTCHA_PRIVATE_KEY, PLAN_CONTEXT_CAPTCHA_SITE_KEY, @@ -56,6 +56,39 @@ class TestCaptchaStage(FlowTestCase): ) self.assertEqual(response.status_code, 200) self.assertStageRedirects(response, reverse("authentik_core:root-redirect")) + self.assertEqual( + mock.request_history[0].headers["Content-Type"], + CaptchaRequestContentType.FORM, + ) + self.assertIn("response=PASSED", mock.request_history[0].text) + + @Mocker() + def test_valid_json_content_type(self, mock: Mocker): + """Test valid captcha with JSON verification request""" + self.stage.request_content_type = CaptchaRequestContentType.JSON + self.stage.save() + mock.post( + "https://www.recaptcha.net/recaptcha/api/siteverify", + json={ + "success": True, + "score": 0.5, + }, + ) + plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()]) + session = self.client.session + session[SESSION_KEY_PLAN] = plan + session.save() + response = self.client.post( + reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}), + {"token": "PASSED"}, + ) + self.assertEqual(response.status_code, 200) + self.assertStageRedirects(response, reverse("authentik_core:root-redirect")) + self.assertEqual( + mock.request_history[0].headers["Content-Type"], + CaptchaRequestContentType.JSON, + ) + self.assertEqual(mock.request_history[0].json()["response"], "PASSED") @Mocker() def test_valid_override(self, mock: Mocker): diff --git a/blueprints/schema.json b/blueprints/schema.json index 03bd2a617c..602e676233 100644 --- a/blueprints/schema.json +++ b/blueprints/schema.json @@ -15105,6 +15105,14 @@ "minLength": 1, "title": "Api url" }, + "request_content_type": { + "type": "string", + "enum": [ + "application/x-www-form-urlencoded", + "application/json" + ], + "title": "Request content type" + }, "interactive": { "type": "boolean", "title": "Interactive" diff --git a/packages/client-ts/src/models/CaptchaStage.ts b/packages/client-ts/src/models/CaptchaStage.ts index 2c6b18c9dc..13430ab177 100644 --- a/packages/client-ts/src/models/CaptchaStage.ts +++ b/packages/client-ts/src/models/CaptchaStage.ts @@ -14,6 +14,11 @@ import type { FlowSet } from "./FlowSet"; import { FlowSetFromJSON } from "./FlowSet"; +import type { RequestContentTypeEnum } from "./RequestContentTypeEnum"; +import { + RequestContentTypeEnumFromJSON, + RequestContentTypeEnumToJSON, +} from "./RequestContentTypeEnum"; /** * CaptchaStage Serializer @@ -81,6 +86,12 @@ export interface CaptchaStage { * @memberof CaptchaStage */ apiUrl?: string; + /** + * + * @type {RequestContentTypeEnum} + * @memberof CaptchaStage + */ + requestContentType?: RequestContentTypeEnum; /** * * @type {boolean} @@ -141,6 +152,10 @@ export function CaptchaStageFromJSONTyped(json: any, ignoreDiscriminator: boolea publicKey: json["public_key"], jsUrl: json["js_url"] == null ? undefined : json["js_url"], apiUrl: json["api_url"] == null ? undefined : json["api_url"], + requestContentType: + json["request_content_type"] == null + ? undefined + : RequestContentTypeEnumFromJSON(json["request_content_type"]), interactive: json["interactive"] == null ? undefined : json["interactive"], scoreMinThreshold: json["score_min_threshold"] == null ? undefined : json["score_min_threshold"], @@ -171,6 +186,7 @@ export function CaptchaStageToJSONTyped( public_key: value["publicKey"], js_url: value["jsUrl"], api_url: value["apiUrl"], + request_content_type: RequestContentTypeEnumToJSON(value["requestContentType"]), interactive: value["interactive"], score_min_threshold: value["scoreMinThreshold"], score_max_threshold: value["scoreMaxThreshold"], diff --git a/packages/client-ts/src/models/CaptchaStageRequest.ts b/packages/client-ts/src/models/CaptchaStageRequest.ts index 1c68022168..37792dc7ef 100644 --- a/packages/client-ts/src/models/CaptchaStageRequest.ts +++ b/packages/client-ts/src/models/CaptchaStageRequest.ts @@ -12,6 +12,12 @@ * Do not edit the class manually. */ +import type { RequestContentTypeEnum } from "./RequestContentTypeEnum"; +import { + RequestContentTypeEnumFromJSON, + RequestContentTypeEnumToJSON, +} from "./RequestContentTypeEnum"; + /** * CaptchaStage Serializer * @export @@ -48,6 +54,12 @@ export interface CaptchaStageRequest { * @memberof CaptchaStageRequest */ apiUrl?: string; + /** + * + * @type {RequestContentTypeEnum} + * @memberof CaptchaStageRequest + */ + requestContentType?: RequestContentTypeEnum; /** * * @type {boolean} @@ -101,6 +113,10 @@ export function CaptchaStageRequestFromJSONTyped( privateKey: json["private_key"], jsUrl: json["js_url"] == null ? undefined : json["js_url"], apiUrl: json["api_url"] == null ? undefined : json["api_url"], + requestContentType: + json["request_content_type"] == null + ? undefined + : RequestContentTypeEnumFromJSON(json["request_content_type"]), interactive: json["interactive"] == null ? undefined : json["interactive"], scoreMinThreshold: json["score_min_threshold"] == null ? undefined : json["score_min_threshold"], @@ -129,6 +145,7 @@ export function CaptchaStageRequestToJSONTyped( private_key: value["privateKey"], js_url: value["jsUrl"], api_url: value["apiUrl"], + request_content_type: RequestContentTypeEnumToJSON(value["requestContentType"]), interactive: value["interactive"], score_min_threshold: value["scoreMinThreshold"], score_max_threshold: value["scoreMaxThreshold"], diff --git a/packages/client-ts/src/models/PatchedCaptchaStageRequest.ts b/packages/client-ts/src/models/PatchedCaptchaStageRequest.ts index b616986c41..b2522615bb 100644 --- a/packages/client-ts/src/models/PatchedCaptchaStageRequest.ts +++ b/packages/client-ts/src/models/PatchedCaptchaStageRequest.ts @@ -12,6 +12,12 @@ * Do not edit the class manually. */ +import type { RequestContentTypeEnum } from "./RequestContentTypeEnum"; +import { + RequestContentTypeEnumFromJSON, + RequestContentTypeEnumToJSON, +} from "./RequestContentTypeEnum"; + /** * CaptchaStage Serializer * @export @@ -48,6 +54,12 @@ export interface PatchedCaptchaStageRequest { * @memberof PatchedCaptchaStageRequest */ apiUrl?: string; + /** + * + * @type {RequestContentTypeEnum} + * @memberof PatchedCaptchaStageRequest + */ + requestContentType?: RequestContentTypeEnum; /** * * @type {boolean} @@ -100,6 +112,10 @@ export function PatchedCaptchaStageRequestFromJSONTyped( privateKey: json["private_key"] == null ? undefined : json["private_key"], jsUrl: json["js_url"] == null ? undefined : json["js_url"], apiUrl: json["api_url"] == null ? undefined : json["api_url"], + requestContentType: + json["request_content_type"] == null + ? undefined + : RequestContentTypeEnumFromJSON(json["request_content_type"]), interactive: json["interactive"] == null ? undefined : json["interactive"], scoreMinThreshold: json["score_min_threshold"] == null ? undefined : json["score_min_threshold"], @@ -128,6 +144,7 @@ export function PatchedCaptchaStageRequestToJSONTyped( private_key: value["privateKey"], js_url: value["jsUrl"], api_url: value["apiUrl"], + request_content_type: RequestContentTypeEnumToJSON(value["requestContentType"]), interactive: value["interactive"], score_min_threshold: value["scoreMinThreshold"], score_max_threshold: value["scoreMaxThreshold"], diff --git a/packages/client-ts/src/models/RequestContentTypeEnum.ts b/packages/client-ts/src/models/RequestContentTypeEnum.ts new file mode 100644 index 0000000000..e287dc0fa2 --- /dev/null +++ b/packages/client-ts/src/models/RequestContentTypeEnum.ts @@ -0,0 +1,58 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * authentik + * Making authentication simple. + * + * The version of the OpenAPI document: 2026.8.0-rc1 + * Contact: hello@goauthentik.io + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +/** + * + * @export + */ +export const RequestContentTypeEnum = { + ApplicationXWwwFormUrlencoded: "application/x-www-form-urlencoded", + ApplicationJson: "application/json", + UnknownDefaultOpenApi: "11184809", +} as const; +export type RequestContentTypeEnum = + (typeof RequestContentTypeEnum)[keyof typeof RequestContentTypeEnum]; + +export function instanceOfRequestContentTypeEnum(value: any): boolean { + for (const key in RequestContentTypeEnum) { + if (Object.prototype.hasOwnProperty.call(RequestContentTypeEnum, key)) { + if (RequestContentTypeEnum[key as keyof typeof RequestContentTypeEnum] === value) { + return true; + } + } + } + return false; +} + +export function RequestContentTypeEnumFromJSON(json: any): RequestContentTypeEnum { + return RequestContentTypeEnumFromJSONTyped(json, false); +} + +export function RequestContentTypeEnumFromJSONTyped( + json: any, + ignoreDiscriminator: boolean, +): RequestContentTypeEnum { + return json as RequestContentTypeEnum; +} + +export function RequestContentTypeEnumToJSON(value?: RequestContentTypeEnum | null): any { + return value as any; +} + +export function RequestContentTypeEnumToJSONTyped( + value: any, + ignoreDiscriminator: boolean, +): RequestContentTypeEnum { + return value as RequestContentTypeEnum; +} diff --git a/packages/client-ts/src/models/index.ts b/packages/client-ts/src/models/index.ts index da4090a4cf..3f9fc870ef 100644 --- a/packages/client-ts/src/models/index.ts +++ b/packages/client-ts/src/models/index.ts @@ -713,6 +713,7 @@ export * from "./RelatedRule"; export * from "./Reputation"; export * from "./ReputationPolicy"; export * from "./ReputationPolicyRequest"; +export * from "./RequestContentTypeEnum"; export * from "./Review"; export * from "./ReviewRequest"; export * from "./ReviewerGroup"; diff --git a/schema.yml b/schema.yml index 6a3f2c51c1..f21afc33db 100644 --- a/schema.yml +++ b/schema.yml @@ -36333,6 +36333,8 @@ components: type: string api_url: type: string + request_content_type: + $ref: '#/components/schemas/RequestContentTypeEnum' interactive: type: boolean score_min_threshold: @@ -36378,6 +36380,8 @@ components: api_url: type: string minLength: 1 + request_content_type: + $ref: '#/components/schemas/RequestContentTypeEnum' interactive: type: boolean score_min_threshold: @@ -48260,6 +48264,8 @@ components: api_url: type: string minLength: 1 + request_content_type: + $ref: '#/components/schemas/RequestContentTypeEnum' interactive: type: boolean score_min_threshold: @@ -53805,6 +53811,11 @@ components: minimum: -2147483648 required: - name + RequestContentTypeEnum: + enum: + - application/x-www-form-urlencoded + - application/json + type: string Review: type: object description: |- diff --git a/web/src/admin/stages/captcha/CaptchaStageForm.ts b/web/src/admin/stages/captcha/CaptchaStageForm.ts index 6c962e3ac2..387f71815c 100644 --- a/web/src/admin/stages/captcha/CaptchaStageForm.ts +++ b/web/src/admin/stages/captcha/CaptchaStageForm.ts @@ -14,9 +14,11 @@ import { SlottedTemplateResult } from "#elements/types"; import { BaseStageForm } from "#admin/stages/BaseStageForm"; import { CAPTCHA_PROVIDERS, + CAPTCHA_REQUEST_CONTENT_TYPES, CaptchaProviderKey, CaptchaProviderKeys, CaptchaProviderPreset, + deriveCapSiteVerifyURL, detectProviderFromInstance, pluckFormValues, } from "#admin/stages/captcha/shared"; @@ -35,6 +37,10 @@ import { customElement, state } from "lit/decorators.js"; import { guard } from "lit/directives/guard.js"; import { ifDefined } from "lit/directives/if-defined.js"; +type CaptchaStageFormRequest = (CaptchaStageRequest | PatchedCaptchaStageRequest) & { + capEndpoint?: string; +}; + @customElement("ak-stage-captcha-form") export class CaptchaStageForm extends BaseStageForm { public static override readonly styles = [...super.styles, Styles]; @@ -83,6 +89,26 @@ export class CaptchaStageForm extends BaseStageForm { public async send( data: CaptchaStageRequest | PatchedCaptchaStageRequest, ): Promise { + const formData = data as CaptchaStageFormRequest; + + if (this.selectedProvider === "cap" && (formData.capEndpoint || formData.publicKey)) { + const capEndpoint = formData.capEndpoint || formData.publicKey || ""; + + formData.publicKey = capEndpoint; + delete formData.capEndpoint; + + const presetURL = CAPTCHA_PROVIDERS.cap.apiUrl; + // The Cap verification URL includes the site key, so derive it from the + // widget endpoint unless the advanced field was explicitly customized. + if (!data.apiUrl || data.apiUrl === presetURL) { + const siteVerifyURL = deriveCapSiteVerifyURL(capEndpoint); + + if (siteVerifyURL) { + data.apiUrl = siteVerifyURL; + } + } + } + if (this.instance) { return this.#api.stagesCaptchaPartialUpdate({ stageUuid: this.instance.pk || "", @@ -117,43 +143,77 @@ export class CaptchaStageForm extends BaseStageForm {

${guard([this.#currentPreset], () => { - const { formatAPISource, keyURL } = this.#currentPreset; + const { formatAPISource, formatDescription, keyURL } = this.#currentPreset; - if (!formatAPISource || !keyURL) { - return null; - } + const description = formatDescription + ? html`

${formatDescription()}

` + : null; + const providerLink = + formatAPISource && keyURL + ? html` + ${this.selectedProvider === "cap" + ? msg( + html`Use the + ${html`
${formatAPISource()}`} + to self-host Cap and configure the endpoint.`, + { + id: "captcha.provider-link.cap", + desc: "Supplementary help text with link to Cap documentation.", + }, + ) + : msg( + html`API keys can be obtained from the + ${html`${formatAPISource()}.`}`, + { + id: "captcha.provider-link", + desc: "Supplementary help text with link to provider dashboard.", + }, + )} + ` + : null; - return html` - ${msg( - html`API keys can be obtained from the - ${html`${formatAPISource()}.`}`, - { - id: "captcha.provider-link", - desc: "Supplementary help text with link to provider dashboard.", - }, - )} - `; + return html`${description} ${providerLink}`; })} `; } protected renderKeyFields(): SlottedTemplateResult { + const isCapProvider = this.selectedProvider === "cap"; + const publicKeyLabel = isCapProvider ? msg("Cap Endpoint") : msg("Public Key"); + const publicKeyPlaceholder = isCapProvider + ? msg("https://cap.example.com/site-key/") + : msg("Paste your CAPTCHA public key..."); + const publicKeyHelp = isCapProvider + ? msg("The public site-key endpoint of your Cap server.", { + id: "captcha.cap-endpoint.description", + desc: "Description for Cap endpoint field.", + }) + : msg("The public key is used by authentik to render the CAPTCHA widget.", { + id: "captcha.public-key.description", + desc: "Description for CAPTCHA public key field.", + }); + return html` @@ -236,9 +296,13 @@ export class CaptchaStageForm extends BaseStageForm { type="url" value="${ifDefined(formValues.jsUrl)}" required - help=${msg( - "URL to fetch the CAPTCHA JavaScript library from. Automatically set based on provider selection but can be customized.", - )} + help=${this.selectedProvider === "cap" + ? msg( + "For Cap, prefer the self-hosted widget asset, for example https://cap.example.com/assets/widget.js. If using a CDN, pin a reviewed release.", + ) + : msg( + "URL to fetch the CAPTCHA JavaScript library from. Automatically set based on provider selection but can be customized.", + )} > { type="url" value="${ifDefined(formValues.apiUrl)}" required - help=${msg( - "URL used to validate CAPTCHA response on the backend. Automatically set based on provider selection but can be customized.", - )} + help=${this.selectedProvider === "cap" + ? msg( + "Cap's server-side verification endpoint, for example https://cap.example.com/site-key/siteverify.", + ) + : msg( + "URL used to validate CAPTCHA response on the backend. Automatically set based on provider selection but can be customized.", + )} > + + +

+ ${msg( + "Content-Type used for server-side verification. Cap requires JSON; most other providers use form-encoded requests.", + )} +

+
`; } diff --git a/web/src/admin/stages/captcha/shared.ts b/web/src/admin/stages/captcha/shared.ts index ce10318569..f7eb92d518 100644 --- a/web/src/admin/stages/captcha/shared.ts +++ b/web/src/admin/stages/captcha/shared.ts @@ -2,12 +2,35 @@ import { CaptchaStage, CaptchaStageRequest } from "@goauthentik/api"; import { msg } from "@lit/localize"; +export type CaptchaRequestContentType = "application/x-www-form-urlencoded" | "application/json"; + +export const CAPTCHA_REQUEST_CONTENT_TYPES = [ + { + value: "application/x-www-form-urlencoded", + formatDisplayName: () => + msg("Form encoded", { + id: "captcha.request-content-type.form", + }), + }, + { + value: "application/json", + formatDisplayName: () => + msg("JSON", { + id: "captcha.request-content-type.json", + }), + }, +] as const satisfies { + value: CaptchaRequestContentType; + formatDisplayName: () => string; +}[]; + export const CaptchaProviderKeys = [ "recaptcha_v2", "recaptcha_v3", "recaptcha_enterprise", "hcaptcha", "turnstile", + "cap", "custom", ] as const satisfies string[]; @@ -15,8 +38,10 @@ export type CaptchaProviderKey = (typeof CaptchaProviderKeys)[number]; export interface CaptchaProviderPreset { formatDisplayName: () => string; + formatDescription?: () => string; jsUrl: string; apiUrl: string; + requestContentType: CaptchaRequestContentType; interactive: boolean; supportsScore: boolean; score?: { min: number; max: number }; @@ -37,6 +62,7 @@ export const CAPTCHA_PROVIDERS = { }), jsUrl: "https://www.recaptcha.net/recaptcha/api.js", apiUrl: "https://www.recaptcha.net/recaptcha/api/siteverify", + requestContentType: "application/x-www-form-urlencoded", interactive: true, supportsScore: false, formatAPISource: () => @@ -52,6 +78,7 @@ export const CAPTCHA_PROVIDERS = { }), jsUrl: "https://www.recaptcha.net/recaptcha/api.js", apiUrl: "https://www.recaptcha.net/recaptcha/api/siteverify", + requestContentType: "application/x-www-form-urlencoded", interactive: false, supportsScore: true, score: { min: 0.5, max: 1.0 }, @@ -68,6 +95,7 @@ export const CAPTCHA_PROVIDERS = { }), jsUrl: "https://www.recaptcha.net/recaptcha/enterprise.js", apiUrl: "https://www.recaptcha.net/recaptcha/api/siteverify", + requestContentType: "application/x-www-form-urlencoded", interactive: false, supportsScore: true, score: { min: 0.5, max: 1.0 }, @@ -84,6 +112,7 @@ export const CAPTCHA_PROVIDERS = { }), jsUrl: "https://js.hcaptcha.com/1/api.js", apiUrl: "https://api.hcaptcha.com/siteverify", + requestContentType: "application/x-www-form-urlencoded", interactive: true, supportsScore: true, score: { min: 0.0, max: 0.5 }, @@ -100,6 +129,7 @@ export const CAPTCHA_PROVIDERS = { }), jsUrl: "https://challenges.cloudflare.com/turnstile/v0/api.js", apiUrl: "https://challenges.cloudflare.com/turnstile/v0/siteverify", + requestContentType: "application/x-www-form-urlencoded", interactive: true, supportsScore: false, formatAPISource: () => @@ -108,6 +138,26 @@ export const CAPTCHA_PROVIDERS = { }), keyURL: "https://dash.cloudflare.com", }, + cap: { + formatDisplayName: () => + msg("Cap", { + id: "captcha.providers.cap", + }), + formatDescription: () => + msg("Cap is a self-hostable CAPTCHA server that uses proof-of-work challenges.", { + id: "captcha.providers.cap.description", + }), + jsUrl: "https://cap.example.com/assets/widget.js", + apiUrl: "https://cap.example.com/site-key/siteverify", + requestContentType: "application/json", + interactive: true, + supportsScore: false, + formatAPISource: () => + msg("Cap documentation", { + id: "captcha.providers.cap.setup-guide", + }), + keyURL: "https://trycap.dev/guide/", + }, custom: { formatDisplayName: () => msg("Custom", { @@ -115,23 +165,56 @@ export const CAPTCHA_PROVIDERS = { }), jsUrl: "https://www.recaptcha.net/recaptcha/api.js", apiUrl: "https://www.recaptcha.net/recaptcha/api/siteverify", + requestContentType: "application/x-www-form-urlencoded", interactive: false, supportsScore: true, score: { min: 0.5, max: 1.0 }, }, } as const satisfies Record; +export function deriveCapSiteVerifyURL(endpoint: string): string | null { + const trimmedEndpoint = endpoint.trim(); + + if (!URL.canParse(trimmedEndpoint)) { + return null; + } + + const endpointURL = new URL(trimmedEndpoint); + const normalizedEndpoint = endpointURL.href.endsWith("/") + ? endpointURL.href + : `${endpointURL.href}/`; + + return new URL("siteverify", normalizedEndpoint).toString(); +} + /** * Detect which provider preset matches the given {@linkcode CaptchaStage} instance. * This allows the form to show the correct provider in the dropdown when editing * an existing CAPTCHA stage. Falls back to "custom" if no match is found. */ +function isCapWidgetURL(jsUrl?: string | null): boolean { + if (!jsUrl || !URL.canParse(jsUrl)) { + return false; + } + + const { pathname } = new URL(jsUrl); + return pathname.includes("cap-widget") || pathname.endsWith("/assets/widget.js"); +} + export function detectProviderFromInstance(stage?: CaptchaStage | null): CaptchaProviderKey { if (!stage) return "custom"; for (const key of CaptchaProviderKeys) { const preset = CAPTCHA_PROVIDERS[key]; + if ( + key === "cap" && + isCapWidgetURL(stage.jsUrl) && + stage.requestContentType === preset.requestContentType + ) { + return key; + } + if (stage.jsUrl === preset.jsUrl && stage.apiUrl === preset.apiUrl) { return key; } @@ -153,6 +236,7 @@ export function pluckFormValues( return { jsUrl: instance.jsUrl, apiUrl: instance.apiUrl, + requestContentType: instance.requestContentType, interactive: instance.interactive, scoreMinThreshold: instance.scoreMinThreshold, scoreMaxThreshold: instance.scoreMaxThreshold, @@ -163,6 +247,7 @@ export function pluckFormValues( return { jsUrl: preset.jsUrl, apiUrl: preset.apiUrl, + requestContentType: preset.requestContentType, interactive: preset.interactive, scoreMinThreshold: preset.score?.min ?? 0.5, scoreMaxThreshold: preset.score?.max ?? 1.0, diff --git a/web/src/flow/stages/captcha/CaptchaStage.css b/web/src/flow/stages/captcha/CaptchaStage.css index 1256ec09e1..4a70ac0c7e 100644 --- a/web/src/flow/stages/captcha/CaptchaStage.css +++ b/web/src/flow/stages/captcha/CaptchaStage.css @@ -36,4 +36,9 @@ ak-stage-captcha[theme="dark"].style-scope { background-color: var(--captcha-background-from); animation: captcha-background-animation 1s infinite var(--pf-global--TimingFunction); } + + &[data-transparent-loading="true"][data-ready="loading"] { + background-color: transparent; + animation: none; + } } diff --git a/web/src/flow/stages/captcha/CaptchaStage.ts b/web/src/flow/stages/captcha/CaptchaStage.ts index 51859f2596..dfd3198fd2 100644 --- a/web/src/flow/stages/captcha/CaptchaStage.ts +++ b/web/src/flow/stages/captcha/CaptchaStage.ts @@ -12,6 +12,7 @@ import { AKFormErrors, ErrorProp } from "#components/ak-field-errors"; import { FlowUserDetails } from "#flow/FormStatic"; import { BaseStage } from "#flow/stages/base"; import Styles from "#flow/stages/captcha/CaptchaStage.css"; +import { CapController, isCapWidgetURL } from "#flow/stages/captcha/controllers/cap"; import { CaptchaController, CaptchaControllerConstructor, @@ -53,7 +54,14 @@ interface LoadMessage { message: "load"; } -type IframeMessageEvent = MessageEvent; +interface ErrorMessage { + source?: string; + context?: string; + message: "error"; + error: string; +} + +type IframeMessageEvent = MessageEvent; @customElement("ak-stage-captcha") export class CaptchaStage @@ -79,6 +87,7 @@ export class CaptchaStage HCaptchaController, GReCaptchaController, TurnstileController, + CapController, ]); #logger = ConsoleLogger.prefix("flow:captcha"); @@ -165,6 +174,9 @@ export class CaptchaStage return match(data) .with({ message: "captcha" }, ({ token }) => this.onTokenChange(token)) .with({ message: "load" }, this.#loadListener) + .with({ message: "error" }, ({ error }) => { + this.error = error; + }) .otherwise(({ message }) => { this.#logger.debug(`Unknown message: ${message}`); }); @@ -183,12 +195,18 @@ export class CaptchaStage } if (this.challenge?.interactive) { + // Cap renders its own framed widget, so the generic iframe loading shimmer looks like + // an extra CAPTCHA box flashing behind it. + const isCapChallenge = + URL.canParse(this.challenge.jsUrl) && isCapWidgetURL(new URL(this.challenge.jsUrl)); + return html` @@ -306,8 +324,13 @@ export class CaptchaStage // Then, load the new script... const scriptElement = document.createElement("script"); + const matchedController = Array.from(CaptchaStage.controllers).find((Controller) => + Controller.matchesURL(challengeURL), + ); scriptElement.src = challengeURL.toString(); + scriptElement.type = + matchedController?.scriptType === "module" ? "module" : "text/javascript"; scriptElement.async = true; scriptElement.defer = true; scriptElement.onload = this.#scriptLoadListener; @@ -528,6 +551,7 @@ export class CaptchaStage challengeURL: challengeURL.toString(), theme: this.activeTheme, scriptOnLoad: !(controller instanceof TurnstileController), + scriptType: controller.scriptType, }); if ( diff --git a/web/src/flow/stages/captcha/controllers/CaptchaController.ts b/web/src/flow/stages/captcha/controllers/CaptchaController.ts index 6da5320f84..6c0c2820d6 100644 --- a/web/src/flow/stages/captcha/controllers/CaptchaController.ts +++ b/web/src/flow/stages/captcha/controllers/CaptchaController.ts @@ -28,6 +28,20 @@ export abstract class CaptchaController implements ReactiveController { return (this.constructor as typeof CaptchaController).globalName; } + public static readonly scriptType: "classic" | "module" = "classic"; + + public get scriptType(): "classic" | "module" { + return (this.constructor as typeof CaptchaController).scriptType; + } + + public static isAvailable(): boolean { + return Object.hasOwn(window, this.globalName); + } + + public static matchesURL(_url: URL): boolean { + return false; + } + /** * A prefix for log messages from this controller. */ @@ -42,7 +56,7 @@ export abstract class CaptchaController implements ReactiveController { ): Array { return Array.from(controllerConstructors).filter((Controller) => { // Can we find the global for this captcha provider? - return Object.hasOwn(window, Controller.globalName); + return Controller.isAvailable(); }); } @@ -98,6 +112,9 @@ export abstract class CaptchaController implements ReactiveController { export type CaptchaControllerConstructor = { globalName: string; + scriptType: "classic" | "module"; + isAvailable: () => boolean; + matchesURL: (url: URL) => boolean; } & (new (host: CaptchaHandlerHost) => CaptchaController); export interface CaptchaHandlerHost extends ReactiveControllerHost { diff --git a/web/src/flow/stages/captcha/controllers/cap.ts b/web/src/flow/stages/captcha/controllers/cap.ts new file mode 100644 index 0000000000..47dfaa3f81 --- /dev/null +++ b/web/src/flow/stages/captcha/controllers/cap.ts @@ -0,0 +1,61 @@ +import { CaptchaController } from "#flow/stages/captcha/controllers/CaptchaController"; + +import { html } from "lit"; + +export function isCapWidgetURL(url: URL): boolean { + return url.pathname.includes("cap-widget") || url.pathname.endsWith("/assets/widget.js"); +} + +export class CapController extends CaptchaController { + public static readonly globalName = "cap-widget"; + + public static readonly scriptType = "module"; + + public static override isAvailable(): boolean { + return customElements.get("cap-widget") !== undefined; + } + + public static override matchesURL(url: URL): boolean { + return isCapWidgetURL(url); + } + + public interactive = () => { + const endpoint = this.host.challenge?.siteKey ?? ""; + + return html`
+ +
+ `; + }; + + public refreshInteractive = async () => { + this.host.iframeRef.value?.contentWindow?.location.reload(); + }; + + public execute = async () => { + throw new Error("Cap requires interactive mode."); + }; + + public refresh = async () => { + throw new Error("Cap requires interactive mode."); + }; +} diff --git a/web/src/flow/stages/captcha/shared.ts b/web/src/flow/stages/captcha/shared.ts index 5245809e7f..a3613aa421 100644 --- a/web/src/flow/stages/captcha/shared.ts +++ b/web/src/flow/stages/captcha/shared.ts @@ -30,6 +30,7 @@ export interface IFrameTemplateInit { * Defaults to `true`. */ scriptOnLoad?: boolean; + scriptType?: "classic" | "module"; } /** @@ -42,7 +43,7 @@ export interface IFrameTemplateInit { */ export function iframeTemplate( children: TemplateResult, - { challengeURL, theme, scriptOnLoad = true }: IFrameTemplateInit, + { challengeURL, theme, scriptOnLoad = true, scriptType = "classic" }: IFrameTemplateInit, ) { return createDocumentTemplate({ head: html` @@ -75,7 +76,7 @@ export function iframeTemplate( ${children} `, diff --git a/web/src/flow/stages/identification/controllers/CaptchaDisplayController.ts b/web/src/flow/stages/identification/controllers/CaptchaDisplayController.ts index b77691567d..918db04736 100644 --- a/web/src/flow/stages/identification/controllers/CaptchaDisplayController.ts +++ b/web/src/flow/stages/identification/controllers/CaptchaDisplayController.ts @@ -49,6 +49,12 @@ export class CaptchaDisplayController implements ReactiveController { const input = this.#inputRef.value; if (!input) return; input.value = token; + // The surrounding identification form only updates its validity when form controls + // emit normal input events, so mirror a user's field change after the CAPTCHA solves. + input.dispatchEvent(new Event("input", { bubbles: true, composed: true })); + input.dispatchEvent(new Event("change", { bubbles: true, composed: true })); + this.#loaded = true; + this.host.requestUpdate(); }; public onFailure() { diff --git a/website/docs/add-secure-apps/flows-stages/stages/captcha/index.md b/website/docs/add-secure-apps/flows-stages/stages/captcha/index.md index 3f65660a9c..79ef5679e6 100644 --- a/website/docs/add-secure-apps/flows-stages/stages/captcha/index.md +++ b/website/docs/add-secure-apps/flows-stages/stages/captcha/index.md @@ -2,7 +2,7 @@ title: Captcha stage --- -The Captcha stage adds CAPTCHA verification to a flow by using Google reCAPTCHA or compatible alternatives like hCaptcha and Cloudflare Turnstile. +The Captcha stage adds CAPTCHA verification to a flow by using Google reCAPTCHA or compatible alternatives like hCaptcha, Cloudflare Turnstile, and Cap. ## Overview @@ -20,6 +20,7 @@ It can either be bound to a flow or embedded inside the [Identification stage](. - **Error on invalid score**: show an error immediately when the score is outside the configured threshold. If disabled, the flow continues and policies can inspect the result from context. - **JS URL**: JavaScript loader URL for the provider. - **API URL**: verification endpoint URL for the provider. +- **Request content type**: content type used when authentik verifies the CAPTCHA token with the provider. ## Flow integration @@ -55,6 +56,25 @@ Recommended values: Score thresholds only apply to hCaptcha Enterprise. +### Cap + +Cap is a self-hostable CAPTCHA server that uses proof-of-work challenges. + +See https://trycap.dev/guide/. + +authentik supports Cap's default widget. The floating widget is not supported. + +Recommended values: + +- **Public key**: public Cap endpoint for the site key path, for example `https://cap.example.com/site-key/` +- **Private key**: Cap secret key +- **Interactive**: enabled +- **JS URL**: self-hosted Cap widget asset, for example `https://cap.example.com/assets/widget.js`. If you use a CDN, pin a reviewed release such as `https://cdn.jsdelivr.net/npm/cap-widget@` instead of the unversioned package URL. See [Cap releases](https://github.com/tiagozip/cap/releases). +- **API URL**: Cap verification endpoint, for example `https://cap.example.com/site-key/siteverify` +- **Request content type**: JSON + +Cap does not use score thresholds. + ### Cloudflare Turnstile See https://developers.cloudflare.com/turnstile/get-started/migrating-from-recaptcha. From ab1f8a06924f4324efa1cae9c1a02f8d9082a538 Mon Sep 17 00:00:00 2001 From: Connor Peshek Date: Thu, 11 Jun 2026 11:20:17 -0500 Subject: [PATCH 18/20] website/integrations: Update nextcloud to support post logout redirect uri (#22989) --- .../chat-communication-collaboration/nextcloud/index.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/integrations/chat-communication-collaboration/nextcloud/index.mdx b/website/integrations/chat-communication-collaboration/nextcloud/index.mdx index 1601cad068..04dbde3697 100644 --- a/website/integrations/chat-communication-collaboration/nextcloud/index.mdx +++ b/website/integrations/chat-communication-collaboration/nextcloud/index.mdx @@ -122,7 +122,8 @@ To connect to an existing Nextcloud user, set the `nextcloud_user_id` attribute - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://nextcloud.company/apps/user_oidc/code`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://nextcloud.company/apps/user_oidc/code`. + - Add a **Redirect URI** of type `Strict` `Post Logout` as `https://nextcloud.company`. - Select any available signing key. - Under **Advanced protocol settings**: - _(optional)_ If you created the `Nextcloud Profile` scope mapping, add it to **Selected Scopes**. From 783859d3c87fe0fee108465f00fe3e52c94c57f3 Mon Sep 17 00:00:00 2001 From: Connor Peshek Date: Thu, 11 Jun 2026 11:58:23 -0500 Subject: [PATCH 19/20] websites/integrations: specify redirect uri of type authorization or post logout (#22981) * docs/integrations: Update docs to specify redirect uri of type authorization or post logout * bold redirect uri * improve wording * update docs * add banner for warning of redirect uri's * Update website/integrations/_redirect-uri-2026-5-note.mdx Signed-off-by: Dewi Roberts --------- Signed-off-by: Connor Peshek Signed-off-by: Dewi Roberts Co-authored-by: Dewi Roberts --- .../docs/install-config/first-steps/index.mdx | 2 +- .../_redirect-uri-2026-5-note.mdx | 3 +++ .../affine/index.md | 6 +++++- .../chatgpt/index.mdx | 7 +++++-- .../espo-crm/index.md | 6 +++++- .../grommunio/index.md | 6 +++++- .../hedgedoc/index.md | 6 +++++- .../kanboard/index.md | 6 +++++- .../mailcow-logs-viewer/index.md | 6 +++++- .../mailcow/index.md | 6 +++++- .../mastodon/index.md | 6 +++++- .../matrix-synapse/index.md | 6 +++++- .../mattermost-team-edition/index.mdx | 5 ++++- .../mobilizon/index.md | 6 +++++- .../nextcloud/index.mdx | 3 +++ .../opencloud/index.mdx | 21 +++++++++++-------- .../openproject/index.md | 6 +++++- .../owncloud/index.md | 14 ++++++++----- .../planka/index.mdx | 6 +++++- .../rocketchat/index.md | 6 +++++- .../roundcube/index.md | 6 +++++- .../sharepoint-se/index.md | 6 +++++- .../vikunja/index.mdx | 7 +++++-- .../wekan/index.mdx | 6 +++++- .../writefreely/index.md | 6 +++++- .../cloud-providers/aws-classic/index.mdx | 5 ++++- .../cloud-providers/digitalocean/index.md | 6 +++++- .../cloud-providers/oracle-cloud/index.md | 6 +++++- .../integrations/dashboards/dashy/index.md | 6 +++++- .../integrations/dashboards/homarr/index.md | 6 +++++- .../dashboards/linkwarden/index.md | 6 +++++- .../integrations/development/coder/index.md | 6 +++++- .../integrations/development/engomo/index.mdx | 6 +++++- .../integrations/development/forgejo/index.md | 6 +++++- .../integrations/development/frappe/index.md | 6 +++++- .../integrations/development/gitea/index.md | 6 +++++- .../integrations/development/gitlab/index.mdx | 6 +++++- .../development/gravitee/index.md | 6 +++++- .../integrations/development/jenkins/index.md | 6 +++++- .../development/node-red/index.md | 6 +++++- .../device-management/apple/index.md | 6 +++++- .../device-management/meshcentral/index.md | 6 +++++- .../omnissa-workspace-one-access/index.md | 8 +++++-- .../documentation/bookstack/index.mdx | 5 ++++- .../documentation/dokuwiki/index.md | 4 ++++ .../documentation/karakeep/index.md | 6 +++++- .../documentation/kitchenowl/index.md | 6 +++++- .../documentation/mealie/index.md | 6 +++++- .../documentation/netbox/index.md | 6 +++++- .../documentation/outline/index.md | 6 +++++- .../documentation/paperless-ngx/index.mdx | 6 +++++- .../documentation/papra/index.mdx | 6 +++++- .../documentation/tandoor/index.md | 6 +++++- .../documentation/wiki-js/index.md | 6 +++++- .../hypervisors-orchestrators/arcane/index.md | 6 +++++- .../portainer/index.md | 6 +++++- .../proxmox-ve/index.md | 6 +++++- .../vmware-cloud-director/index.md | 6 +++++- .../vmware-vcenter/index.md | 6 +++++- .../xen-orchestra/index.md | 6 +++++- .../infrastructure/apache-guacamole/index.mdx | 5 ++++- .../infrastructure/argocd/index.md | 6 +++++- .../infrastructure/harbor/index.md | 6 +++++- .../infrastructure/keycloak/index.mdx | 5 ++++- .../infrastructure/komodo/index.mdx | 6 +++++- .../infrastructure/minio/index.mdx | 5 ++++- .../infrastructure/nexterm/index.md | 6 +++++- .../infrastructure/osticket/index.md | 6 +++++- .../infrastructure/pgadmin/index.md | 6 +++++- .../infrastructure/plesk/index.md | 6 +++++- .../infrastructure/rabbitmq/index.mdx | 5 ++++- .../infrastructure/rustdesk-pro/index.mdx | 6 +++++- .../infrastructure/semaphore/index.mdx | 6 +++++- .../infrastructure/synology-dsm/index.md | 6 +++++- .../infrastructure/termix/index.mdx | 6 +++++- .../infrastructure/terrakube/index.md | 6 +++++- .../infrastructure/zammad/index.md | 5 ++++- .../infrastructure/zendesk/index.mdx | 5 ++++- .../integrations/infrastructure/zot/index.md | 8 ++++--- .../learning/absorb-lms/index.mdx | 5 ++++- .../media/audiobookshelf/index.md | 4 ++++ website/integrations/media/freshrss/index.mdx | 6 +++++- website/integrations/media/immich/index.md | 6 +++++- website/integrations/media/jellyfin/index.md | 6 +++++- website/integrations/media/komga/index.md | 6 +++++- website/integrations/media/miniflux/index.md | 6 +++++- .../integrations/media/photoprism/index.md | 6 +++++- website/integrations/media/seafile/index.md | 6 +++++- website/integrations/media/seerr/index.md | 6 +++++- .../miscellaneous/actual-budget/index.mdx | 5 ++++- .../miscellaneous/adventurelog/index.mdx | 6 +++++- .../miscellaneous/ezbookkeeping/index.mdx | 5 ++++- .../miscellaneous/filerise/index.mdx | 6 +++++- .../miscellaneous/home-assistant/index.md | 8 +++++-- .../miscellaneous/open-webui/index.md | 6 +++++- .../miscellaneous/wallos/index.mdx | 6 +++++- .../miscellaneous/zipline/index.md | 6 +++++- .../integrations/monitoring/beszel/index.mdx | 6 +++++- .../monitoring/chronograf/index.mdx | 6 +++++- .../integrations/monitoring/gatus/index.mdx | 6 +++++- .../monitoring/glitchtip/index.md | 6 +++++- .../integrations/monitoring/grafana/index.mdx | 6 +++++- .../integrations/monitoring/icinga/index.md | 6 +++++- .../monitoring/observium/index.md | 6 +++++- .../integrations/monitoring/pulse/index.md | 6 +++++- .../monitoring/ubuntu-landscape/index.md | 6 +++++- .../monitoring/whats-up-docker/index.md | 6 +++++- .../integrations/networking/firezone/index.md | 6 +++++- .../integrations/networking/gravity/index.md | 6 +++++- .../networking/headscale/index.md | 6 +++++- .../integrations/networking/hoop.dev/index.md | 6 +++++- .../integrations/networking/netbird/index.mdx | 9 +++++--- .../networking/pangolin/index.mdx | 8 +++++-- .../networking/tailscale/index.md | 6 +++++- .../networking/technitium/index.md | 6 +++++- .../integrations/platforms/budibase/index.md | 6 +++++- .../integrations/platforms/drupal/index.md | 6 +++++- .../integrations/platforms/personio/index.md | 6 +++++- .../platforms/pocketbase/index.md | 6 +++++- .../integrations/platforms/wordpress/index.md | 6 +++++- .../integrations/security/1password/index.mdx | 6 +++++- .../integrations/security/bitwarden/index.mdx | 15 +++++++------ .../security/cloudflare-access/index.md | 6 +++++- .../security/hashicorp-vault/index.md | 6 +++++- .../security/vaultwarden/index.md | 6 +++++- .../integrations/security/xcreds/index.mdx | 6 +++++- 126 files changed, 627 insertions(+), 148 deletions(-) create mode 100644 website/integrations/_redirect-uri-2026-5-note.mdx diff --git a/website/docs/install-config/first-steps/index.mdx b/website/docs/install-config/first-steps/index.mdx index 25f0f1e0ed..e07e6d0ffe 100644 --- a/website/docs/install-config/first-steps/index.mdx +++ b/website/docs/install-config/first-steps/index.mdx @@ -102,7 +102,7 @@ Every application that you add to authentik requires a provider, which is used t authorization, etc. - **Protocol settings**: provide the following required configurations: - Note the **Client ID**, **Client Secret**, and **Slug** values because they will be required later when you configure Grafana to use authentik. - - Set the **Redirect URI** as a `Strict` redirect to `https://grafana.company/login/generic_oauth`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://grafana.company/login/generic_oauth`. - TIP: The Redirect URI is where a user is directed to, as soon as authentik's authorization flow is successfully completed. - **Grant Types** (required): Select at least one [grant type](../../add-secure-apps/providers/oauth2/#oauth-20-flows-and-grant-types) that the provider can use. diff --git a/website/integrations/_redirect-uri-2026-5-note.mdx b/website/integrations/_redirect-uri-2026-5-note.mdx new file mode 100644 index 0000000000..309aa5dc3f --- /dev/null +++ b/website/integrations/_redirect-uri-2026-5-note.mdx @@ -0,0 +1,3 @@ +:::info Redirect URI changes in authentik 2026.5 +In authentik versions earlier than 2026.5, all **Redirect URIs** are automatically treated as `Authorization` type. If you are using one of these older authentik versions, add only the `Authorization` URL to your **Redirect URIs** and do not configure a `Post Logout` URI. +::: diff --git a/website/integrations/chat-communication-collaboration/affine/index.md b/website/integrations/chat-communication-collaboration/affine/index.md index 62d37b65e3..260489d9b8 100644 --- a/website/integrations/chat-communication-collaboration/affine/index.md +++ b/website/integrations/chat-communication-collaboration/affine/index.md @@ -4,6 +4,8 @@ sidebar_label: AFFiNE support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is AFFiNE? > AFFiNE is an open-source, self-hostable workspace for documents, whiteboards, and databases. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of AFFiNE with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of AFFiNE with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Add one `Strict` redirect URI and set it to `https://affine.company/oauth/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://affine.company/oauth/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/chat-communication-collaboration/chatgpt/index.mdx b/website/integrations/chat-communication-collaboration/chatgpt/index.mdx index 8108314f42..427cccdcd9 100644 --- a/website/integrations/chat-communication-collaboration/chatgpt/index.mdx +++ b/website/integrations/chat-communication-collaboration/chatgpt/index.mdx @@ -4,6 +4,7 @@ sidebar_label: ChatGPT support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import SAMLProvider20265Warning from "../../_saml-provider-2026-5-warning.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -38,6 +39,8 @@ You can configure ChatGPT to use either OIDC or SAML; this guide explains both o ## authentik configuration + + To support the integration of ChatGPT with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -48,7 +51,7 @@ To support the integration of ChatGPT with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Temporarily set a `Strict` redirect URI to `https://temp.temp`. + - Temporarily add a **Redirect URI** of type `Strict` `Authorization` as `https://temp.temp`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. @@ -77,7 +80,7 @@ ChatGPT only enables the **Manage SSO** wizard after you verify ownership of you 1. Log in to authentik as an administrator and open the authentik Admin interface. 2. Navigate to **Applications** > **Providers** and click the **Edit** icon of the newly created ChatGPT provider. -3. Under **Protocol settings**, set the **Redirect URIs** to the **Login redirect URI** from ChatGPT. +3. Under **Protocol settings**, add a **Redirect URI** of type `Strict` `Authorization` as the **Login redirect URI** value from ChatGPT. 4. Click **Update**. diff --git a/website/integrations/chat-communication-collaboration/espo-crm/index.md b/website/integrations/chat-communication-collaboration/espo-crm/index.md index f497fdb616..072cab9d27 100644 --- a/website/integrations/chat-communication-collaboration/espo-crm/index.md +++ b/website/integrations/chat-communication-collaboration/espo-crm/index.md @@ -4,6 +4,8 @@ sidebar_label: EspoCRM support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is EspoCRM? > EspoCRM is a CRM (customer relationship management) web application that allows users to store, visualize, and analyze their company's business-related relationships such as opportunities, people, businesses, and projects. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of EspoCRM with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -37,7 +41,7 @@ To support the integration of EspoCRM with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://espocrm.company/oauth-callback.php`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://espocrm.company/oauth-callback.php`. - Select any available signing key. - Under **Advanced protocol settings**, set **Subject mode** to **Based on the User's username**. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/chat-communication-collaboration/grommunio/index.md b/website/integrations/chat-communication-collaboration/grommunio/index.md index 3671d94f37..052a2a2eb9 100644 --- a/website/integrations/chat-communication-collaboration/grommunio/index.md +++ b/website/integrations/chat-communication-collaboration/grommunio/index.md @@ -4,6 +4,8 @@ sidebar_label: grommunio support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is grommunio? @@ -25,6 +27,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To integrate authentik with grommunio, you will need to create an application and provider pair in authentik. :::info Keycloak-compatible endpoints @@ -39,7 +43,7 @@ grommunio-web expects Keycloak-compatible OIDC endpoints. Because authentik does - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name, the authorization flow to use, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://grommunio.company/web`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://grommunio.company/web`. - Set **Signing Key** to an available RSA key. - Under **Advanced protocol settings**: - Add the `authentik default OAuth Mapping: OpenID 'offline_access'` scope to **Selected Scopes**. diff --git a/website/integrations/chat-communication-collaboration/hedgedoc/index.md b/website/integrations/chat-communication-collaboration/hedgedoc/index.md index b4e41f8dab..50883c1ca1 100644 --- a/website/integrations/chat-communication-collaboration/hedgedoc/index.md +++ b/website/integrations/chat-communication-collaboration/hedgedoc/index.md @@ -4,6 +4,8 @@ sidebar_label: HedgeDoc support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is HedgeDoc? > HedgeDoc lets you create real-time collaborative markdown notes. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of HedgeDoc with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of HedgeDoc with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://hedgedoc.company/auth/oauth2/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://hedgedoc.company/auth/oauth2/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. 3. Click **Submit** to save the new application and provider. diff --git a/website/integrations/chat-communication-collaboration/kanboard/index.md b/website/integrations/chat-communication-collaboration/kanboard/index.md index b204eca231..389713f351 100644 --- a/website/integrations/chat-communication-collaboration/kanboard/index.md +++ b/website/integrations/chat-communication-collaboration/kanboard/index.md @@ -4,6 +4,8 @@ sidebar_label: Kanboard support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Kanboard? > Kanboard is a free and open source Kanban project management software. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Kanboard with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Kanboard with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://kanboard.company/oauth/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://kanboard.company/oauth/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/chat-communication-collaboration/mailcow-logs-viewer/index.md b/website/integrations/chat-communication-collaboration/mailcow-logs-viewer/index.md index 609173069d..9f30192c53 100644 --- a/website/integrations/chat-communication-collaboration/mailcow-logs-viewer/index.md +++ b/website/integrations/chat-communication-collaboration/mailcow-logs-viewer/index.md @@ -4,6 +4,8 @@ sidebar_label: mailcow Logs Viewer support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is mailcow Logs Viewer? > A modern, self-hosted dashboard for monitoring, analyzing, and managing your mailcow mail server. Track email delivery, investigate spam, manage quarantine, detect bounce-based abuse, and validate DNS configurations, all from a single interface. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of mailcow Logs Viewer with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of mailcow Logs Viewer with authentik, you need to cr - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **application slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://mailcow-logs-viewer.company/api/auth/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://mailcow-logs-viewer.company/api/auth/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/chat-communication-collaboration/mailcow/index.md b/website/integrations/chat-communication-collaboration/mailcow/index.md index d5fe636eb3..1fcdc73dc4 100644 --- a/website/integrations/chat-communication-collaboration/mailcow/index.md +++ b/website/integrations/chat-communication-collaboration/mailcow/index.md @@ -4,6 +4,8 @@ sidebar_label: mailcow support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is mailcow? > mailcow is a Dockerized, open-source groupware and email suite based on Docker. It relies on many well-known and long-used components, which, when combined, result in a comprehensive email server solution. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of mailcow with authentik, you need to create a property mapping, set the `email_verified` attribute on required users, and create an application/provider pair in authentik. ### Create a property mapping @@ -56,7 +60,7 @@ Repeat these steps for all users that need to use the Mailcow integration. - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://mailcow.company`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://mailcow.company`. - Select any available signing key. - Under **Advanced protocol settings**: - Remove the `authentik default OAuth Mapping: OpenID 'email'` scope from **Selected Scopes**. diff --git a/website/integrations/chat-communication-collaboration/mastodon/index.md b/website/integrations/chat-communication-collaboration/mastodon/index.md index 61aaa6c24b..6b2a6589e8 100644 --- a/website/integrations/chat-communication-collaboration/mastodon/index.md +++ b/website/integrations/chat-communication-collaboration/mastodon/index.md @@ -4,6 +4,8 @@ sidebar_label: Mastodon support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Mastodon? > Mastodon is free and open-source software for running self-hosted social networking services. It has microblogging features similar to Twitter @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Mastodon with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Mastodon with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://mastodon.company/auth/auth/openid_connect/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://mastodon.company/auth/auth/openid_connect/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/chat-communication-collaboration/matrix-synapse/index.md b/website/integrations/chat-communication-collaboration/matrix-synapse/index.md index d57e7f6b50..1d79d8ac53 100644 --- a/website/integrations/chat-communication-collaboration/matrix-synapse/index.md +++ b/website/integrations/chat-communication-collaboration/matrix-synapse/index.md @@ -4,6 +4,8 @@ sidebar_label: Matrix Synapse support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Matrix Synapse? > Matrix is an open source project that publishes the Matrix open standard for secure, decentralized, real-time communication, and its Apache licensed reference implementations. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Matrix Synapse with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Matrix Synapse with authentik, you need to create - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://matrix.company/_synapse/client/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://matrix.company/_synapse/client/oidc/callback`. - Select any available RSA signing key. Matrix Synapse doesn't support ECC keys. - Do not set an encryption key because this is not supported by Matrix Synapse. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/chat-communication-collaboration/mattermost-team-edition/index.mdx b/website/integrations/chat-communication-collaboration/mattermost-team-edition/index.mdx index 3311917e88..6ac90c4476 100644 --- a/website/integrations/chat-communication-collaboration/mattermost-team-edition/index.mdx +++ b/website/integrations/chat-communication-collaboration/mattermost-team-edition/index.mdx @@ -4,6 +4,7 @@ sidebar_label: Mattermost Team Edition support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import SAMLProvider20265Warning from "../../_saml-provider-2026-5-warning.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -45,6 +46,8 @@ Once configured, Mattermost will display a login button with the GitLab icon, bu ## authentik configuration + + To support the integration of Mattermost Team Edition with authentik, you need to create property mappings and an application/provider pair in authentik. ### Create property mappings @@ -84,7 +87,7 @@ The following `id` property mapping is optional. If omitted, Mattermost will gen - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://mattermost.company/signup/gitlab/complete`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://mattermost.company/signup/gitlab/complete`. - Select any available signing key. - Under **Advanced protocol settings**, add the scopes you just created to the list of selected scopes. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/chat-communication-collaboration/mobilizon/index.md b/website/integrations/chat-communication-collaboration/mobilizon/index.md index 51fb0c597f..f3a190d6fe 100644 --- a/website/integrations/chat-communication-collaboration/mobilizon/index.md +++ b/website/integrations/chat-communication-collaboration/mobilizon/index.md @@ -4,6 +4,8 @@ sidebar_label: Mobilizon support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Mobilizon? > Gather, organize and mobilize yourselves with a convivial, ethical, and emancipating tool. https://joinmobilizon.org @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Mobilizon with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Mobilizon with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://mobilizon.company/auth/keycloak/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://mobilizon.company/auth/keycloak/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/chat-communication-collaboration/nextcloud/index.mdx b/website/integrations/chat-communication-collaboration/nextcloud/index.mdx index 04dbde3697..476f1b7e38 100644 --- a/website/integrations/chat-communication-collaboration/nextcloud/index.mdx +++ b/website/integrations/chat-communication-collaboration/nextcloud/index.mdx @@ -4,6 +4,7 @@ sidebar_label: Nextcloud support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import SAMLProvider20265Warning from "../../_saml-provider-2026-5-warning.mdx"; ## What is Nextcloud? @@ -116,6 +117,8 @@ To connect to an existing Nextcloud user, set the `nextcloud_user_id` attribute ## Create an application and provider in authentik + + 1. Log in to authentik as an administrator and open the authentik Admin interface. 2. Navigate to **Applications** > **Applications** and click **New Application** to create an application and provider pair. (Alternatively you can first create a provider separately, then create the application and connect it with the provider.) - **Application**: provide a descriptive name, an optional group for the type of application, the policy engine mode, and optional UI settings. diff --git a/website/integrations/chat-communication-collaboration/opencloud/index.mdx b/website/integrations/chat-communication-collaboration/opencloud/index.mdx index 9fcfc14a12..f082bd73df 100644 --- a/website/integrations/chat-communication-collaboration/opencloud/index.mdx +++ b/website/integrations/chat-communication-collaboration/opencloud/index.mdx @@ -4,6 +4,7 @@ sidebar_label: OpenCloud support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -35,6 +36,8 @@ Choose your setup below. The **Web only** tab logs in through the browser. The * ## authentik configuration + + 1. Log in to authentik as an administrator and open the Admin interface. 2. Navigate to **Applications** > **Applications** and click **New Application**. - **Application**: provide a name and note the **slug**. @@ -43,9 +46,9 @@ Choose your setup below. The **Web only** tab logs in through the browser. The * - **Client type**: `Public` - **Client ID**: `web` - **Redirect URIs**: - - Strict: `https://opencloud.company/oidc-callback.html` - - Strict: `https://opencloud.company/oidc-silent-redirect.html` - - Strict: `https://opencloud.company/` + - `Strict` `Authorization`: `https://opencloud.company/oidc-callback.html` + - `Strict` `Authorization`: `https://opencloud.company/oidc-silent-redirect.html` + - `Strict` `Authorization`: `https://opencloud.company/` - **Signing Key**: select any available key. - **Scopes**: `openid`, `profile`, `email`. 3. Click **Submit**. @@ -112,12 +115,12 @@ With GLOBAL issuer mode enabled, tokens use an issuer of `iss = https://authenti Repeat these steps for **each** of the four clients (Web, Desktop, Android, and iOS), using the per-client values from the table below. -| Client | Client ID | Redirect URIs | -| ------- | ------------------ | ------------------------------------------------------------------------------------------- | -| Web | `web` | Strict: `https://opencloud.company/oidc-callback.html`, `…/oidc-silent-redirect.html`, `…/` | -| Desktop | `OpenCloudDesktop` | Regex: `http://127.0.0.1(:[0-9]+)?(/.*)?` and `http://localhost(:[0-9]+)?(/.*)?` | -| Android | `OpenCloudAndroid` | Strict: `oc://android.opencloud.eu` | -| iOS | `OpenCloudIOS` | Strict: `oc://ios.opencloud.eu` | +| Client | Client ID | Redirect URIs | +| ------- | ------------------ | ------------------------------------------------------------------------------------------------------------- | +| Web | `web` | `Strict` `Authorization`: `https://opencloud.company/oidc-callback.html`, `…/oidc-silent-redirect.html`, `…/` | +| Desktop | `OpenCloudDesktop` | `Regex` `Authorization`: `http://127.0.0.1(:[0-9]+)?(/.*)?` and `http://localhost(:[0-9]+)?(/.*)?` | +| Android | `OpenCloudAndroid` | `Strict` `Authorization`: `oc://android.opencloud.eu` | +| iOS | `OpenCloudIOS` | `Strict` `Authorization`: `oc://ios.opencloud.eu` | 1. Log in to authentik as an administrator and open the Admin interface. 2. Navigate to **Applications** > **Applications** and click **New Application**. diff --git a/website/integrations/chat-communication-collaboration/openproject/index.md b/website/integrations/chat-communication-collaboration/openproject/index.md index 810faadcb7..5fa39a36f0 100644 --- a/website/integrations/chat-communication-collaboration/openproject/index.md +++ b/website/integrations/chat-communication-collaboration/openproject/index.md @@ -4,6 +4,8 @@ sidebar_label: OpenProject support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is OpenProject? > OpenProject is a web-based project management software. Use OpenProject to manage your projects, tasks and goals. Collaborate via work packages and link them to your pull requests on GitHub. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of OpenProject with authentik, you need to create a property mapping and an application/provider pair in authentik. ### Create a scope mapping @@ -61,7 +65,7 @@ OpenProject requires a first and last name for each user. By default authentik o - **Protocol settings**: - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - **Redirect URI**: - - Strict: `https://openproject.company/auth/oidc-authentik/callback` + - `Strict` `Authorization`: `https://openproject.company/auth/oidc-authentik/callback` - **Signing key**: select any available signing key. - **Advanced protocol settings**: - **Scopes**: diff --git a/website/integrations/chat-communication-collaboration/owncloud/index.md b/website/integrations/chat-communication-collaboration/owncloud/index.md index 3fe9e17576..2ffe8b378d 100644 --- a/website/integrations/chat-communication-collaboration/owncloud/index.md +++ b/website/integrations/chat-communication-collaboration/owncloud/index.md @@ -4,6 +4,8 @@ sidebar_label: ownCloud support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is ownCloud? > ownCloud is a free and open-source software project for content collaboration and sharing and syncing of files. @@ -23,6 +25,8 @@ This guide focuses on deploying ownCloud installations using Docker. If you depl ## authentik configuration + + To support the integration of ownCloud with authentik, you need to create multiple application/provider pairs in authentik. A different pair is required for the Web UI, Desktop application, Android application, and iOS application. The configuration for each application is nearly identical, except for the **Client ID**, **Client Secret**, and the **Redirect URI** values, which are [predefined](https://doc.owncloud.com/server/latest/admin_manual/configuration/user/oidc/oidc.html#client-ids-secrets-and-redirect-uris) by ownCloud for the Desktop, Android, and iOS applications. @@ -43,29 +47,29 @@ The configuration for each application is nearly identical, except for the **Cli - **Client ID**: Use the value generated by authentik. - **Client Secret**: Use the value generated by authentik. - **Redirect URIs**: - - Strict: `https://owncloud.company/apps/openidconnect/redirect` + - `Strict` `Authorization`: `https://owncloud.company/apps/openidconnect/redirect` **Desktop Application** - **Signing Key**: Select any available signing key. - **Client ID**: Use the predefined value found in the [ownCloud admin manual](https://doc.owncloud.com/server/latest/admin_manual/configuration/user/oidc/oidc.html#client-id). - **Client Secret**: Use the predefined value found in the [ownCloud admin manual](https://doc.owncloud.com/server/latest/admin_manual/configuration/user/oidc/oidc.html#client-secret). - **Redirect URIs**: - - Regex: `http://localhost:\d+` - - Regex: `http://127.0.0.1:\d+` + - `Regex` `Authorization`: `http://localhost:\d+` + - `Regex` `Authorization`: `http://127.0.0.1:\d+` **Android Application** - **Signing Key**: Select any available signing key. - **Client ID**: Use the predefined value found in the [ownCloud admin manual](https://doc.owncloud.com/server/latest/admin_manual/configuration/user/oidc/oidc.html#client-id). - **Client Secret**: Use the predefined value found in the [ownCloud admin manual](https://doc.owncloud.com/server/latest/admin_manual/configuration/user/oidc/oidc.html#client-secret). - **Redirect URI**: - - Strict: `oc://android.owncloud.com` + - `Strict` `Authorization`: `oc://android.owncloud.com` **iOS Application** - **Signing Key**: Select any available signing key. - **Client ID**: Use the predefined value found in the [ownCloud admin manual](https://doc.owncloud.com/server/latest/admin_manual/configuration/user/oidc/oidc.html#client-id). - **Client Secret**: Use the predefined value found in the [ownCloud admin manual](https://doc.owncloud.com/server/latest/admin_manual/configuration/user/oidc/oidc.html#client-secret). - **Redirect URI**: - - Strict: `oc://ios.owncloud.com` + - `Strict` `Authorization`: `oc://ios.owncloud.com` - **Advanced protocol settings:** - **Scopes**: Select the following scopes for each of the four application/provider pairs: `email`, `offline_access`, `openid`, `profile`. diff --git a/website/integrations/chat-communication-collaboration/planka/index.mdx b/website/integrations/chat-communication-collaboration/planka/index.mdx index 3cb8a3938c..184f8fb23a 100644 --- a/website/integrations/chat-communication-collaboration/planka/index.mdx +++ b/website/integrations/chat-communication-collaboration/planka/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Planka support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Planka? > Planka is an open-source, Trello-like application with a Kanban board system, used for project management. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Planka with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Planka with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://planka.company/oidc-callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://planka.company/oidc-callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/chat-communication-collaboration/rocketchat/index.md b/website/integrations/chat-communication-collaboration/rocketchat/index.md index ec6b751bc9..eb4dc1657f 100644 --- a/website/integrations/chat-communication-collaboration/rocketchat/index.md +++ b/website/integrations/chat-communication-collaboration/rocketchat/index.md @@ -4,6 +4,8 @@ sidebar_label: Rocket.chat support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Rocket.chat? > Rocket.Chat is an open-source fully customizable communications platform developed in JavaScript for organizations with high standards of data protection. It is licensed under the MIT License with some other licenses mixed in. See [Rocket.chat GitHub](https://github.com/RocketChat/Rocket.Chat/blob/develop/LICENSE) for licensing information. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Rocket.chat with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -38,7 +42,7 @@ To support the integration of Rocket.chat with authentik, you need to create an - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://rocket.company/\_oauth/authentik`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://rocket.company/\_oauth/authentik`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/chat-communication-collaboration/roundcube/index.md b/website/integrations/chat-communication-collaboration/roundcube/index.md index 16ea18ad68..a87f28148e 100644 --- a/website/integrations/chat-communication-collaboration/roundcube/index.md +++ b/website/integrations/chat-communication-collaboration/roundcube/index.md @@ -4,6 +4,8 @@ sidebar_label: Roundcube support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Roundcube? > Roundcube is a browser-based multilingual IMAP client with an application-like user interface. It provides the full functionality you expect from an email client, including MIME support, address book, folder manipulation, message searching and spell checking. @@ -29,6 +31,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Roundcube with authentik, you need to create an application/provider pair in authentik. ### Create property mappings @@ -59,7 +63,7 @@ To support the integration of Roundcube with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://roundcube.company/index.php?\_task=settings&\_action=plugin.oauth_redirect`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://roundcube.company/index.php?\_task=settings&\_action=plugin.oauth_redirect`. - Select any available signing key. - Under **Advanced protocol settings**: - Under **Scopes**, add `dovecotprofile` and `authentik default OAuth Mapping: OpenID 'offline_access'` to the list of selected scopes. diff --git a/website/integrations/chat-communication-collaboration/sharepoint-se/index.md b/website/integrations/chat-communication-collaboration/sharepoint-se/index.md index b10ca7489b..8f1ecac453 100644 --- a/website/integrations/chat-communication-collaboration/sharepoint-se/index.md +++ b/website/integrations/chat-communication-collaboration/sharepoint-se/index.md @@ -4,6 +4,8 @@ sidebar_label: SharePoint Server SE support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Microsoft SharePoint? > SharePoint is a proprietary, web-based collaborative platform that integrates natively with Microsoft 365. @@ -66,6 +68,8 @@ These guidelines use the following placeholders for the overall setup: ## authentik configuration + + ### Step 1: Create authentik OpenID property mappings SharePoint requires additional properties within the OpenID and profile scopes in order to operate OIDC properly and map incoming authentik OID claims with Microsoft claims. @@ -140,7 +144,7 @@ From the authentik Admin Dashboard: :::info use the explicit flow if user consents are required ::: - - **Redirect URIs / Origins**: `auth.providerRedirectURI` + - **Redirect URIs / Origins** (`Strict` `Authorization`): `auth.providerRedirectURI` - **Signing Key**: authentik Self-signed Certificate :::info The certificate is used for signing JWT tokens; if you change it after the integration do not forget to update your SharePoint Trusted Certificate. diff --git a/website/integrations/chat-communication-collaboration/vikunja/index.mdx b/website/integrations/chat-communication-collaboration/vikunja/index.mdx index ffc336152c..8d528ffe16 100644 --- a/website/integrations/chat-communication-collaboration/vikunja/index.mdx +++ b/website/integrations/chat-communication-collaboration/vikunja/index.mdx @@ -4,6 +4,7 @@ sidebar_label: Vikunja support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -31,6 +32,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Vikunja with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -41,8 +44,8 @@ To support the integration of Vikunja with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - For web login, set a `Strict` redirect URI to `https://vikunja.company/auth/openid/authentik`. - - If using the Vikunja desktop client, add a `Regex` redirect URI such as `^http://127\\.0\\.0\\.1:[0-9]+/auth/openid/authentik$` to allow loopback redirects to `127.0.0.1`. + - For web login, add a **Redirect URI** of type `Strict` `Authorization` as `https://vikunja.company/auth/openid/authentik`. + - If using the Vikunja desktop client, add a **Redirect URI** of type `Regex` `Authorization` such as `^http://127\\.0\\.0\\.1:[0-9]+/auth/openid/authentik$` to allow loopback redirects to `127.0.0.1`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. 3. Click **Submit** to save the new application and provider. diff --git a/website/integrations/chat-communication-collaboration/wekan/index.mdx b/website/integrations/chat-communication-collaboration/wekan/index.mdx index bc3c91a631..008d8557bf 100644 --- a/website/integrations/chat-communication-collaboration/wekan/index.mdx +++ b/website/integrations/chat-communication-collaboration/wekan/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Wekan support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Wekan? > Wekan is an open-source kanban board which allows a card-based task and to-do management. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Wekan with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Wekan with authentik, you need to create an applic - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://wekan.company/_oauth/oidc`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://wekan.company/_oauth/oidc`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/chat-communication-collaboration/writefreely/index.md b/website/integrations/chat-communication-collaboration/writefreely/index.md index 435217e1f9..180e536ddd 100644 --- a/website/integrations/chat-communication-collaboration/writefreely/index.md +++ b/website/integrations/chat-communication-collaboration/writefreely/index.md @@ -4,6 +4,8 @@ sidebar_label: Writefreely support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Writefreely? > An open source platform for building a writing space on the web. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Writefreely with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -38,7 +42,7 @@ To support the integration of Writefreely with authentik, you need to create an - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://writefreely.company/oauth/callback/generic`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://writefreely.company/oauth/callback/generic`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/cloud-providers/aws-classic/index.mdx b/website/integrations/cloud-providers/aws-classic/index.mdx index 21a3c348a8..6838258512 100644 --- a/website/integrations/cloud-providers/aws-classic/index.mdx +++ b/website/integrations/cloud-providers/aws-classic/index.mdx @@ -4,6 +4,7 @@ sidebar_label: Amazon Web Services (Classic IAM) support_level: authentik --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import SAMLProvider20265Warning from "../../_saml-provider-2026-5-warning.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -44,6 +45,8 @@ SCIM Provisioning is only supported in conjunction with [IAM Identity Center](.. ## authentik configuration + + To support the integration of AWS with authentik via the Classic IAM method, you need to create two property mappings, an application/provider pair, and application entitlements for the AWS roles that users can assume. ### Create property mappings @@ -273,7 +276,7 @@ To support the integration of AWS with authentik using OIDC, you need to create - **Choose a Provider type**: Select OAuth2/OpenID Provider as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **slug** values because they will be required later. - - Set a `Strict` redirect URI to match the AWS resource that you want to access via OIDC. + - Add a **Redirect URI** of type `Strict` `Authorization` that matches the AWS resource that you want to access via OIDC. - Select any available signing key. - Under **Advanced protocol settings** > **Selected Scopes**, add `authentik default OAuth Mapping: OpenID 'entitlements'`. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/cloud-providers/digitalocean/index.md b/website/integrations/cloud-providers/digitalocean/index.md index 12fb4abfd6..a0b6dbacd8 100644 --- a/website/integrations/cloud-providers/digitalocean/index.md +++ b/website/integrations/cloud-providers/digitalocean/index.md @@ -4,6 +4,8 @@ sidebar_label: DigitalOcean support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is DigitalOcean? > DigitalOcean is a cloud infrastructure provider that offers developers simple, scalable virtual servers (droplets), managed databases, and other cloud services to deploy and manage applications efficiently. @@ -22,6 +24,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of DigitalOcean with authentik, you need to create a scope mapping, an application/provider pair, and application entitlements for the DigitalOcean roles that users should receive. ### Create a scope mapping @@ -72,7 +76,7 @@ To support the integration of DigitalOcean with authentik, you need to create a - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://cloud.digitalocean.com/sessions/sso/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://cloud.digitalocean.com/sessions/sso/callback`. - Select any available signing key. - Under **Advanced protocol settings**: - Add the `profile` scope created in the previous section. Do not remove authentik’s `authentik default OAuth Mapping: OpenID 'profile'`, as claims such as `name` are required by DigitalOcean. diff --git a/website/integrations/cloud-providers/oracle-cloud/index.md b/website/integrations/cloud-providers/oracle-cloud/index.md index 70ba59ce8b..2eb4bea93e 100644 --- a/website/integrations/cloud-providers/oracle-cloud/index.md +++ b/website/integrations/cloud-providers/oracle-cloud/index.md @@ -4,6 +4,8 @@ sidebar_label: Oracle Cloud support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Oracle Cloud? > Oracle Cloud is the first public cloud built from the ground up to be a better cloud for every application. By rethinking core engineering and systems design for cloud computing, we created innovations that accelerate migrations, deliver better reliability and performance for all applications, and offer the complete services customers need to build innovative cloud applications. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Oracle Cloud with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -35,7 +39,7 @@ To support the integration of Oracle Cloud with authentik, you need to create an - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://tenant.identity.oraclecloud.com/oauth2/v1/social/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://tenant.identity.oraclecloud.com/oauth2/v1/social/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/dashboards/dashy/index.md b/website/integrations/dashboards/dashy/index.md index 382d70586f..580e689017 100644 --- a/website/integrations/dashboards/dashy/index.md +++ b/website/integrations/dashboards/dashy/index.md @@ -4,6 +4,8 @@ sidebar_label: Dashy support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Dashy? > Dashy is a self-hostable personal dashboard built for you. Includes status-checking, widgets, themes, icon packs, a UI editor and tons more. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Dashy with authentik, you need to create an application/provider pair in authentik. If you want to manage Dashy administrator access through authentik, create or choose a group for Dashy administrators and add the appropriate users to it. Note the exact group name because it will be required later. @@ -36,7 +40,7 @@ If you want to manage Dashy administrator access through authentik, create or ch - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **slug** values because they will be required later. - Set the **Client type** to `Public`. Dashy runs entirely in the browser and does not store a client secret. - - Create two `Strict` redirect URIs: + - Add two **Redirect URIs** of type `Strict` `Authorization`: - `https://dashy.company` - `https://dashy.company/` - Select any available signing key. diff --git a/website/integrations/dashboards/homarr/index.md b/website/integrations/dashboards/homarr/index.md index 0005de3bcc..550e93b9e8 100644 --- a/website/integrations/dashboards/homarr/index.md +++ b/website/integrations/dashboards/homarr/index.md @@ -4,6 +4,8 @@ sidebar_label: Homarr support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Homarr? > A sleek, modern dashboard that puts all of your apps and services at your fingertips. Control everything in one convenient location. Seamlessly integrates with the apps you've added, providing you with valuable information. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Homarr with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Homarr with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Create two `Strict` redirect URIs: `https://homarr.company/api/auth/callback/oidc` and `http://localhost:50575/api/auth/callback/oidc`. + - Add two **Redirect URIs** of type `Strict` `Authorization` as `https://homarr.company/api/auth/callback/oidc` and `http://localhost:50575/api/auth/callback/oidc`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/dashboards/linkwarden/index.md b/website/integrations/dashboards/linkwarden/index.md index 60cffdfc14..73d572ed29 100644 --- a/website/integrations/dashboards/linkwarden/index.md +++ b/website/integrations/dashboards/linkwarden/index.md @@ -4,6 +4,8 @@ sidebar_label: Linkwarden support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Linkwarden? > Linkwarden is an open-source collaborative bookmark manager used to collect, organize, and preserve webpages. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Linkwarden with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Linkwarden with authentik, you need to create an a - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://linkwarden.company/api/v1/auth/callback/authentik`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://linkwarden.company/api/v1/auth/callback/authentik`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/development/coder/index.md b/website/integrations/development/coder/index.md index a0d75d89eb..94570c3081 100644 --- a/website/integrations/development/coder/index.md +++ b/website/integrations/development/coder/index.md @@ -4,6 +4,8 @@ sidebar_label: Coder support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Coder? > Coder is an open-source platform that provides browser-based cloud development environments, enabling developers and teams to securely write, edit, and manage code remotely without the need for local setup. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Coder with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Coder with authentik, you need to create an applic - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://coder.company/api/v2/users/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://coder.company/api/v2/users/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/development/engomo/index.mdx b/website/integrations/development/engomo/index.mdx index d9cedfb59f..c8f3967bf3 100644 --- a/website/integrations/development/engomo/index.mdx +++ b/website/integrations/development/engomo/index.mdx @@ -4,6 +4,8 @@ sidebar_label: engomo support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is engomo? > engomo is a low-code app development platform to create enterprise apps for smartphones and tablets based on Android, iOS, or iPadOS. @@ -25,6 +27,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Engomo with authentik, you need to create an application/provider pair in authentik. ### Create property mappings @@ -46,7 +50,7 @@ To support the integration of Engomo with authentik, you need to create an appli - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **slug** values because they will be required later. - Set the **Client type** to `Public`. - - Add two `Strict` redirect URIs and set them to `https://engomo.company/auth` and `com.engomo.engomo://callback/`. + - Add two **Redirect URIs** of type `Strict` `Authorization` as `https://engomo.company/auth` and `com.engomo.engomo://callback/`. - Select any available signing key. - Under **Advanced protocol settings**, add the scope you just created to the list of available scopes. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/development/forgejo/index.md b/website/integrations/development/forgejo/index.md index a29b10f261..df34aa3bf3 100644 --- a/website/integrations/development/forgejo/index.md +++ b/website/integrations/development/forgejo/index.md @@ -4,6 +4,8 @@ sidebar_label: Forgejo support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Forgejo? > Forgejo is a lightweight, self‑hosted alternative to GitHub/GitLab, with a strong emphasis on community governance and open development. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Forgejo with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Forgejo with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https:///user/oauth2/authentik/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https:///user/oauth2/authentik/callback`. - Select any available signing key. - Under **Advanced protocol settings** > **Selected Scopes**, add `authentik default OAuth Mapping: OpenID 'entitlements'`. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/development/frappe/index.md b/website/integrations/development/frappe/index.md index e5664a78a1..b893d8de94 100644 --- a/website/integrations/development/frappe/index.md +++ b/website/integrations/development/frappe/index.md @@ -4,6 +4,8 @@ sidebar_label: Frappe support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + :::info These instructions apply to all projects in the Frappe Family, including ERPNext. ::: @@ -28,6 +30,8 @@ This documentation only lists the settings that have been changed from their def ## authentik configuration + + To support the integration of Frappe with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -39,7 +43,7 @@ To support the integration of Frappe with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://frappe.company/api/method/frappe.integrations.oauth2_logins.custom/`. Replace `` with the name of the provider in Frappe. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://frappe.company/api/method/frappe.integrations.oauth2_logins.custom/`. Replace `` with the name of the provider in Frappe. - Select any available signing key. - Under **Advanced protocol settings**, set **Subject mode** to be `Based on the Users's username`. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/development/gitea/index.md b/website/integrations/development/gitea/index.md index 33dfaa2094..eda4ad538f 100644 --- a/website/integrations/development/gitea/index.md +++ b/website/integrations/development/gitea/index.md @@ -4,6 +4,8 @@ sidebar_label: Gitea support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Gitea? > Gitea is a community managed lightweight code hosting solution written in Go. It is published under the MIT license. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Gitea with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Gitea with authentik, you need to create an applic - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https:///user/oauth2/authentik/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https:///user/oauth2/authentik/callback`. - Select any available signing key. - Under **Advanced protocol settings** > **Selected Scopes**, add `authentik default OAuth Mapping: OpenID 'entitlements'`. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/development/gitlab/index.mdx b/website/integrations/development/gitlab/index.mdx index 6154cc6239..e8e243e85d 100644 --- a/website/integrations/development/gitlab/index.mdx +++ b/website/integrations/development/gitlab/index.mdx @@ -4,6 +4,8 @@ sidebar_label: GitLab support_level: authentik --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is GitLab? > GitLab is a complete DevOps platform with features for version control, CI/CD, issue tracking, and collaboration, facilitating efficient software development and deployment workflows. @@ -43,6 +45,8 @@ import Tabs from "@theme/Tabs"; ## authentik configuration + + To support the integration of GitLab with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -110,7 +114,7 @@ To support the integration of GitLab with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://gitlab.company/users/auth/openid_connect/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://gitlab.company/users/auth/openid_connect/callback`. - Select any available signing key. - Under **Advanced protocol settings**, set the **Subject mode** to `Based on the User's Email`. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/development/gravitee/index.md b/website/integrations/development/gravitee/index.md index f05fdfd16f..0e4565936f 100644 --- a/website/integrations/development/gravitee/index.md +++ b/website/integrations/development/gravitee/index.md @@ -4,6 +4,8 @@ sidebar_label: Gravitee support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Gravitee? > Gravitee.io API Management is a flexible, lightweight and blazing-fast Open Source solution that helps your organization control who, when and how users access your APIs. @@ -25,6 +27,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Gravitee with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -36,7 +40,7 @@ To support the integration of Gravitee with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Add two `Strict` redirect URI and set them to `https://gravitee.company/user/login` and `https://gravitee.company/console/`. Ensure a trailing slash is present at the end of the second redirect URI. + - Add two **Redirect URIs** of type `Strict` `Authorization` as `https://gravitee.company/user/login` and `https://gravitee.company/console/`. Ensure a trailing slash is present at the end of the second redirect URI. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/development/jenkins/index.md b/website/integrations/development/jenkins/index.md index 0ce37bf2c0..470bc2dd47 100644 --- a/website/integrations/development/jenkins/index.md +++ b/website/integrations/development/jenkins/index.md @@ -4,6 +4,8 @@ sidebar_label: Jenkins support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Jenkins? > The leading open source automation server, Jenkins provides hundreds of plugins to support building, deploying and automating any project. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Jenkins with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Jenkins with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://jenkins.company/securityRealm/finishLogin`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://jenkins.company/securityRealm/finishLogin`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/development/node-red/index.md b/website/integrations/development/node-red/index.md index f0ef11869f..4e21606981 100644 --- a/website/integrations/development/node-red/index.md +++ b/website/integrations/development/node-red/index.md @@ -4,6 +4,8 @@ sidebar_label: Node-RED support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Node-RED? > Node-RED is a programming tool for wiring together hardware devices, APIs and online services in new and interesting ways. @@ -29,6 +31,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Node-RED with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -40,7 +44,7 @@ To support the integration of Node-RED with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://nodered.company/auth/strategy/callback/`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://nodered.company/auth/strategy/callback/`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/device-management/apple/index.md b/website/integrations/device-management/apple/index.md index 5a259e2680..37d0798933 100644 --- a/website/integrations/device-management/apple/index.md +++ b/website/integrations/device-management/apple/index.md @@ -13,6 +13,8 @@ authentik_enterprise: true authentik_preview: true --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Apple Business Manager? > Apple Business Manager is a web-based portal for IT administrators, managers, and procurement professionals to manage devices and automate device enrollment. @@ -71,6 +73,8 @@ Be aware that Apple Business Manager imposes the following restrictions on feder ## authentik configuration + + The workflow to configure authentik as an identity provider for Apple Business Manager involves creating scope mappings, signing keys, a Shared Signals Framework provider, and an OIDC provider/application pair. Together, these components will handle the authentication flow and backchannel communication between authentik and Apple Business Manager. @@ -160,7 +164,7 @@ You will need to create an [OAuth2/OpenID Provider](/docs/add-secure-apps/provid - **Choose a Provider type**: select **OAuth2/OpenID Provider** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://gsa-ws.apple.com/grandslam/GsService2/acs`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://gsa-ws.apple.com/grandslam/GsService2/acs`. - Select any available signing key. - Under **Advanced protocol settings**, in addition to the default scopes, add the four following **Selected Scopes** to the provider. - `Apple Business Manager ssf.manage` diff --git a/website/integrations/device-management/meshcentral/index.md b/website/integrations/device-management/meshcentral/index.md index 226adb7a07..9329c80bc7 100644 --- a/website/integrations/device-management/meshcentral/index.md +++ b/website/integrations/device-management/meshcentral/index.md @@ -4,6 +4,8 @@ sidebar_label: MeshCentral support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is MeshCentral? > MeshCentral is a free, open source, web-based platform for remote device management. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of MeshCentral with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of MeshCentral with authentik, you need to create an - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://meshcentral.company/auth-oidc-callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://meshcentral.company/auth-oidc-callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/device-management/omnissa-workspace-one-access/index.md b/website/integrations/device-management/omnissa-workspace-one-access/index.md index 6b8a5baa32..8bc4bc2330 100644 --- a/website/integrations/device-management/omnissa-workspace-one-access/index.md +++ b/website/integrations/device-management/omnissa-workspace-one-access/index.md @@ -4,6 +4,8 @@ sidebar_label: Omnissa Workspace ONE Access support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Omnissa Workspace ONE Access? > Omnissa Workspace ONE Access, now Omnissa Access, is the identity and access service for the Omnissa Workspace ONE platform. It provides single sign-on, access policies, and identity federation for applications and devices, and can delegate authentication to external identity providers such as authentik. @@ -31,6 +33,8 @@ You can leave the form open in another browser tab while configuring authentik. ## authentik configuration + + To support the integration of Omnissa Workspace ONE Access with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -43,8 +47,8 @@ To support the integration of Omnissa Workspace ONE Access with authentik, you n - Note the **Client ID** and **Client Secret** values because they will be required later. - **Protocol Settings**: - **Redirect URI**: - - Strict: the redirect URI you noted in the Omnissa Workspace ONE Access pre-configuration step. - - Strict: `awgb://oauth2`. This URI is used by the Workspace ONE mobile applications. + - `Strict` `Authorization`: the redirect URI you noted in the Omnissa Workspace ONE Access pre-configuration step. + - `Strict` `Authorization`: `awgb://oauth2`. This URI is used by the Workspace ONE mobile applications. - **Signing Key**: select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/documentation/bookstack/index.mdx b/website/integrations/documentation/bookstack/index.mdx index a73e7894fb..e80c785311 100644 --- a/website/integrations/documentation/bookstack/index.mdx +++ b/website/integrations/documentation/bookstack/index.mdx @@ -4,6 +4,7 @@ sidebar_label: BookStack support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -38,6 +39,8 @@ You can configure Bookstack to use either OIDC or SAML, and this guide explains ## authentik configuration + + To support the integration of BookStack with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -48,7 +51,7 @@ To support the integration of BookStack with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://bookstack.company/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://bookstack.company/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/documentation/dokuwiki/index.md b/website/integrations/documentation/dokuwiki/index.md index 2dd3bc1cb0..1d45852a02 100644 --- a/website/integrations/documentation/dokuwiki/index.md +++ b/website/integrations/documentation/dokuwiki/index.md @@ -4,6 +4,8 @@ sidebar_label: DokuWiki support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is DokuWiki? > DokuWiki is an open source wiki application licensed under GPLv2 and written in the PHP programming language. It works on plain text files and thus does not need a database. Its syntax is similar to the one used by MediaWiki and it is often recommended as a more lightweight, easier to customize alternative to MediaWiki. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of DokuWiki with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik diff --git a/website/integrations/documentation/karakeep/index.md b/website/integrations/documentation/karakeep/index.md index 19d6b625ad..1eb9d46a33 100644 --- a/website/integrations/documentation/karakeep/index.md +++ b/website/integrations/documentation/karakeep/index.md @@ -4,6 +4,8 @@ sidebar_label: Karakeep support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Karakeep? > A self-hostable bookmark-everything app (links, notes and images) with AI-based automatic tagging and full-text search. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Karakeep with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Karakeep with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://karakeep.company/api/auth/callback/custom`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://karakeep.company/api/auth/callback/custom`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/documentation/kitchenowl/index.md b/website/integrations/documentation/kitchenowl/index.md index 87aa24dbb0..802e171e35 100644 --- a/website/integrations/documentation/kitchenowl/index.md +++ b/website/integrations/documentation/kitchenowl/index.md @@ -4,6 +4,8 @@ sidebar_label: KitchenOwl support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is KitchenOwl? > KitchenOwl is a smart self-hosted grocery list and recipe manager. Easily add items to your shopping list before you go shopping. You can also create recipes and set up meal plans to help you organize your cooking. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of KitchenOwl with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of KitchenOwl with authentik, you need to create an a - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret** values because they will be required later. - - Create two `Strict` redirect URIs and set them to `https://kitchenowl.company/signin/redirect` and `kitchenowl:/signin/redirect`. + - Add two **Redirect URIs** of type `Strict` `Authorization` as `https://kitchenowl.company/signin/redirect` and `kitchenowl:/signin/redirect`. 3. Click **Submit** to save the new application and provider. diff --git a/website/integrations/documentation/mealie/index.md b/website/integrations/documentation/mealie/index.md index d21edafe32..96117a7172 100644 --- a/website/integrations/documentation/mealie/index.md +++ b/website/integrations/documentation/mealie/index.md @@ -4,6 +4,8 @@ sidebar_label: Mealie support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Mealie? > Mealie is a self-hosted recipe manager and meal planner. Easily add recipes by providing the URL and Mealie will automatically import the relevant data or add a family recipe with the UI editor. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Mealie with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Mealie with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, , and **slug** values because they will be required later. - - Create two `Strict` redirect URIs and set to `https://mealie.company/login` and `https://mealie.company/login?direct=1`. + - Add two **Redirect URIs** of type `Strict` `Authorization` as `https://mealie.company/login` and `https://mealie.company/login?direct=1`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/documentation/netbox/index.md b/website/integrations/documentation/netbox/index.md index 8a4cdaa9c8..0cdcffef91 100644 --- a/website/integrations/documentation/netbox/index.md +++ b/website/integrations/documentation/netbox/index.md @@ -4,6 +4,8 @@ sidebar_label: NetBox support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is NetBox? > NetBox is the leading solution for modeling and documenting modern networks. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of NetBox with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of NetBox with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://netbox.company/oauth/complete/oidc/`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://netbox.company/oauth/complete/oidc/`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/documentation/outline/index.md b/website/integrations/documentation/outline/index.md index ab058984bc..547fd9cc2e 100644 --- a/website/integrations/documentation/outline/index.md +++ b/website/integrations/documentation/outline/index.md @@ -4,6 +4,8 @@ sidebar_label: Outline support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Outline? > Your team's knowledge base. @@ -24,6 +26,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Outline with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -35,7 +39,7 @@ To support the integration of Outline with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://outline.company/auth/oidc.callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://outline.company/auth/oidc.callback`. - Select any available signing key. - Under **Advanced protocol settings**, set the **Subject Mode** to **Based on the User's username**. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/documentation/paperless-ngx/index.mdx b/website/integrations/documentation/paperless-ngx/index.mdx index 758116cee2..c14dcbbc85 100644 --- a/website/integrations/documentation/paperless-ngx/index.mdx +++ b/website/integrations/documentation/paperless-ngx/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Paperless-ngx support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Paperless-ngx? > Paperless-ngx is an application that indexes your scanned documents and allows you to easily search for documents and store metadata alongside your documents. It was a fork from Paperless-ng, in turn a fork from the original Paperless, neither of which are maintained any longer. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Paperless-ngx with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Paperless-ngx with authentik, you need to create a - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://paperless.company/accounts/oidc/authentik/login/callback/`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://paperless.company/accounts/oidc/authentik/login/callback/`. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. - **Advanced protocol settings**: - **Selected Scopes**: Add the following diff --git a/website/integrations/documentation/papra/index.mdx b/website/integrations/documentation/papra/index.mdx index 06f04fd13a..3ded3f7628 100644 --- a/website/integrations/documentation/papra/index.mdx +++ b/website/integrations/documentation/papra/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Papra support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Papra? > An open-source document management platform designed to help you organize, secure, and archive your files effortlessly. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Papra with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Papra with authentik, you need to create an applic - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **Slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://papra.company/api/auth/oauth2/callback/authentik`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://papra.company/api/auth/oauth2/callback/authentik`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/documentation/tandoor/index.md b/website/integrations/documentation/tandoor/index.md index 75a7259e7c..dde4f187b1 100644 --- a/website/integrations/documentation/tandoor/index.md +++ b/website/integrations/documentation/tandoor/index.md @@ -4,6 +4,8 @@ sidebar_label: Tandoor support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Tandoor? > Application for managing recipes, planning meals and building shopping lists. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Tandoor with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Tandoor with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://tandoor.company/accounts/oidc/authentik/login/callback/`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://tandoor.company/accounts/oidc/authentik/login/callback/`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/documentation/wiki-js/index.md b/website/integrations/documentation/wiki-js/index.md index d02f80d636..9353aec562 100644 --- a/website/integrations/documentation/wiki-js/index.md +++ b/website/integrations/documentation/wiki-js/index.md @@ -4,6 +4,8 @@ sidebar_label: Wiki.js support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Wiki.js? > Wiki.js is a wiki engine running on Node.js and written in JavaScript. It is free software released under the Affero GNU General Public License. It is available as a self-hosted solution or using "single-click" install on the DigitalOcean and AWS marketplace. @@ -33,6 +35,8 @@ Add a _Generic OpenID Connect / OAuth2_ strategy and take note of the _Callback ## authentik configuration + + To support the integration of Wiki.js with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -44,7 +48,7 @@ To support the integration of Wiki.js with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://wiki.company/login/id-from-wiki/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://wiki.company/login/id-from-wiki/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/hypervisors-orchestrators/arcane/index.md b/website/integrations/hypervisors-orchestrators/arcane/index.md index c2ca0a3774..805f50c3b0 100644 --- a/website/integrations/hypervisors-orchestrators/arcane/index.md +++ b/website/integrations/hypervisors-orchestrators/arcane/index.md @@ -4,6 +4,8 @@ sidebar_label: Arcane support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Arcane? > Modern Docker Management, Designed for Everyone. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Arcane with authentik, you need to create an application/provider pair in authentik. ### Create custom scope mapping @@ -53,7 +57,7 @@ Arcane either requires the email scope to return a `true` value for whether the - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://arcane.company/auth/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://arcane.company/auth/oidc/callback`. - Select any available signing key. - Under **Advanced protocol settings**: - Remove the `authentik default OAuth Mapping: OpenID 'email'` scope, and add the custom scope mapping you created above. diff --git a/website/integrations/hypervisors-orchestrators/portainer/index.md b/website/integrations/hypervisors-orchestrators/portainer/index.md index be6161989c..8e43594255 100644 --- a/website/integrations/hypervisors-orchestrators/portainer/index.md +++ b/website/integrations/hypervisors-orchestrators/portainer/index.md @@ -4,6 +4,8 @@ sidebar_label: Portainer support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Portainer? > Portainer is a powerful, GUI-based Container-as-a-Service solution that helps organizations manage and deploy cloud-native applications easily and securely. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Portainer with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -38,7 +42,7 @@ To support the integration of Portainer with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations: - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://portainer.company/`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://portainer.company/`. - Select any available signing key. - Under **Advanced protocol settings** > **Selected Scopes**, add `authentik default OAuth Mapping: OpenID 'entitlements'`. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/hypervisors-orchestrators/proxmox-ve/index.md b/website/integrations/hypervisors-orchestrators/proxmox-ve/index.md index a9506d099f..b388bb87ad 100644 --- a/website/integrations/hypervisors-orchestrators/proxmox-ve/index.md +++ b/website/integrations/hypervisors-orchestrators/proxmox-ve/index.md @@ -4,6 +4,8 @@ sidebar_label: Proxmox VE support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Proxmox VE? > Proxmox Virtual Environment is an open source server virtualization management solution based on QEMU/KVM and LXC. You can manage virtual machines, containers, highly available clusters, storage, and networks with an integrated, easy-to-use web interface or via CLI. Proxmox VE code is licensed under the GNU Affero General Public License, version 3. The project is developed and maintained by Proxmox Server Solutions GmbH. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Proxmox with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -38,7 +42,7 @@ To support the integration of Proxmox with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://proxmox.company:8006`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://proxmox.company:8006`. - Select any available signing key. - Ensure that encryption is disabled. - Under **Advanced protocol settings**: diff --git a/website/integrations/hypervisors-orchestrators/vmware-cloud-director/index.md b/website/integrations/hypervisors-orchestrators/vmware-cloud-director/index.md index eaff37aad4..c969104797 100644 --- a/website/integrations/hypervisors-orchestrators/vmware-cloud-director/index.md +++ b/website/integrations/hypervisors-orchestrators/vmware-cloud-director/index.md @@ -4,6 +4,8 @@ sidebar_label: VMware Cloud Director support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is VMware Cloud Director? > VMware Cloud Director is a platform that enables service providers and enterprises to create multi-tenant virtual data centers (VDCs) from underlying VMware vSphere infrastructure. It supports self-service resource provisioning, secure tenant isolation, and management of compute, storage, and networking via web portals and APIs. @@ -21,6 +23,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of VMware Cloud Director with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -31,7 +35,7 @@ To support the integration of VMware Cloud Director with authentik, you need to - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://clouddirector.company/login/oauth?service=provider`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://clouddirector.company/login/oauth?service=provider`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/flows-stages/bindings/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/hypervisors-orchestrators/vmware-vcenter/index.md b/website/integrations/hypervisors-orchestrators/vmware-vcenter/index.md index da00fb37bd..e4a44cab11 100644 --- a/website/integrations/hypervisors-orchestrators/vmware-vcenter/index.md +++ b/website/integrations/hypervisors-orchestrators/vmware-vcenter/index.md @@ -4,6 +4,8 @@ sidebar_label: VMware vCenter support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is vCenter? > vCenter Server is the centralized management utility for VMware, and is used to manage virtual machines, multiple ESXi hosts, and all dependent components from a single centralized location. VMware vMotion and svMotion require the use of vCenter and ESXi hosts. @@ -25,6 +27,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of vCenter with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -36,7 +40,7 @@ To support the integration of vCenter with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://vcenter.company/ui/login/oauth2/authcode`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://vcenter.company/ui/login/oauth2/authcode`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/hypervisors-orchestrators/xen-orchestra/index.md b/website/integrations/hypervisors-orchestrators/xen-orchestra/index.md index e984d08396..4807639da1 100644 --- a/website/integrations/hypervisors-orchestrators/xen-orchestra/index.md +++ b/website/integrations/hypervisors-orchestrators/xen-orchestra/index.md @@ -4,6 +4,8 @@ sidebar_label: Xen Orchestra support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Xen Orchestra? > Xen Orchestra provides a user friendly web interface for every Xen based hypervisor (XenServer, xcp-ng, etc.). @@ -28,6 +30,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Xen Orchestra with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -39,7 +43,7 @@ To support the integration of Xen Orchestra with authentik, you need to create a - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://xenorchestra.company/signin/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://xenorchestra.company/signin/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/apache-guacamole/index.mdx b/website/integrations/infrastructure/apache-guacamole/index.mdx index a91a85d647..be8e3ed55a 100644 --- a/website/integrations/infrastructure/apache-guacamole/index.mdx +++ b/website/integrations/infrastructure/apache-guacamole/index.mdx @@ -4,6 +4,7 @@ sidebar_label: Apache Guacamole support_level: authentik --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -26,6 +27,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Apache Guacamole with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -37,7 +40,7 @@ To support the integration of Apache Guacamole with authentik, you need to creat - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://guacamole.company/`. If you have configured [Apache Tomcat](https://tomcat.apache.org/) to run Apache Guacamole on a subpath, you will need to update this value accordingly. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://guacamole.company/`. If you have configured [Apache Tomcat](https://tomcat.apache.org/) to run Apache Guacamole on a subpath, you will need to update this value accordingly. - Select any available signing key. - Note that Apache Guacamole does not support session tokens longer than 300 minutes (5 hours). - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/argocd/index.md b/website/integrations/infrastructure/argocd/index.md index ae576f176d..6c201276c3 100644 --- a/website/integrations/infrastructure/argocd/index.md +++ b/website/integrations/infrastructure/argocd/index.md @@ -4,6 +4,8 @@ sidebar_label: ArgoCD support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is ArgoCD? > Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of ArgoCD with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of ArgoCD with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Add two `Strict` redirect URI and set them to `https://argocd.company/api/dex/callback` and `https://localhost:8085/auth/callback`. + - Add two **Redirect URIs** of type `Strict` `Authorization` as `https://argocd.company/api/dex/callback` and `https://localhost:8085/auth/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/harbor/index.md b/website/integrations/infrastructure/harbor/index.md index cb18da1d9c..4d7ec76acc 100644 --- a/website/integrations/infrastructure/harbor/index.md +++ b/website/integrations/infrastructure/harbor/index.md @@ -4,6 +4,8 @@ sidebar_label: Harbor support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Harbor? > Harbor is an open source container image registry that secures images with role-based access control, scans images for vulnerabilities, and signs images as trusted. A CNCF Graduated project, Harbor delivers compliance, performance, and interoperability to help you consistently and securely manage images across cloud native compute platforms like Kubernetes and Docker. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Harbor with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -35,7 +39,7 @@ To support the integration of Harbor with authentik, you need to create an appli - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - **Protocol Settings**: - **Redirect URI**: - - Strict: `https://harbor.company/c/oidc/callback`. + - `Strict` `Authorization`: `https://harbor.company/c/oidc/callback`. - **Signing Key**: select any available signing key. - **Advanced Protocol Settings**: - **Scopes**: add `authentik default OAuth Mapping: OpenID 'offline_access'` to **Selected Scopes**. diff --git a/website/integrations/infrastructure/keycloak/index.mdx b/website/integrations/infrastructure/keycloak/index.mdx index df90fb72c6..b4ba14dc11 100644 --- a/website/integrations/infrastructure/keycloak/index.mdx +++ b/website/integrations/infrastructure/keycloak/index.mdx @@ -4,6 +4,7 @@ sidebar_label: Keycloak support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import SAMLProvider20265Warning from "../../_saml-provider-2026-5-warning.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -39,6 +40,8 @@ Keycloak can be configured to use either OIDC or SAML for federated login source ## authentik configuration + + To support the integration of Keycloak with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -49,7 +52,7 @@ To support the integration of Keycloak with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://keycloak.company/access/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://keycloak.company/access/oidc/callback`. - Set the **Logout URI** to `https://keycloak.company/realms//protocol/openid-connect/logout/backchannel-logout`. - Set the **Logout Method** to `Back-channel`. - Select any available signing key. diff --git a/website/integrations/infrastructure/komodo/index.mdx b/website/integrations/infrastructure/komodo/index.mdx index de4d83794a..a8abba5089 100644 --- a/website/integrations/infrastructure/komodo/index.mdx +++ b/website/integrations/infrastructure/komodo/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Komodo support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Komodo? > Komodo is a web-based application designed to organize and streamline the management of servers, builds, deployments, and automated tasks. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Komodo with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Komodo with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://komodo.company/auth/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://komodo.company/auth/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. - **Configure Launch URL** _(optional)_: set to `https://komodo.company/auth/oidc/login`. diff --git a/website/integrations/infrastructure/minio/index.mdx b/website/integrations/infrastructure/minio/index.mdx index a82346f0c7..e53fc9e4d7 100644 --- a/website/integrations/infrastructure/minio/index.mdx +++ b/website/integrations/infrastructure/minio/index.mdx @@ -4,6 +4,7 @@ sidebar_label: MinIO support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -30,6 +31,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of MinIO with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -40,7 +43,7 @@ To support the integration of MinIO with authentik, you need to create an applic - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://minio.company/oauth_callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://minio.company/oauth_callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/nexterm/index.md b/website/integrations/infrastructure/nexterm/index.md index ab4e0eb326..7a5284b1f3 100644 --- a/website/integrations/infrastructure/nexterm/index.md +++ b/website/integrations/infrastructure/nexterm/index.md @@ -4,6 +4,8 @@ sidebar_label: Nexterm support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Nexterm? > Nexterm is an open-source server management platform for SSH, VNC, and RDP. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Nexterm with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Nexterm with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://nexterm.company/api/auth/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://nexterm.company/api/auth/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/osticket/index.md b/website/integrations/infrastructure/osticket/index.md index 57f6f202b1..e1a5976301 100644 --- a/website/integrations/infrastructure/osticket/index.md +++ b/website/integrations/infrastructure/osticket/index.md @@ -4,6 +4,8 @@ sidebar_label: osTicket support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is osTicket? > osTicket is a web-based, open source user support/ticketing solution. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of osTicket with authentik, you need to create an application/provider pair in authentik. 1. Log in to authentik as an administrator and open the authentik Admin interface. @@ -31,7 +35,7 @@ To support the integration of osTicket with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret** and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://osticket.company/osticket/api/auth/oauth2`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://osticket.company/osticket/api/auth/oauth2`. - Select any available signing key. - Under **Advanced protocol settings**: - **Subject Mode**: `Based on the User's Email` diff --git a/website/integrations/infrastructure/pgadmin/index.md b/website/integrations/infrastructure/pgadmin/index.md index ff0e1fb1fe..8f63db21c0 100644 --- a/website/integrations/infrastructure/pgadmin/index.md +++ b/website/integrations/infrastructure/pgadmin/index.md @@ -4,6 +4,8 @@ sidebar_label: pgAdmin support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is pgAdmin? > pgAdmin is a management tool for PostgreSQL and derivative relational databases such as EnterpriseDB's EDB Advanced Server. It may be run either as a web or desktop application. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of pgAdmin with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -37,7 +41,7 @@ To support the integration of pgAdmin with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://pgadmin.company/oauth2/authorize`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://pgadmin.company/oauth2/authorize`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/plesk/index.md b/website/integrations/infrastructure/plesk/index.md index 9a261458a7..54d57cd237 100644 --- a/website/integrations/infrastructure/plesk/index.md +++ b/website/integrations/infrastructure/plesk/index.md @@ -4,6 +4,8 @@ sidebar_label: Plesk support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Plesk? > Plesk is a web hosting platform with a control panel that helps manage servers, applications, and websites through a comprehensive graphical user interface. It provides tools for web professionals, IT administrators, and hosting companies to simplify the process of hosting and managing websites. @@ -27,6 +29,8 @@ Replace these placeholders in the guide with your values: ## authentik configuration + + To support the integration of Plesk with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -38,7 +42,7 @@ To support the integration of Plesk with authentik, you need to create an applic - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://plesk.company/modules/oauth/public/login.php`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://plesk.company/modules/oauth/public/login.php`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/rabbitmq/index.mdx b/website/integrations/infrastructure/rabbitmq/index.mdx index 5b10602f2b..cf4d6d9b25 100644 --- a/website/integrations/infrastructure/rabbitmq/index.mdx +++ b/website/integrations/infrastructure/rabbitmq/index.mdx @@ -4,6 +4,7 @@ sidebar_label: RabbitMQ support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -28,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of RabbitMQ with authentik, you need to create a property mapping, two user groups, and an application/provider pair. ### Create a property mapping @@ -66,7 +69,7 @@ After creating the groups, select a group, navigate to the **Users** tab, and ma - Set **Client Type** to **Public**. - Note the **Client ID** and **slug** values because they will be required later. - Under **Grant Types**, select **Authorization Code** and **Client credentials**. - - Set a `Strict` redirect URI to `https://rabbitmq.company:15672/js/oidc-oauth/login-callback.html`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://rabbitmq.company:15672/js/oidc-oauth/login-callback.html`. - Select any available signing key. - Under **Advanced protocol settings**: - Add the `RabbitMQ claims` scope that you created in the previous section to **Selected Scopes**. diff --git a/website/integrations/infrastructure/rustdesk-pro/index.mdx b/website/integrations/infrastructure/rustdesk-pro/index.mdx index f50a6e2052..4aef8bb2ce 100644 --- a/website/integrations/infrastructure/rustdesk-pro/index.mdx +++ b/website/integrations/infrastructure/rustdesk-pro/index.mdx @@ -4,6 +4,8 @@ sidebar_label: RustDesk Server Pro support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is RustDesk Server Pro? > RustDesk Server Pro is a premium self-hosted solution for managing remote desktop connections securely and efficiently. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Rustdesk Server Pro with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -38,7 +42,7 @@ To support the integration of Rustdesk Server Pro with authentik, you need to cr - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://rustdesk.company/api/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://rustdesk.company/api/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/semaphore/index.mdx b/website/integrations/infrastructure/semaphore/index.mdx index e2e7f7117a..4ffdeb8337 100644 --- a/website/integrations/infrastructure/semaphore/index.mdx +++ b/website/integrations/infrastructure/semaphore/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Semaphore support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Semaphore UI? > Semaphore UI is a modern web interface for managing popular DevOps tools. @@ -25,6 +27,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Semaphore with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -35,7 +39,7 @@ To support the integration of Semaphore with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://semaphore.company/api/auth/oidc/authentik/redirect`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://semaphore.company/api/auth/oidc/authentik/redirect`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/synology-dsm/index.md b/website/integrations/infrastructure/synology-dsm/index.md index b3d9fe326a..c5811b0909 100644 --- a/website/integrations/infrastructure/synology-dsm/index.md +++ b/website/integrations/infrastructure/synology-dsm/index.md @@ -4,6 +4,8 @@ sidebar_label: Synology DSM (DiskStation Manager) support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Synology DSM? > Synology Inc. is a Taiwanese corporation that specializes in network-attached storage (NAS) appliances. Synology's line of NAS is known as the DiskStation for desktop models, FlashStation for all-flash models, and RackStation for rack-mount models. Synology's products are distributed worldwide and localized in several languages. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Synology DSM with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -38,7 +42,7 @@ To support the integration of Synology DSM with authentik, you need to create an - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://synology.company`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://synology.company`. - Select any available signing key. - Under **Advanced protocol settings**, set the **subject mode** to be based on the user's email. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/termix/index.mdx b/website/integrations/infrastructure/termix/index.mdx index 5db31fb6ce..4eac67e7a4 100644 --- a/website/integrations/infrastructure/termix/index.mdx +++ b/website/integrations/infrastructure/termix/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Termix support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Termix? > Termix is a clientless web-based server management platform with SSH terminal, tunneling, and file editing capabilities. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Termix with authentik, you need to create an application/provider pair in authentik. 1. Log in to authentik as an administrator and open the authentik Admin interface. @@ -31,7 +35,7 @@ To support the integration of Termix with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://termix.company/users/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://termix.company/users/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/terrakube/index.md b/website/integrations/infrastructure/terrakube/index.md index 10f7a4f35a..b10aba8f25 100644 --- a/website/integrations/infrastructure/terrakube/index.md +++ b/website/integrations/infrastructure/terrakube/index.md @@ -4,6 +4,8 @@ sidebar_label: Terrakube support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Terrakube? > Terrakube is an open-source collaboration platform designed for managing remote Infrastructure-as-Code (IaC) operations with Terraform. It serves as an alternative to proprietary tools like Terraform Enterprise. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Terrakube with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Terrakube with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://terrakube-dex.company/dex/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://terrakube-dex.company/dex/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/zammad/index.md b/website/integrations/infrastructure/zammad/index.md index 6cc586b61d..13788cac5c 100644 --- a/website/integrations/infrastructure/zammad/index.md +++ b/website/integrations/infrastructure/zammad/index.md @@ -4,6 +4,7 @@ sidebar_label: Zammad support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; import SAMLProvider20265Warning from "../../\_saml-provider-2026-5-warning.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -40,6 +41,8 @@ values={[ ## authentik configuration + + To support the integration of Zammad with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -102,7 +105,7 @@ To support the integration of Zammad with authentik, you need to create an appli - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Set the **Client type** to `Public`. - Take note of the **Client ID** and **slug** values because they will be required later. - - Set the **Redirect URIs/Origins** to `Strict` / `https://zammad.company/auth/openid_connect/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://zammad.company/auth/openid_connect/callback`. - Select a **Signing Key**. - Under **Advanced protocol settings**, set **Subject mode** to **Based on the User's Email**. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/zendesk/index.mdx b/website/integrations/infrastructure/zendesk/index.mdx index 2ea808ab58..3897cc8bd6 100644 --- a/website/integrations/infrastructure/zendesk/index.mdx +++ b/website/integrations/infrastructure/zendesk/index.mdx @@ -4,6 +4,7 @@ sidebar_label: Zendesk support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -38,6 +39,8 @@ Zendesk can be configured to use either OIDC or SAML. This guide covers both met ## authentik configuration + + To support the integration of Zendesk with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -48,7 +51,7 @@ To support the integration of Zendesk with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://company.zendesk.com/access/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://company.zendesk.com/access/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/infrastructure/zot/index.md b/website/integrations/infrastructure/zot/index.md index 4c6b0945be..3c8f47151d 100644 --- a/website/integrations/infrastructure/zot/index.md +++ b/website/integrations/infrastructure/zot/index.md @@ -4,6 +4,8 @@ sidebar_label: Zot support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Zot? > Zot is an OCI-native container registry for distributing container images and OCI artifacts. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Zot with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -35,11 +39,9 @@ To support the integration of Zot with authentik, you need to create an applicat - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - **Protocol Settings**: - **Redirect URI**: - - Strict: `https://zot.company/zot/auth/callback/oidc`. + - `Strict` `Authorization`: `https://zot.company/zot/auth/callback/oidc`. - **Signing Key**: select any available signing key. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://zot.company/zot/auth/callback/oidc`. - - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. 3. Click **Submit** to save the new application and provider. diff --git a/website/integrations/learning/absorb-lms/index.mdx b/website/integrations/learning/absorb-lms/index.mdx index 2445d92fd1..f29b7e71fc 100644 --- a/website/integrations/learning/absorb-lms/index.mdx +++ b/website/integrations/learning/absorb-lms/index.mdx @@ -5,6 +5,7 @@ support_level: community authentik_version: 2026.5 --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import SAMLProvider20265Warning from "../../_saml-provider-2026-5-warning.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -39,6 +40,8 @@ values={[ ## authentik configuration + + To integrate authentik with Absorb LMS via OIDC, you will need to create an application and provider pair in authentik. ### Create an application and provider in authentik @@ -49,7 +52,7 @@ To integrate authentik with Absorb LMS via OIDC, you will need to create an appl - **Choose a Provider type**: select **OAuth2/OIDC Provider** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Take note of the **Client ID** and **Client Secret** values as these will be required in the next section. - - Set a `Strict` Redirect URI to `https://company.myabsorb.com/account/openidconnect` + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://company.myabsorb.com/account/openidconnect` - Select any available **Signing key**. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications in a user's **Application Dashboard**. diff --git a/website/integrations/media/audiobookshelf/index.md b/website/integrations/media/audiobookshelf/index.md index b99aeebec9..0918f4713b 100644 --- a/website/integrations/media/audiobookshelf/index.md +++ b/website/integrations/media/audiobookshelf/index.md @@ -4,6 +4,8 @@ sidebar_label: Audiobookshelf support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Audiobookshelf? > Audiobookshelf is a self-hosted audiobook and podcast server. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Audiobookshelf with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik diff --git a/website/integrations/media/freshrss/index.mdx b/website/integrations/media/freshrss/index.mdx index ebc10d11f8..9945828a29 100644 --- a/website/integrations/media/freshrss/index.mdx +++ b/website/integrations/media/freshrss/index.mdx @@ -4,6 +4,8 @@ sidebar_label: FreshRSS support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is FreshRSS? > FreshRSS is a self-hosted RSS feed aggregator. @@ -23,6 +25,8 @@ This documentation only lists the settings that have been changed from their def ## authentik configuration + + To support the integration of FreshRSS with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of FreshRSS with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Add two `Strict` redirect URIs and set them to `https://freshrss.company/i/oidc/` and `https://freshrss.company:443/i/oidc/`. If FreshRSS is exposed on a port other than `443`, update the second redirect URI accordingly. + - Add two **Redirect URIs** of type `Strict` `Authorization` as `https://freshrss.company/i/oidc/` and `https://freshrss.company:443/i/oidc/`. If FreshRSS is exposed on a port other than `443`, update the second redirect URI accordingly. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/media/immich/index.md b/website/integrations/media/immich/index.md index 9668fc947c..c8212d7fb1 100644 --- a/website/integrations/media/immich/index.md +++ b/website/integrations/media/immich/index.md @@ -4,6 +4,8 @@ sidebar_label: Immich support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Immich? > Immich is a self-hosted backup solution for photos and videos on mobile devices. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Immich with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Immich with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Add three `Strict` redirect URIs and set them to `app.immich:///oauth-callback`, `https://immich.company/auth/login`, and `https://immich.company/user-settings`. + - Add three **Redirect URIs** of type `Strict` `Authorization` as `app.immich:///oauth-callback`, `https://immich.company/auth/login`, and `https://immich.company/user-settings`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. - **Configure Launch URL** _(optional)_: set the [Launch URL](/docs/add-secure-apps/applications/#appearance) to `https://immich.company/auth/login?autoLaunch=1` to allow automatic login to Immich when clicking the application from within authentik. diff --git a/website/integrations/media/jellyfin/index.md b/website/integrations/media/jellyfin/index.md index f0252d06fd..815be053f5 100644 --- a/website/integrations/media/jellyfin/index.md +++ b/website/integrations/media/jellyfin/index.md @@ -4,6 +4,8 @@ sidebar_label: Jellyfin support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Jellyfin? > Jellyfin is a free and open source media management and streaming platform for movies, TV shows, and music. @@ -95,6 +97,8 @@ At this point, enter a username and click **Save Search Attribute Settings and Q ## OIDC configuration + + ### authentik configuration **Provider Settings** @@ -102,7 +106,7 @@ At this point, enter a username and click **Save Search Attribute Settings and Q In authentik under **Providers**, create an OAuth2/OpenID Provider with these settings: - Name: `jellyfin` -- Redirect URI: `https://jellyfin.company/sso/OID/redirect/authentik` +- **Redirect URI**: `Strict` `Authorization` `https://jellyfin.company/sso/OID/redirect/authentik` Everything else is up to you, just make sure to grab the client ID and the client secret! diff --git a/website/integrations/media/komga/index.md b/website/integrations/media/komga/index.md index 10ed952c3c..27cb7f3cc0 100644 --- a/website/integrations/media/komga/index.md +++ b/website/integrations/media/komga/index.md @@ -4,6 +4,8 @@ sidebar_label: Komga support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Komga? > Komga is an open-source comic and manga server that lets users organize, read, and stream their digital comic collections with ease. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Komga with authentik, you need to create an application/provider pair in authentik. ### Create an email verification scope mapping in authentik @@ -40,7 +44,7 @@ Refer to [Email scope verification](/docs/add-secure-apps/providers/oauth2/index - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://komga.company/login/oauth2/code/authentik`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://komga.company/login/oauth2/code/authentik`. - Select any available signing key. - **Advanced protocol settings** > **Scopes**: - Add `OAuth Mapping: OpenID 'email' with "email_verified"` to the **Selected Scopes**. diff --git a/website/integrations/media/miniflux/index.md b/website/integrations/media/miniflux/index.md index 9bea7a0a77..97f98adf79 100644 --- a/website/integrations/media/miniflux/index.md +++ b/website/integrations/media/miniflux/index.md @@ -4,6 +4,8 @@ sidebar_label: Miniflux support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Miniflux? > Miniflux is a minimalist and opinionated RSS feed reader. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Miniflux with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Miniflux with authentik, you need to create an app - **Choose a Provider type**: Select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://miniflux.company/oauth2/oidc/callback` + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://miniflux.company/oauth2/oidc/callback` - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/media/photoprism/index.md b/website/integrations/media/photoprism/index.md index 9857859d1e..287fb75624 100644 --- a/website/integrations/media/photoprism/index.md +++ b/website/integrations/media/photoprism/index.md @@ -4,6 +4,8 @@ sidebar_label: PhotoPrism support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is PhotoPrism? > PhotoPrism is an AI-powered photos app that lets you browse, organize, and find photos and videos on a home server, private server, or in the cloud. @@ -27,6 +29,8 @@ PhotoPrism requires HTTPS for OpenID Connect (OIDC). Make sure that the `PHOTOPR ## authentik configuration + + To support the integration of PhotoPrism with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -37,7 +41,7 @@ To support the integration of PhotoPrism with authentik, you need to create an a - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Add one `Strict` redirect URI and set it to `https://photoprism.company/api/v1/oidc/redirect`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://photoprism.company/api/v1/oidc/redirect`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/media/seafile/index.md b/website/integrations/media/seafile/index.md index 67e2e2dec9..4b5e99fbfd 100644 --- a/website/integrations/media/seafile/index.md +++ b/website/integrations/media/seafile/index.md @@ -4,6 +4,8 @@ sidebar_label: Seafile support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Seafile? > Seafile is an open-source, cross-platform file-hosting software system. Files are stored on a central server and can be synchronized with personal computers and mobile devices through apps. Files on the Seafile server can also be accessed directly via the server's web interface. @@ -22,6 +24,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Seafile with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -32,7 +36,7 @@ To support the integration of Seafile with authentik, you need to create an appl - **Choose a Provider type**: select OAuth2/OpenID Connect as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://seafile.company/oauth/callback/`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://seafile.company/oauth/callback/`. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. 3. Click **Submit** to save the new application and provider. diff --git a/website/integrations/media/seerr/index.md b/website/integrations/media/seerr/index.md index f6e1cc3a35..74a2a527a6 100644 --- a/website/integrations/media/seerr/index.md +++ b/website/integrations/media/seerr/index.md @@ -4,6 +4,8 @@ sidebar_label: Seerr support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Seerr? > Seerr (previously Jellyseerr) is a free and open source application for managing requests in your media library. It integrates with media servers like Jellyfin, Plex, and Emby, and services such as Sonarr and Radarr. @@ -17,6 +19,8 @@ support_level: community ## authentik configuration + + To support the integration of Seerr with authentik, you need to create an application/provider pair in authentik. 1. Log in to authentik as an administrator and open the authentik Admin interface. @@ -25,7 +29,7 @@ To support the integration of Seerr with authentik, you need to create an applic - **Choose a Provider type**: OAuth2/OpenID - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and any required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://seerr.company/login`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://seerr.company/login`. - Select any available signing key. - **Configure Bindings** _(optional):_ you can create a [binding](https://docs.goauthentik.io/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user’s **Application Dashboard** page. diff --git a/website/integrations/miscellaneous/actual-budget/index.mdx b/website/integrations/miscellaneous/actual-budget/index.mdx index 1ecc595a90..f04328b09c 100644 --- a/website/integrations/miscellaneous/actual-budget/index.mdx +++ b/website/integrations/miscellaneous/actual-budget/index.mdx @@ -4,6 +4,7 @@ sidebar_label: Actual Budget support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -26,6 +27,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Actual Budget with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -36,7 +39,7 @@ To support the integration of Actual Budget with authentik, you need to create a - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://actual.company/openid/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://actual.company/openid/callback`. - Select any available signing key. Actual Budget only supports the RS256 algorithm. Be aware of this when choosing a signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/miscellaneous/adventurelog/index.mdx b/website/integrations/miscellaneous/adventurelog/index.mdx index a599de2c8a..b81f0afc60 100644 --- a/website/integrations/miscellaneous/adventurelog/index.mdx +++ b/website/integrations/miscellaneous/adventurelog/index.mdx @@ -4,6 +4,8 @@ sidebar_label: AdventureLog support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is AdventureLog? > AdventureLog is a self-hosted travel tracker and trip planner. AdventureLog is the ultimate travel companion for the modern-day explorer. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of AdventureLog with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of AdventureLog with authentik, you need to create an - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Regex` redirect URI to `^https://adventurelog.company/accounts/oidc/.\*$`. + - Add a **Redirect URI** of type `Regex` `Authorization` as `^https://adventurelog.company/accounts/oidc/.\*$`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/miscellaneous/ezbookkeeping/index.mdx b/website/integrations/miscellaneous/ezbookkeeping/index.mdx index d16aaf1c2b..fd98dbd539 100644 --- a/website/integrations/miscellaneous/ezbookkeeping/index.mdx +++ b/website/integrations/miscellaneous/ezbookkeeping/index.mdx @@ -4,6 +4,7 @@ sidebar_label: ezBookkeeping support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -26,6 +27,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of ezBookkeeping with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -36,7 +39,7 @@ To support the integration of ezBookkeeping with authentik, you need to create a - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://ezbookkeeping.company/oauth2/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://ezbookkeeping.company/oauth2/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/miscellaneous/filerise/index.mdx b/website/integrations/miscellaneous/filerise/index.mdx index 0311d22e73..783d388e57 100644 --- a/website/integrations/miscellaneous/filerise/index.mdx +++ b/website/integrations/miscellaneous/filerise/index.mdx @@ -4,6 +4,8 @@ sidebar_label: FileRise support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is FileRise? > Lightweight, self-hosted web-based file manager with multi-file upload, editing, and batch operations. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of FileRise with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of FileRise with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set **Redirect URI** to `https://filerise.company/api/auth/auth.php?oidc=callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://filerise.company/api/auth/auth.php?oidc=callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/miscellaneous/home-assistant/index.md b/website/integrations/miscellaneous/home-assistant/index.md index 6ea250576a..f7d6e83d4c 100644 --- a/website/integrations/miscellaneous/home-assistant/index.md +++ b/website/integrations/miscellaneous/home-assistant/index.md @@ -4,6 +4,8 @@ sidebar_label: Home Assistant support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Home Assistant? @@ -47,6 +49,8 @@ values={[ ## authentik configuration + + To support the integration of Home Assistant with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -58,7 +62,7 @@ To support the integration of Home Assistant with authentik, you need to create - Choose a **Provider Type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://hass.company/auth/openid/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://hass.company/auth/openid/callback`. - Select any available signing key (to use the RS256 `id_token_signing_alg`) - Configure Bindings (optional): you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. @@ -109,7 +113,7 @@ To support the integration of Home Assistant with authentik, you need to create - Choose a **Provider Type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://hass.company/auth/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://hass.company/auth/oidc/callback`. - Select any available signing key (to use the RS256 `id_token_signing_alg`) - Configure Bindings (optional): you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/miscellaneous/open-webui/index.md b/website/integrations/miscellaneous/open-webui/index.md index a5dfbc91f9..c5ceb67eaa 100644 --- a/website/integrations/miscellaneous/open-webui/index.md +++ b/website/integrations/miscellaneous/open-webui/index.md @@ -4,6 +4,8 @@ sidebar_label: Open WebUI support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Open WebUI? > Open WebUI is a simple, self-hosted AI platform that works entirely offline. It supports tools like Ollama and OpenAI-style APIs and has a built-in engine for RAG tasks. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Open WebUI with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Open WebUI with authentik, you need to create an a - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://openwebui.company/oauth/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://openwebui.company/oauth/oidc/callback`. - Select any available signing key. - Make sure to leave the **Encryption Key** field empty. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/miscellaneous/wallos/index.mdx b/website/integrations/miscellaneous/wallos/index.mdx index b24f151b0e..7606385b16 100644 --- a/website/integrations/miscellaneous/wallos/index.mdx +++ b/website/integrations/miscellaneous/wallos/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Wallos support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Wallos? > Wallos is a self-hosted subscription and budget planning application. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Wallos with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Wallos with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://wallos.company/index.php`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://wallos.company/index.php`. - Select any available signing key. - **Configure Bindings** (optional): you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/miscellaneous/zipline/index.md b/website/integrations/miscellaneous/zipline/index.md index 38f1e5997f..814477df42 100644 --- a/website/integrations/miscellaneous/zipline/index.md +++ b/website/integrations/miscellaneous/zipline/index.md @@ -4,6 +4,8 @@ sidebar_label: Zipline support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Zipline? > Zipline is a self-hostable file upload server designed for easy file sharing, supporting tools like ShareX and Flameshot, with features such as simplified setup and extensive customization options. @@ -27,6 +29,8 @@ This guide is compatible with Zipline [version `v4.0.0`](https://github.com/dice ## authentik configuration + + To support the integration of Zipline with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -38,7 +42,7 @@ To support the integration of Zipline with authentik, you need to create an appl - **Choose a Provider type**: Select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: Provide a name (or accept the auto-provided name), choose the authorization flow for this provider, and configure the following required settings: - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://zipline.company/api/auth/oauth/oidc`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://zipline.company/api/auth/oauth/oidc`. - Select any available signing key. - Under **Advanced protocol settings** > **Scopes**, add `authentik default OAuth Mapping: OpenID 'offline_access'` to the **Selected Scopes** list. - **Configure Bindings** _(optional)_: Create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/monitoring/beszel/index.mdx b/website/integrations/monitoring/beszel/index.mdx index e7a3c01b8c..ebe9f916cc 100644 --- a/website/integrations/monitoring/beszel/index.mdx +++ b/website/integrations/monitoring/beszel/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Beszel support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Beszel? > Beszel is a lightweight server monitoring platform that provides Docker statistics, historical data, and configurable alerts. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + The steps to configure authentik include creating an email verification scope mapping, creating an application and provider pair in authentik, obtaining the Client ID and Client Secret values, setting the redirect URI, and selecting a signing key. ### Create an email verification scope mapping in authentik @@ -44,7 +48,7 @@ Refer to [Email scope verification](/docs/add-secure-apps/providers/oauth2/index - **Choose a Provider type**: OAuth2/OpenID - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and any required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://beszel.company/api/oauth2-redirect`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://beszel.company/api/oauth2-redirect`. - Select any available signing key. - **Advanced protocol settings** > **Scopes**: - Add `OAuth Mapping: OpenID 'email' with "email_verified"` to the **Selected Scopes**. diff --git a/website/integrations/monitoring/chronograf/index.mdx b/website/integrations/monitoring/chronograf/index.mdx index e8d7bc2f6c..5ed04465f5 100644 --- a/website/integrations/monitoring/chronograf/index.mdx +++ b/website/integrations/monitoring/chronograf/index.mdx @@ -3,6 +3,8 @@ title: Integrate with Chronograf sidebar_label: Chronograf --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Chronograf? > Chronograf lets you quickly visualize the data stored in InfluxDB, enabling you to build robust queries and alerts. It is simple to use and comes with templates and libraries for rapidly creating dashboards with real-time data visualizations. @@ -22,6 +24,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Chronograf with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Chronograf with authentik, you need to create an a - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://chronograf.company/oauth/authentik/callback/`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://chronograf.company/oauth/authentik/callback/`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/monitoring/gatus/index.mdx b/website/integrations/monitoring/gatus/index.mdx index 7a1b81b638..a4fe0a9362 100644 --- a/website/integrations/monitoring/gatus/index.mdx +++ b/website/integrations/monitoring/gatus/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Gatus support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Gatus? > Gatus is a developer-oriented health dashboard that gives you the ability to monitor your services using HTTP, ICMP, TCP, and even DNS queries as well as evaluate the result of said queries by using a list of conditions on values like the status code, the response time, the certificate expiration, the body and many others. The icing on top is that each of these health checks can be paired with alerting via Slack, Teams, PagerDuty, Discord, Twilio and many more. @@ -23,6 +25,8 @@ This documentation only lists the settings that have been changed from their def ## authentik configuration + + To support the integration of Gatus with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Gatus with authentik, you need to create an applic - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://gatus.company/authorization-code/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://gatus.company/authorization-code/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/monitoring/glitchtip/index.md b/website/integrations/monitoring/glitchtip/index.md index 0f05c9f64f..feb67a9e65 100644 --- a/website/integrations/monitoring/glitchtip/index.md +++ b/website/integrations/monitoring/glitchtip/index.md @@ -4,6 +4,8 @@ sidebar_label: Glitchtip support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Glitchtip? > Bugs are inevitable in web development. The important thing is to catch them when they appear. With GlitchTip, you can rest easy knowing that if your web app throws an error or goes down, you will be notified immediately. GlitchTip combines error tracking and uptime monitoring in one open-source package to keep you and your team fully up-to-date on the status of your projects. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Glitchtip with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Glitchtip with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://glitchtip.company/accounts/oidc/authentik/login/callback/`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://glitchtip.company/accounts/oidc/authentik/login/callback/`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/monitoring/grafana/index.mdx b/website/integrations/monitoring/grafana/index.mdx index 5fedbdaaf3..43596d0225 100644 --- a/website/integrations/monitoring/grafana/index.mdx +++ b/website/integrations/monitoring/grafana/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Grafana support_level: authentik --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Grafana? > Grafana is a multi-platform open source analytics and interactive visualization web application. It provides charts, graphs, and alerts for the web when connected to supported data sources, Grafana Enterprise version with additional capabilities is also available. It is expandable through a plug-in system. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Grafana with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Grafana with authentik, you need to create an appl - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://grafana.company/login/generic_oauth`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://grafana.company/login/generic_oauth`. - Set the Logout URI to `https://grafana.company/logout`. - Set the Logout Method to `Front-channel`. - Select any available signing key. diff --git a/website/integrations/monitoring/icinga/index.md b/website/integrations/monitoring/icinga/index.md index 06e29e3962..792b203e50 100644 --- a/website/integrations/monitoring/icinga/index.md +++ b/website/integrations/monitoring/icinga/index.md @@ -4,6 +4,8 @@ sidebar_label: Icinga Web 2 support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Icinga Web 2? > Icinga Web 2 is the next-generation web interface for the Icinga monitoring stack. It provides a flexible UI to view monitoring states, drill into problems, and integrate with the Icinga 2 backend. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Icinga Web 2 with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -37,7 +41,7 @@ To support the integration of Icinga Web 2 with authentik, you need to create an - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://icinga.company/icingaweb2/oidc/authentication/realm?name=authentik`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://icinga.company/icingaweb2/oidc/authentication/realm?name=authentik`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/monitoring/observium/index.md b/website/integrations/monitoring/observium/index.md index 4b9e6381c3..d660c5854e 100644 --- a/website/integrations/monitoring/observium/index.md +++ b/website/integrations/monitoring/observium/index.md @@ -4,6 +4,8 @@ sidebar_label: Observium support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Observium? > Observium is a network monitoring and management platform that provides real-time insight into network health and performance. @@ -40,6 +42,8 @@ apt install ./libapache2-mod-auth-openidc_2.4.15.7-1.bookworm_amd64.deb ## authentik configuration + + To support the integration of Observium with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -51,7 +55,7 @@ To support the integration of Observium with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://observium.company/secure/redirect_uri`. Note that the Redirect URI can be anything, as long as it does not point to existing content. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://observium.company/secure/redirect_uri`. Note that the Redirect URI can be anything, as long as it does not point to existing content. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/monitoring/pulse/index.md b/website/integrations/monitoring/pulse/index.md index c5ea687734..da36ce91ec 100644 --- a/website/integrations/monitoring/pulse/index.md +++ b/website/integrations/monitoring/pulse/index.md @@ -4,6 +4,8 @@ sidebar_label: Pulse support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Pulse? > Pulse is an open-source monitoring platform that provides real-time insight into Proxmox, Docker, and Kubernetes infrastructure. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Pulse with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Pulse with authentik, you need to create an applic - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://pulse.company/api/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://pulse.company/api/oidc/callback`. - Select any available signing key. - Under **Advanced protocol settings**, add `authentik default OAuth Mapping: OpenID 'offline_access'` to the selected scopes if you want long-lived sessions backed by refresh tokens. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/monitoring/ubuntu-landscape/index.md b/website/integrations/monitoring/ubuntu-landscape/index.md index f4161b36d9..d4e4deab7d 100644 --- a/website/integrations/monitoring/ubuntu-landscape/index.md +++ b/website/integrations/monitoring/ubuntu-landscape/index.md @@ -4,6 +4,8 @@ sidebar_label: Ubuntu Landscape support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Ubuntu Landscape? > Landscape is a systems management tool developed by Canonical. It can be run on-premises or in the cloud depending on the needs of the user. It is primarily designed for use with Ubuntu derivatives such as Desktop, Server, and Core. @@ -29,6 +31,8 @@ Landscape uses the OpenID Connect protocol for single sign-on. ## authentik configuration + + To support the integration of Landscape with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -40,7 +44,7 @@ To support the integration of Landscape with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://landscape.company/login/handle-openid`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://landscape.company/login/handle-openid`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/monitoring/whats-up-docker/index.md b/website/integrations/monitoring/whats-up-docker/index.md index ed47fd8a62..c85db5da6b 100644 --- a/website/integrations/monitoring/whats-up-docker/index.md +++ b/website/integrations/monitoring/whats-up-docker/index.md @@ -4,6 +4,8 @@ sidebar_label: What's Up Docker support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is What's Up Docker? > What's Up Docker (WUD) is an easy-to-use tool that alerts you whenever a new version of your Docker containers is released. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of What's Up Docker with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of What's Up Docker with authentik, you need to creat - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://wud.company/auth/oidc/authentik/cb`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://wud.company/auth/oidc/authentik/cb`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/networking/firezone/index.md b/website/integrations/networking/firezone/index.md index 7209c8d314..0ed2e1bcfe 100644 --- a/website/integrations/networking/firezone/index.md +++ b/website/integrations/networking/firezone/index.md @@ -4,6 +4,8 @@ sidebar_label: Firezone support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Firezone? > Firezone is an open-source remote access platform built on WireGuard®, a modern VPN protocol that's 4-6x faster than OpenVPN. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Firezone with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -34,7 +38,7 @@ To support the integration of Firezone with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://firezone.company/auth/oidc/authentik/callback/`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://firezone.company/auth/oidc/authentik/callback/`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/networking/gravity/index.md b/website/integrations/networking/gravity/index.md index 01384e25f6..8c4aae2c9e 100644 --- a/website/integrations/networking/gravity/index.md +++ b/website/integrations/networking/gravity/index.md @@ -4,6 +4,8 @@ sidebar_label: Gravity support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Gravity? > Gravity is a fully-replicated DNS, DHCP, and TFTP server powered by [etcd](https://etcd.io/), offering features like built-in caching, ad/privacy blocking, automatic DNS registration, and metric tracking. @@ -27,6 +29,8 @@ Gravity automatically triggers SSO authentication when configured. To prevent th ## authentik configuration + + To support the integration of Gravity with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -38,7 +42,7 @@ To support the integration of Gravity with authentik, you need to create an appl - **Choose a Provider type**: Select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: Provide a name (or accept the auto-provided name), choose the authorization flow for this provider, and configure the following required settings: - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://gravity.company/auth/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://gravity.company/auth/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: Create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/networking/headscale/index.md b/website/integrations/networking/headscale/index.md index 2fa1fd81c6..5cad73276e 100644 --- a/website/integrations/networking/headscale/index.md +++ b/website/integrations/networking/headscale/index.md @@ -4,6 +4,8 @@ sidebar_label: Headscale support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Headscale? > Headscale is an open source alternative to the Tailscale coordination server and can be self-hosted for a single tailnet. Headscale is a re-implemented version of the Tailscale coordination server, developed independently and completely separate from Tailscale, with its own independent community of users and developers. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Headscale with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Headscale with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://headscale.company/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://headscale.company/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/networking/hoop.dev/index.md b/website/integrations/networking/hoop.dev/index.md index c8307cd3fd..679e85679d 100644 --- a/website/integrations/networking/hoop.dev/index.md +++ b/website/integrations/networking/hoop.dev/index.md @@ -4,6 +4,8 @@ sidebar_label: Hoop.dev support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Hoop.dev? > Hoop.dev is an access gateway for databases and servers with AI-powered automations that eliminate cumbersome access policies and break-glass workflows without compromising security. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Hoop.dev with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Hoop.dev with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://hoop.company/api/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://hoop.company/api/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/networking/netbird/index.mdx b/website/integrations/networking/netbird/index.mdx index 1ae5d51621..4ce088796e 100644 --- a/website/integrations/networking/netbird/index.mdx +++ b/website/integrations/networking/netbird/index.mdx @@ -4,6 +4,7 @@ sidebar_label: NetBird support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -41,6 +42,8 @@ NetBird can use authentik in two ways: ## authentik configuration + + To support adding authentik as an external identity provider in NetBird, you need to create an application/provider pair and application entitlements in authentik. ### Create an application and provider in authentik @@ -80,7 +83,7 @@ Name each entitlement exactly as the NetBird group value that NetBird should syn - **Issuer**: `https://authentik.company/application/o//` 4. Copy the redirect URL shown by NetBird. Do not complete the provider setup yet. 5. Return to authentik, navigate to **Applications** > **Providers**, and edit the NetBird provider. -6. Under **Redirect URIs/Origins**, add the redirect URL from NetBird as a `Strict` redirect. +6. Under **Redirect URIs/Origins**, add the redirect URL from NetBird as a `Strict` `Authorization` redirect. 7. Click **Update**. 8. Return to NetBird and complete the identity provider setup. @@ -109,8 +112,8 @@ To support replacing NetBird's embedded IdP with authentik, you need to create a - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** value because it will be required later. - Set **Client type** to `Public`. - - Add a `Strict` redirect URI to `http://localhost:53000`. - - Add a `Regex` redirect URI to `https://netbird.company/.*`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `http://localhost:53000`. + - Add a **Redirect URI** of type `Regex` `Authorization` as `https://netbird.company/.*`. - Select any available signing key. - Under **Advanced protocol settings**, set **Access Code Validity** to `minutes=10`. - Under **Advanced protocol settings**, set **Subject Mode** to `Based on the User's ID`. diff --git a/website/integrations/networking/pangolin/index.mdx b/website/integrations/networking/pangolin/index.mdx index 1b9c1f9d9c..c25c233df5 100644 --- a/website/integrations/networking/pangolin/index.mdx +++ b/website/integrations/networking/pangolin/index.mdx @@ -4,6 +4,8 @@ sidebar_label: Pangolin support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is Pangolin? > Pangolin is a self-hosted tunneled reverse proxy server with identity and access control, designed to securely expose private resources on distributed networks. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Pangolin with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Pangolin with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, and **Client Secret** values because they will be required later. - - Temporarily set **Redirect URI** to `https://temp.temp`. + - Temporarily add a **Redirect URI** of type `Strict` `Authorization` as `https://temp.temp`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. @@ -61,7 +65,7 @@ To support the integration of Pangolin with authentik, you need to create an app 1. Log in to authentik as an administrator and open the authentik Admin interface. 2. Navigate to **Applications** > **Providers** and click the **Edit** icon of the newly created Pangolin provider. -3. Set the **Redirect URI** to the value taken from Pangolin (e.g. `https://pangolin.company/auth/idp//oidc/callback`). +3. Add a **Redirect URI** of type `Strict` `Authorization` as the value taken from Pangolin (e.g. `https://pangolin.company/auth/idp//oidc/callback`). 4. Click **Update**. ## Configuration verification diff --git a/website/integrations/networking/tailscale/index.md b/website/integrations/networking/tailscale/index.md index 3df0c2dd67..859640e4a6 100644 --- a/website/integrations/networking/tailscale/index.md +++ b/website/integrations/networking/tailscale/index.md @@ -4,6 +4,8 @@ sidebar_label: Tailscale support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Tailscale? > Tailscale is a mesh VPN service that creates secure, encrypted, peer-to-peer connections between devices across different networks using the WireGuard protocol. @@ -42,6 +44,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Tailscale with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -52,7 +56,7 @@ To support the integration of Tailscale with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://login.tailscale.com/a/oauth_response`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://login.tailscale.com/a/oauth_response`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/networking/technitium/index.md b/website/integrations/networking/technitium/index.md index c34f85e40d..698b8b630f 100644 --- a/website/integrations/networking/technitium/index.md +++ b/website/integrations/networking/technitium/index.md @@ -4,6 +4,8 @@ sidebar_label: Technitium DNS support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Technitium DNS? > Technitium DNS Server is a free, open source, cross-platform, authoritative and recursive DNS server that can be self-hosted for privacy and security, software development, and testing on small to medium-sized networks. @@ -25,6 +27,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Technitium DNS with authentik, you need to create a scope mapping, an application/provider pair, and application entitlements in authentik. ### Create a scope mapping in authentik @@ -59,7 +63,7 @@ Technitium DNS uses the `roles` claim to map SSO users to local groups. Create a - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - Set **Client type** to `Confidential`. - - Set a `Strict` redirect URI to `https://technitium.company/sso/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://technitium.company/sso/callback`. - Select any available signing key. - Ensure that the `openid`, `email`, and `profile` scopes are selected. Remove the `email` scope if you prefer usernames to use the preferred username claim instead of the email address. - Under **Advanced protocol settings** > **Selected Scopes**, add the scope mapping that you created in the previous section. diff --git a/website/integrations/platforms/budibase/index.md b/website/integrations/platforms/budibase/index.md index 693a7d7ac0..d2a45e6c0e 100644 --- a/website/integrations/platforms/budibase/index.md +++ b/website/integrations/platforms/budibase/index.md @@ -4,6 +4,8 @@ sidebar_label: Budibase support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Budibase? > Budibase is an open source low-code platform, and the easiest way to build internal tools that improve productivity. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Budibase with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of Budibase with authentik, you need to create an app - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://budibase.company/api/global/auth/oidc/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://budibase.company/api/global/auth/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/platforms/drupal/index.md b/website/integrations/platforms/drupal/index.md index 0afc315b4c..89d4b8b05e 100644 --- a/website/integrations/platforms/drupal/index.md +++ b/website/integrations/platforms/drupal/index.md @@ -4,6 +4,8 @@ sidebar_label: Drupal support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Drupal? > Drupal is a free and open-source content management system written in PHP and @@ -28,6 +30,8 @@ There are many different modules for Drupal that allow you to set up SSO using d ## authentik configuration + + To support the integration of Drupal with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -38,7 +42,7 @@ To support the integration of Drupal with authentik, you need to create an appli - **Application**: provide a descriptive name, an optional group for the type of application, the policy engine mode, and optional UI settings. The **slug** will be used in URLs and should match the `drupal-slug` placeholder defined earlier. - **Choose a Provider type**: select **OAuth2/OpenID Provider** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), and configure the following required settings: - - Add the following **Redirect URI**: `https://drupal.company/openid-connect/generic` + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://drupal.company/openid-connect/generic`. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. 3. Click **Submit** to save the new application and provider. diff --git a/website/integrations/platforms/personio/index.md b/website/integrations/platforms/personio/index.md index 74b89535d1..62506db268 100644 --- a/website/integrations/platforms/personio/index.md +++ b/website/integrations/platforms/personio/index.md @@ -4,6 +4,8 @@ sidebar_label: Personio support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Personio? > Personio is an HR software platform for managing core HR processes such as recruiting, onboarding, payroll, time tracking, and performance management. @@ -22,6 +24,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Personio with authentik, you need to create an application/provider pair in authentik. ### Copy the Personio callback URL @@ -40,7 +44,7 @@ To support the integration of Personio with authentik, you need to create an app - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - Set the **Client type** to `Confidential`. - - Add two `Strict` redirect URIs: + - Add two **Redirect URIs** of type `Strict` `Authorization`: - The **Callback URLs/Redirect URIs** value from Personio. - `https://login.personio.com/login/callback` - Select any available signing key. diff --git a/website/integrations/platforms/pocketbase/index.md b/website/integrations/platforms/pocketbase/index.md index 747e5bbbca..643fd453e5 100644 --- a/website/integrations/platforms/pocketbase/index.md +++ b/website/integrations/platforms/pocketbase/index.md @@ -4,6 +4,8 @@ sidebar_label: PocketBase support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is PocketBase? > PocketBase is an open source backend consisting of an embedded SQLite database, realtime subscriptions, built-in auth management, a dashboard UI, and a REST-like API. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of PocketBase with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -33,7 +37,7 @@ To support the integration of PocketBase with authentik, you need to create an a - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://pocketbase.company/api/oauth2-redirect`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://pocketbase.company/api/oauth2-redirect`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/platforms/wordpress/index.md b/website/integrations/platforms/wordpress/index.md index 9f9ea62820..8eb025e5e1 100644 --- a/website/integrations/platforms/wordpress/index.md +++ b/website/integrations/platforms/wordpress/index.md @@ -4,6 +4,8 @@ sidebar_label: WordPress support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is WordPress? > WordPress is an open source publishing platform used to create websites, blogs, and other web content. @@ -27,6 +29,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of WordPress with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider @@ -37,7 +41,7 @@ To support the integration of WordPress with authentik, you need to create an ap - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and application **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://wp.company/wp-admin/admin-ajax.php?action=openid-connect-authorize`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://wp.company/wp-admin/admin-ajax.php?action=openid-connect-authorize`. - Select any available signing key. - Under **Advanced protocol settings** > **Scopes**, add `authentik default OAuth Mapping: OpenID 'offline_access'` to the **Selected Scopes** list. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/security/1password/index.mdx b/website/integrations/security/1password/index.mdx index 18d81c8f8e..bae482d09f 100644 --- a/website/integrations/security/1password/index.mdx +++ b/website/integrations/security/1password/index.mdx @@ -4,6 +4,8 @@ sidebar_label: 1Password support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is 1Password? > 1Password is a password management tool that simplifies the process of creating, storing, and sharing passwords. It allows you to create strong, unique passwords, securely store them in a vault, and automatically fill them in when needed. @@ -24,6 +26,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of 1Password with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -35,7 +39,7 @@ To support the integration of 1Password with authentik, you need to create an ap - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Set **Client Type** to `Public`. - Note the **Client ID** and **slug** values because they will be required later. - - Add two `Strict` redirect URIs and set them to `https://your-domain.1password.com/sso/oidc/redirect/` and `onepassword://sso/oidc/redirect`. + - Add two **Redirect URIs** of type `Strict` `Authorization` as `https://your-domain.1password.com/sso/oidc/redirect/` and `onepassword://sso/oidc/redirect`. - Select any available **Signing Key**. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. If you add a SCIM provider as a backchannel provider later, only users who can view this application are synchronized. diff --git a/website/integrations/security/bitwarden/index.mdx b/website/integrations/security/bitwarden/index.mdx index 10bde10045..9ec8306744 100644 --- a/website/integrations/security/bitwarden/index.mdx +++ b/website/integrations/security/bitwarden/index.mdx @@ -4,6 +4,7 @@ sidebar_label: Bitwarden support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; import SAMLProvider20265Warning from "../../_saml-provider-2026-5-warning.mdx"; import TabItem from "@theme/TabItem"; import Tabs from "@theme/Tabs"; @@ -43,6 +44,8 @@ You can configure Bitwarden to use either OIDC or SAML; this guide explains both ## authentik configuration + + To support the integration of Bitwarden with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -55,14 +58,14 @@ To support the integration of Bitwarden with authentik, you need to create an ap - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - Add the redirect URIs for your Bitwarden deployment: - For Bitwarden Cloud US: - - Set a `Strict` `Authorization` redirect URI to `https://sso.bitwarden.com/oidc-signin`. - - Set a `Strict` `Post Logout` redirect URI to `https://sso.bitwarden.com/oidc-signedout`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://sso.bitwarden.com/oidc-signin`. + - Add a **Redirect URI** of type `Strict` `Post Logout` as `https://sso.bitwarden.com/oidc-signedout`. - For Bitwarden Cloud EU: - - Set a `Strict` `Authorization` redirect URI to `https://sso.bitwarden.eu/oidc-signin`. - - Set a `Strict` `Post Logout` redirect URI to `https://sso.bitwarden.eu/oidc-signedout`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://sso.bitwarden.eu/oidc-signin`. + - Add a **Redirect URI** of type `Strict` `Post Logout` as `https://sso.bitwarden.eu/oidc-signedout`. - For self-hosted Bitwarden: - - Set a `Strict` `Authorization` redirect URI to `https://bitwarden.company/sso/oidc-signin`. - - Set a `Strict` `Post Logout` redirect URI to `https://bitwarden.company/sso/oidc-signedout`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://bitwarden.company/sso/oidc-signin`. + - Add a **Redirect URI** of type `Strict` `Post Logout` as `https://bitwarden.company/sso/oidc-signedout`. - Select any available **Signing Key**. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. diff --git a/website/integrations/security/cloudflare-access/index.md b/website/integrations/security/cloudflare-access/index.md index bbd635f768..61e736c569 100644 --- a/website/integrations/security/cloudflare-access/index.md +++ b/website/integrations/security/cloudflare-access/index.md @@ -4,6 +4,8 @@ sidebar_label: Cloudflare Access support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Cloudflare Access? > Cloudflare Access is a secure, cloud-based zero-trust solution for managing and authenticating user access to internal applications and resources. @@ -29,6 +31,8 @@ Looking to integrate authentik with your Cloudflare Dashboard? See our [integrat ## authentik configuration + + To support the integration of Cloudflare Access with authentik, you need to create an application/provider pair in authentik. Cloudflare uses your Cloudflare Access team name in the callback URL. You can find the team name in the Cloudflare dashboard under **Settings** > **Team name and domain** > **Team name**. @@ -41,7 +45,7 @@ Cloudflare uses your Cloudflare Access team name in the callback URL. You can fi - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Add one `Strict` redirect URI and set it to `https://company.cloudflareaccess.com/cdn-cgi/access/callback`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://company.cloudflareaccess.com/cdn-cgi/access/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. 3. Click **Submit** to save the new application and provider. diff --git a/website/integrations/security/hashicorp-vault/index.md b/website/integrations/security/hashicorp-vault/index.md index f31df5dab4..9f14ceac9c 100644 --- a/website/integrations/security/hashicorp-vault/index.md +++ b/website/integrations/security/hashicorp-vault/index.md @@ -4,6 +4,8 @@ sidebar_label: HashiCorp Vault support_level: authentik --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is HashiCorp Vault? > HashiCorp Vault secures, stores, and controls access to tokens, passwords, certificates, encryption keys, and other sensitive data. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of HashiCorp Vault with authentik, you need to create an application and provider pair in authentik. ### Create an application and provider @@ -33,7 +37,7 @@ To support the integration of HashiCorp Vault with authentik, you need to create - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set two `Strict` redirect URIs to `https://vault.company/ui/vault/auth/oidc/oidc/callback` and `http://localhost:8250/oidc/callback`. + - Add two **Redirect URIs** of type `Strict` `Authorization` as `https://vault.company/ui/vault/auth/oidc/oidc/callback` and `http://localhost:8250/oidc/callback`. - Select any available signing key. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. 3. Click **Submit** to save the new application and provider. diff --git a/website/integrations/security/vaultwarden/index.md b/website/integrations/security/vaultwarden/index.md index a039ae91e5..9b588144d8 100644 --- a/website/integrations/security/vaultwarden/index.md +++ b/website/integrations/security/vaultwarden/index.md @@ -4,6 +4,8 @@ sidebar_label: Vaultwarden support_level: community --- +import RedirectURI20265Note from "../../\_redirect-uri-2026-5-note.mdx"; + ## What is Vaultwarden? > Vaultwarden is an alternative server implementation of the Bitwarden Client API, written in Rust and compatible with official Bitwarden clients, perfect for self-hosted deployment where running the official resource-heavy service might not be ideal. @@ -23,6 +25,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of Vaultwarden with authentik, you need to create an application/provider pair in authentik. ### Create custom scope mapping @@ -53,7 +57,7 @@ Vaultwarden requires the email scope to return either `email_verified: True` or - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later. - - Set a `Strict` redirect URI to `https://vaultwarden.company/identity/connect/oidc-signin`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://vaultwarden.company/identity/connect/oidc-signin`. - Select any available signing key. - Under **Advanced protocol settings**: - Set **Access token validity** to more than 5 minutes. diff --git a/website/integrations/security/xcreds/index.mdx b/website/integrations/security/xcreds/index.mdx index 81be6f33d9..baaf24a556 100644 --- a/website/integrations/security/xcreds/index.mdx +++ b/website/integrations/security/xcreds/index.mdx @@ -4,6 +4,8 @@ sidebar_label: XCreds support_level: community --- +import RedirectURI20265Note from "../../_redirect-uri-2026-5-note.mdx"; + ## What is XCreds? > XCreds is an open source project for synchronizing IdP passwords with macOS login passwords. XCreds replaces the macOS login window to provide authentication to the cloud provider; a user enters their cloud password for authentication and XCreds keeps the local Mac password synchronized with the cloud password. @@ -26,6 +28,8 @@ This documentation lists only the settings that you need to change from their de ## authentik configuration + + To support the integration of XCreds with authentik, you need to create an application/provider pair in authentik. ### Create an application and provider in authentik @@ -36,7 +40,7 @@ To support the integration of XCreds with authentik, you need to create an appli - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - Note the **Client ID** and **Client Secret** values because they will be required later. - - Set a `Strict` redirect URI to `https://127.0.0.1/xcreds`. + - Add a **Redirect URI** of type `Strict` `Authorization` as `https://127.0.0.1/xcreds`. - Select any available signing key. - Under **Advanced protocol settings**, add `authentik default OAuth Mapping: OpenID 'offline_access'` to **Selected Scopes**. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/bindings-overview/) (policy, group, or user) to manage the listing and access to applications on a user's **Application Dashboard** page. From 9457696385e5adea715c8ca95f54ad1ed03453c3 Mon Sep 17 00:00:00 2001 From: "Jens L." Date: Fri, 12 Jun 2026 14:09:41 +0200 Subject: [PATCH 20/20] root: bump pyo3 (#23036) Signed-off-by: Jens Langhammer --- Cargo.lock | 21 ++++++++++----------- Cargo.toml | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ec2a1c779..08179d8e4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2642,9 +2642,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.28.3" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fd8e38a3b50ed1167fb981cd6fd60147e091784c427b8f7183a7ee32c31c12" +checksum = "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c" dependencies = [ "libc", "once_cell", @@ -2656,18 +2656,18 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.28.3" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e368e7ddfdeb98c9bca7f8383be1648fd84ab466bf2bc015e94008db6d35611e" +checksum = "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078" dependencies = [ "target-lexicon", ] [[package]] name = "pyo3-ffi" -version = "0.28.3" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f29e10af80b1f7ccaf7f69eace800a03ecd13e883acfacc1e5d0988605f651e" +checksum = "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b" dependencies = [ "libc", "pyo3-build-config", @@ -2675,9 +2675,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.28.3" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df6e520eff47c45997d2fc7dd8214b25dd1310918bbb2642156ef66a67f29813" +checksum = "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -2687,13 +2687,12 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.28.3" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cdc218d835738f81c2338f822078af45b4afdf8b2e33cbb5916f108b813acb" +checksum = "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362" dependencies = [ "heck", "proc-macro2", - "pyo3-build-config", "quote", "syn", ] diff --git a/Cargo.toml b/Cargo.toml index 520f596bac..802f80573d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,8 +48,8 @@ metrics-exporter-prometheus = { version = "= 0.18.3", default-features = false } nix = { version = "= 0.31.3", features = ["hostname", "signal"] } notify = "= 8.2.0" pin-project-lite = "= 0.2.17" -pyo3 = "= 0.28.3" -pyo3-build-config = "= 0.28.3" +pyo3 = "= 0.29.0" +pyo3-build-config = "= 0.29.0" regex = "= 1.12.3" reqwest = { version = "= 0.13.4", features = [ "form",