Compare commits

..

119 Commits

Author SHA1 Message Date
Teffen Ellis
c11f407470 web: Demo. 2025-08-25 22:40:00 +02:00
Teffen Ellis
b7c6b961a1 web: Flesh out wave boi. 2025-08-25 18:25:20 +02:00
Teffen Ellis
e6adb72695 web: Flesh out reload behavior. 2025-08-25 18:25:18 +02:00
Teffen Ellis
9cbdcd2cad web: Automatic reload during server start up. 2025-08-25 18:25:12 +02:00
Marc 'risson' Schmitt
197f4c5585 providers/oauth2: avoid deadlock during session migration (#16361) 2025-08-25 17:48:20 +02:00
dependabot[bot]
80e9865c6a lifecycle/aws: bump aws-cdk from 2.1025.0 to 2.1026.0 in /lifecycle/aws (#16352)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 12:25:57 +00:00
dependabot[bot]
c08df26c65 core: bump github.com/stretchr/testify from 1.10.0 to 1.11.0 (#16357)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 14:07:09 +02:00
dependabot[bot]
332a53ceff core: bump axllent/mailpit from v1.27.5 to v1.27.6 in /tests/e2e (#16358)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-25 14:06:01 +02:00
Mo
4919772d68 website/docs: fix missing trailing slash in vaultwarden documentation (#16348)
Missing trailing slash in documentation

Won't work without the missing forward slash.
Source: https://github.com/dani-garcia/vaultwarden/wiki/Enabling-SSO-support-using-OpenId-Connect#authentik

Signed-off-by: Mo <65728018+Moe1369@users.noreply.github.com>
2025-08-24 22:16:54 +01:00
Dominic R
a978b4b60e root: fix security.md (#16345)
Signed-off-by: Dominic R <dominic@sdko.org>
2025-08-24 22:13:45 +01:00
Dewi Roberts
17bd1f1574 root: update security.md with github reporting link (#16332)
* Adds github reporting link

* Applied suggestions

* Improved wording

* Improved wording
2025-08-22 16:46:16 +01:00
Marc 'risson' Schmitt
0b4be1fdda website/docs: 2025.8.1 release notes (#16343) 2025-08-22 14:51:40 +00:00
Marc 'risson' Schmitt
e305c98eb8 packages/django-dramatiq-postgres: broker: fix various timing issues (#16340) 2025-08-22 14:04:54 +00:00
Dewi Roberts
35bd1d9907 website/docs: adds details to certificates doc (#16335)
* Clarifies certs directory mounting and adds instruction for manually re-triggering discovery.

* Fixed mounting info

* Update website/docs/sys-mgmt/certificates.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/docs/sys-mgmt/certificates.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-08-22 14:53:44 +01:00
Marc 'risson' Schmitt
3150885889 outposts: allow ingress path type configuration (#16339) 2025-08-22 15:36:18 +02:00
authentik-automation[bot]
5fd96518d3 core, web: update translations (#16321)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-08-22 12:47:49 +00:00
Marc 'risson' Schmitt
287647beea outposts: fix service connection update task arguments (#16312) 2025-08-22 14:31:49 +02:00
Marcelo Elizeche Landó
2c1a0ca0fc core: use email backend for test_email management command (#16311) 2025-08-22 14:17:02 +02:00
dependabot[bot]
da47095ebc core: bump astral-sh/uv from 0.8.12 to 0.8.13 (#16325)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-22 14:15:57 +02:00
Dominic R
2ea95ba189 website: Move docs netlify.toml (#16320)
* website: Move docs netlify.toml

* Update publish path in Netlify configuration

Signed-off-by: Dominic R <dominic@sdko.org>

---------

Signed-off-by: Dominic R <dominic@sdko.org>
2025-08-22 13:36:16 +02:00
Tana M Berry
b277828b21 website/docs: add link in 2025.8 rel notes to back-channel logout docs (#16306)
Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-08-21 19:12:54 +00:00
Marc 'risson' Schmitt
8765c92fc4 packages/django-dramatiq-postgres: middleware: fix listening on hosts where ipv6 is not supported (#16308) 2025-08-21 19:11:21 +00:00
Teffen Ellis
536688f23b website: Fix version origin detection, build-time URLs (#15774)
* website: Update route base path.

* website: Add copy step for migration.

* website: Use build redirects.

* website: Ensure that netlify config is picked up.

* website: Add shared Netlify plugin cache.

* website: Use relative path.

* website: Fix routing when moving across versioned URLs.

* website: Fix issues surrounding origin detection.

* website: Allow integrations to omit plugin data, fix types.
2025-08-21 18:31:54 +00:00
Teffen Ellis
7861f5a40e web/a11y: Associating labels with inputs (#16119)
web: Flesh out use of label component.

web: Add correct ID to stage inputs.
2025-08-21 18:28:38 +00:00
Teffen Ellis
e7b43b72ab web: Username truncation, field alignment. (#16283) 2025-08-21 18:03:51 +02:00
Dewi Roberts
2bf9a9d4fe website/docs: adds a webhook header mapping example (#16301)
* Adds webhook header example

* Small changes

* Update website/docs/sys-mgmt/events/transports.md

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-08-21 16:59:03 +01:00
Teffen Ellis
f6af8f3b9d web: Fix issue where form group uses unknown slot. (#16276) 2025-08-21 17:56:26 +02:00
Marc 'risson' Schmitt
c9a4eff3a8 lifecycle: set PROMETHEUS_MULTIPROC_DIR as early as possible (#16298) 2025-08-21 11:09:36 -03:00
Marc 'risson' Schmitt
b893305e5f providers/oauth2: fix logout token missing sid, fix wrong sub mode used (#16295) 2025-08-21 10:43:10 -03:00
dependabot[bot]
b3a5cc8320 web: bump core-js from 3.45.0 to 3.45.1 in /web (#16290)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.45.0 to 3.45.1.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.45.1/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-version: 3.45.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-21 08:29:05 -04:00
Dominic R
94d7a989a1 root: Remove CODEOWNERS entries from docs/ directory (#16287) 2025-08-21 14:19:09 +02:00
Dominic R
359fa5d5df *: Fix dead doc link (#16288) 2025-08-21 14:09:20 +02:00
Dominic R
11c9015a49 web: saml provider view: fix state refresh issues (#14474)
* web: saml provider view: fix state refresh issues

Fixes the following issues:
1. Fixed incorrect certificate download when changing a signing certificate - previously, clicking "Download Signing Certificate" after updating a certificate would still download the old certificate until the page was refreshed.
2. Fixed missing UI updates when adding a signing certificate - previously, when a signing certificate was added to a provider, the download button wouldn't appear until the page was refreshed.
3. Fixed persistent download button when removing a certificate - previously, when a signing certificate was removed from a provider, the download button would still be visible until the page was refreshed.

* prob has more uses than for certs only

* teffen's suggestions

Signed-off-by: Dominic R <dominic@sdko.org>

* fix

Signed-off-by: Dominic R <dominic@sdko.org>

* this should fix it?

Signed-off-by: Dominic R <dominic@sdko.org>

---------

Signed-off-by: Dominic R <dominic@sdko.org>
2025-08-21 03:39:16 +02:00
Max
f135990c6b web: fix "Explore integrations" link in Quick actions (#16274)
fix "Explore integrations" link in Quick actions
2025-08-20 19:21:46 -04:00
Max
6f63a3eb15 website/integrations: fix dead links to external docs (#16273) 2025-08-20 18:46:27 +00:00
Marc 'risson' Schmitt
2209fcea2a tasks: add rel_obj to system task exception event (#16270) 2025-08-20 17:29:05 +00:00
Marc 'risson' Schmitt
e5efb50a37 website/docs: update 2025.8 release notes (#16269) 2025-08-20 19:15:20 +02:00
dependabot[bot]
bbc02dc065 web: bump @patternfly/elements from 4.1.0 to 4.2.0 in /web (#16265)
Bumps [@patternfly/elements](https://github.com/patternfly/patternfly-elements/tree/HEAD/elements) from 4.1.0 to 4.2.0.
- [Release notes](https://github.com/patternfly/patternfly-elements/releases)
- [Changelog](https://github.com/patternfly/patternfly-elements/blob/main/elements/CHANGELOG.md)
- [Commits](https://github.com/patternfly/patternfly-elements/commits/@patternfly/elements@4.2.0/elements)

---
updated-dependencies:
- dependency-name: "@patternfly/elements"
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-20 13:05:02 +01:00
dependabot[bot]
f3f81951c6 web: bump mermaid from 11.9.0 to 11.10.0 in /web (#16263)
Bumps [mermaid](https://github.com/mermaid-js/mermaid) from 11.9.0 to 11.10.0.
- [Release notes](https://github.com/mermaid-js/mermaid/releases)
- [Commits](https://github.com/mermaid-js/mermaid/compare/mermaid@11.9.0...mermaid@11.10.0)

---
updated-dependencies:
- dependency-name: mermaid
  dependency-version: 11.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-20 13:04:50 +01:00
dependabot[bot]
739eff66e0 web: bump @types/guacamole-common-js from 1.5.3 to 1.5.4 in /web (#16262)
Bumps [@types/guacamole-common-js](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/guacamole-common-js) from 1.5.3 to 1.5.4.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/guacamole-common-js)

---
updated-dependencies:
- dependency-name: "@types/guacamole-common-js"
  dependency-version: 1.5.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-20 13:04:24 +01:00
Dominic R
48de61a926 security: Bump supported versions (#16261)
Signed-off-by: Dominic R <dominic@sdko.org>
2025-08-20 12:41:45 +01:00
Marcelo Elizeche Landó
032031f2cf core: bump channels from 4.3.0 to v4.3.1 (#16260) 2025-08-20 13:25:44 +02:00
transifex-integration[bot]
4e44209af1 translate: Updates for file web/xliff/en.xlf in cs_CZ (#16264)
* Translate web/xliff/en.xlf in cs_CZ

100% translated source file: 'web/xliff/en.xlf'
on 'cs_CZ'.

* Translate web/xliff/en.xlf in cs_CZ

100% translated source file: 'web/xliff/en.xlf'
on 'cs_CZ'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-20 11:12:41 +00:00
dependabot[bot]
289555abcd website: bump the eslint group in /website with 3 updates (#16248) 2025-08-19 21:38:10 +01:00
Marcelo Elizeche Landó
943c456555 stages/authenticator_duo: Add test to fix codecov error (#16257)
* Add test to fix codecov error

* use self.assertJSONEqual instead of assertEqual
2025-08-19 22:12:39 +02:00
dependabot[bot]
a79b914d39 core: bump selenium/standalone-chrome from 138.0 to 139.0 in /tests/e2e (#16256) 2025-08-19 21:06:20 +01:00
dependabot[bot]
7a8816abd1 web: bump the eslint group across 2 directories with 3 updates (#16255) 2025-08-19 21:06:00 +01:00
Dominic R
93e448c3fd website/docs: sys-mgmt/s3: Clean up and improve (#16242)
* website/docs: sys-mgmt/s3: Clean up and improve

Signed-off-by: Dominic R <dominic@sdko.org>

Co-authored-by: Dewi Roberts <dewi@goauthentik.io>

* Update website/docs/sys-mgmt/ops/storage-s3.md

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-08-19 15:01:32 -05:00
Tana M Berry
109c869f97 website/docs: Advanced queries, remove reference to QL and add more examples (#16191)
* remove reference to QL

* add Jens' examples

* tweak

* Update website/docs/users-sources/user/user_basic_operations.md

Co-authored-by: Jens L. <jens@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/docs/users-sources/user/user_basic_operations.md

Co-authored-by: Jens L. <jens@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* add note about UX ticks

* tweak

* argh

* clarify there are more values

* add link to Event actions list

* tweaks, typo

* Update website/docs/users-sources/user/user_basic_operations.md

Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/docs/sys-mgmt/events/logging-events.md

Co-authored-by: Jens L. <jens@goauthentik.io>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* jens edits

---------

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tana@goauthentik.io>
Co-authored-by: Jens L. <jens@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-08-19 14:27:00 -05:00
Dominic R
8029fdad7b website/integrations: emby (#15921)
Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Tana Berry <tana@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Ivan Schaller <ivan@schaller.sh>
2025-08-19 14:12:45 -05:00
Marcelo Elizeche Landó
d2aac457ef stages/authenticator_duo: return generic error message (#16194)
* return generic error message

Signed-off-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>

* fix linting

* Trigger Build

---------

Signed-off-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>
2025-08-19 18:27:48 +02:00
dependabot[bot]
70ce5ccceb core: bump axllent/mailpit from v1.27.4 to v1.27.5 in /tests/e2e (#16252)
Bumps axllent/mailpit from v1.27.4 to v1.27.5.

---
updated-dependencies:
- dependency-name: axllent/mailpit
  dependency-version: v1.27.5
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 17:05:56 +01:00
dependabot[bot]
173c334478 core: bump astral-sh/uv from 0.8.11 to 0.8.12 (#16250)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.8.11 to 0.8.12.
- [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.8.11...0.8.12)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.8.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 17:05:33 +01:00
dependabot[bot]
6e321097a1 web: bump the rollup group across 1 directory with 4 updates (#16251)
Bumps the rollup group with 4 updates in the /web directory: [@rollup/rollup-darwin-arm64](https://github.com/rollup/rollup), [@rollup/rollup-linux-arm64-gnu](https://github.com/rollup/rollup), [@rollup/rollup-linux-x64-gnu](https://github.com/rollup/rollup) and [rollup](https://github.com/rollup/rollup).


Updates `@rollup/rollup-darwin-arm64` from 4.46.2 to 4.46.3
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.46.2...v4.46.3)

Updates `@rollup/rollup-linux-arm64-gnu` from 4.46.2 to 4.46.3
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.46.2...v4.46.3)

Updates `@rollup/rollup-linux-x64-gnu` from 4.46.2 to 4.46.3
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.46.2...v4.46.3)

Updates `rollup` from 4.46.2 to 4.46.3
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.46.2...v4.46.3)

---
updated-dependencies:
- dependency-name: "@rollup/rollup-darwin-arm64"
  dependency-version: 4.46.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rollup
- dependency-name: "@rollup/rollup-linux-arm64-gnu"
  dependency-version: 4.46.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rollup
- dependency-name: "@rollup/rollup-linux-x64-gnu"
  dependency-version: 4.46.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rollup
- dependency-name: rollup
  dependency-version: 4.46.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: rollup
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 17:05:29 +01:00
dependabot[bot]
f3bf8097b8 core: bump goauthentik/fips-python from 3.13.6-slim-bookworm-fips to 3.13.7-slim-bookworm-fips (#16253)
core: bump goauthentik/fips-python

Bumps goauthentik/fips-python from 3.13.6-slim-bookworm-fips to 3.13.7-slim-bookworm-fips.

---
updated-dependencies:
- dependency-name: goauthentik/fips-python
  dependency-version: 3.13.7-slim-bookworm-fips
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-19 17:05:16 +01:00
authentik-automation[bot]
b869433e4d core, web: update translations (#16244)
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>
2025-08-19 13:51:45 +01:00
Dominic R
5aef86c3d1 core: Block usage of Django's createsuperuser (#16215)
wip
2025-08-19 13:43:06 +01:00
Dominic R
970ac44ff8 web: Do not mark Attributes as a mandatory field (#16004)
* web: Do not mark Attributes as a mandatory field

* fix lint

* Teffen's suggestion
2025-08-19 14:16:49 +02:00
dependabot[bot]
9145d55e6c web: bump @types/react from 19.1.8 to 19.1.10 in /packages/docusaurus-config (#16131)
web: bump @types/react in /packages/docusaurus-config

Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 19.1.8 to 19.1.10.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-version: 19.1.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 20:39:35 +01:00
Dominic R
1c36b361b2 router: fix missing response headers on compressed 404 for static files (#16216)
* router: only serve dist assets if present; fallback to backend 404

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-08-18 20:18:28 +01:00
Teffen Ellis
d55e23cdb8 web: Fix ak-flow-card footer alignment. (#16236) 2025-08-18 18:10:51 +00:00
Teffen Ellis
52673e4223 web: Fix reported error precedence (#16231)
* web: Fix issue where controlled element is not assigned.

* web: Fix preferred error to display when API response include fields.

* web: Clarify error message alert.

* web: Fix issue where impersonation form can be submitted with empty
fields. Clarify message behavior.
2025-08-18 17:39:44 +00:00
Marc 'risson' Schmitt
5cbcbf8d2c brands: revert sort matched brand by match length (revert #15413) (#16233) 2025-08-18 17:22:00 +00:00
Dominic R
f29a4c1876 website/integrations: vaultwarden (#16057)
Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-08-18 11:36:41 -05:00
Brian Begun
38fb5cd712 website/integrations: update tautulli (#16059)
* Update index.md

Revised tutorial using new template.  Sorry for the delay on this.  

Signed-off-by: Brian Begun <begunfx@usa.net>

* Update website/integrations/media/tautulli/index.md

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Brian Begun <begunfx@usa.net>

* fix linting

* remove placeholder section

* Update website/integrations/media/tautulli/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/media/tautulli/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/media/tautulli/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/media/tautulli/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/media/tautulli/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/media/tautulli/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/media/tautulli/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/media/tautulli/index.md

Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

---------

Signed-off-by: Brian Begun <begunfx@usa.net>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Marcelo Elizeche Landó <marcelo@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-08-18 11:30:35 -05:00
authentik-automation[bot]
5b2aad586f core, web: update translations (#16210)
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>
2025-08-18 17:12:15 +01:00
Simonyi Gergő
2dd1c7b1ab rbac: assign InitialPermissions in a middleware (#16138)
assign `InitialPermission`s in a middleware

This will catch more creation events, hopefully fixing things like
https://github.com/goauthentik/authentik/issues/14313
2025-08-18 18:02:48 +02:00
dependabot[bot]
57c24e5c1c website: bump @types/node from 24.2.1 to 24.3.0 in /website (#16218)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.2.1 to 24.3.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 24.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 16:50:46 +01:00
dependabot[bot]
76d9b3479e web: bump the goauthentik group across 1 directory with 2 updates (#16219)
Bumps the goauthentik group with 2 updates in the /web directory: @goauthentik/prettier-config and [@goauthentik/api](https://github.com/goauthentik/authentik).


Updates `@goauthentik/prettier-config` from 1.0.5 to 3.1.0

Updates `@goauthentik/api` from 2024.6.0-1720200294 to 2025.10.0-rc1-1755254677
- [Release notes](https://github.com/goauthentik/authentik/releases)
- [Commits](https://github.com/goauthentik/authentik/commits)

---
updated-dependencies:
- dependency-name: "@goauthentik/prettier-config"
  dependency-version: 3.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: goauthentik
- dependency-name: "@goauthentik/api"
  dependency-version: 2025.10.0-rc1-1755254677
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: goauthentik
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 16:50:38 +01:00
dependabot[bot]
e9f946cdf2 web: bump @types/node from 24.2.1 to 24.3.0 in /packages/prettier-config (#16220)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.2.1 to 24.3.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 24.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 16:50:22 +01:00
dependabot[bot]
167452f1ed web: bump @types/node from 24.2.1 to 24.3.0 in /packages/esbuild-plugin-live-reload (#16221)
web: bump @types/node in /packages/esbuild-plugin-live-reload

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.2.1 to 24.3.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 24.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 16:50:14 +01:00
dependabot[bot]
dbfdb37e83 web: bump @types/node from 22.15.19 to 24.3.0 in /web (#16222)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.15.19 to 24.3.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 24.3.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 16:48:49 +01:00
dependabot[bot]
efdbf7aeed core: bump goauthentik.io/api/v3 from 3.2025100.1 to 3.2025100.2 (#16217)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-18 15:43:36 +02:00
Dominic R
8e9e4de80f website: prettierignore: Add docsmg Rust target (#16067) 2025-08-18 15:31:21 +02:00
Teffen Ellis
a63c5b1846 web: Improvements to ReCaptcha resizing (#16171)
* web: Remove comments from serialized HTML.

* web: Apply color theme to iframe.

* web: Fix issues surrounding reCaptcha resize events not propagating.
2025-08-18 13:24:14 +00:00
Teffen Ellis
80b84fa8a8 web/a11y: QL Search Input (#16198)
web: Fix issues surrounding form submission, keyboard focus, alignment.
2025-08-18 15:01:47 +02:00
Dominic R
4ce9795491 website/integrations: headscale: Remove href in product description (#16214)
Not included in any other integration and frankly unneeded with the link right below

Signed-off-by: Dominic R <dominic@sdko.org>
2025-08-18 01:41:27 -05:00
dependabot[bot]
e50cf1c150 web: bump @sentry/browser from 10.3.0 to 10.4.0 in /web in the sentry group across 1 directory (#16122)
web: bump @sentry/browser in /web in the sentry group across 1 directory

Bumps the sentry group with 1 update in the /web directory: [@sentry/browser](https://github.com/getsentry/sentry-javascript).


Updates `@sentry/browser` from 10.3.0 to 10.4.0
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/10.3.0...10.4.0)

---
updated-dependencies:
- dependency-name: "@sentry/browser"
  dependency-version: 10.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: sentry
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-15 17:37:25 +01:00
authentik-automation[bot]
4178717386 core, web: update translations (#16195)
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>
2025-08-15 17:36:59 +01:00
M-Slanec
20d068f767 policies/password: Fix amount_uppercase in password policy check (#16197)
Fix amount_uppercase in password policy check

Co-authored-by: Matthew Slanec <matthewslanec@Matthews-MacBook-Pro.local>
2025-08-15 13:51:43 +01:00
authentik-automation[bot]
5b7a42e6d6 web: bump API Client version (#16203)
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>
2025-08-15 13:04:59 +01:00
dependabot[bot]
1398561142 core: bump astral-sh/uv from 0.8.10 to 0.8.11 (#16201) 2025-08-15 12:27:42 +01:00
dependabot[bot]
55657e149b web: bump chromedriver from 139.0.0 to 139.0.1 in /web (#16200)
Bumps [chromedriver](https://github.com/giggio/node-chromedriver) from 139.0.0 to 139.0.1.
- [Commits](https://github.com/giggio/node-chromedriver/compare/139.0.0...139.0.1)

---
updated-dependencies:
- dependency-name: chromedriver
  dependency-version: 139.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-15 11:47:52 +01:00
authentik-automation[bot]
d5d7140631 stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#16196)
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>
2025-08-15 11:46:40 +01:00
Marcelo Elizeche Landó
17ff12f68f core: Add email template selector (#16170)
* Unify all email templates under stages.email.models.EmailTemplates

* Add template selector to Email Authenticator Stage

* fix tests

* Add email_template field to events.notificationtransport

* update schemas

* Make email_template default as None, add UI to notif transports

* Add showEmail and fix default selection in TransportForm

* fix required field for emailtemplate and webhookurl in TransportForm

* use switch because typescript is whinning

* Add email_subject_prefix to NotificationTransport

* Add tests, update migration

* remove duplicate API

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* rename template name

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* move send_once up

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* better defaults

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* no null

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* update test for email templates endpoint

* fix test url

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-08-15 11:44:18 +01:00
Tana M Berry
9c9a6e3d66 website/docs: add content about new Advanced Query searches (#16019)
Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-08-14 17:31:36 +02:00
dependabot[bot]
2cd81b2e78 web: bump the eslint group across 2 directories with 3 updates (#16133)
Bumps the eslint group with 1 update in the /packages/eslint-config directory: [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).
Bumps the eslint group with 1 update in the /web directory: [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `typescript-eslint` from 8.39.0 to 8.39.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.39.1/packages/typescript-eslint)

Updates `@typescript-eslint/eslint-plugin` from 8.39.0 to 8.39.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.39.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.39.0 to 8.39.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.39.1/packages/parser)

Updates `typescript-eslint` from 8.39.0 to 8.39.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.39.1/packages/typescript-eslint)

Updates `@typescript-eslint/eslint-plugin` from 8.39.0 to 8.39.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.39.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.39.0 to 8.39.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.39.1/packages/parser)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.39.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.39.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.39.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.39.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.39.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.39.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 14:31:52 +01:00
dependabot[bot]
bad426f694 web: bump @types/react from 19.1.8 to 19.1.10 in /web (#16125)
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 19.1.8 to 19.1.10.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-version: 19.1.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 14:31:44 +01:00
dependabot[bot]
6404fba2e4 web: bump core-js from 3.44.0 to 3.45.0 in /web (#16123)
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.44.0 to 3.45.0.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.45.0/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-version: 3.45.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 14:31:28 +01:00
Marc 'risson' Schmitt
c33b9f2d3f web/admin: fix settings saving (#16184)
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-08-14 12:33:33 +00:00
dependabot[bot]
bac6e965f4 website: bump the eslint group in /website with 3 updates (#16124)
Bumps the eslint group in /website with 3 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `@typescript-eslint/eslint-plugin` from 8.39.0 to 8.39.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.39.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.39.0 to 8.39.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.39.1/packages/parser)

Updates `typescript-eslint` from 8.39.0 to 8.39.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.39.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.39.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.39.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.39.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 12:01:48 +01:00
dependabot[bot]
36cb4dc750 web: bump typedoc-plugin-markdown from 4.8.0 to 4.8.1 in /packages/esbuild-plugin-live-reload (#16126)
web: bump typedoc-plugin-markdown

Bumps [typedoc-plugin-markdown](https://github.com/typedoc2md/typedoc-plugin-markdown/tree/HEAD/packages/typedoc-plugin-markdown) from 4.8.0 to 4.8.1.
- [Release notes](https://github.com/typedoc2md/typedoc-plugin-markdown/releases)
- [Changelog](https://github.com/typedoc2md/typedoc-plugin-markdown/blob/main/packages/typedoc-plugin-markdown/CHANGELOG.md)
- [Commits](https://github.com/typedoc2md/typedoc-plugin-markdown/commits/typedoc-plugin-markdown@4.8.1/packages/typedoc-plugin-markdown)

---
updated-dependencies:
- dependency-name: typedoc-plugin-markdown
  dependency-version: 4.8.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 12:01:34 +01:00
dependabot[bot]
45d9945a3a web: bump the storybook group across 1 directory with 5 updates (#16134)
Bumps the storybook group with 4 updates in the /web directory: [@storybook/addon-docs](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/docs), [@storybook/addon-links](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/links), [@storybook/web-components](https://github.com/storybookjs/storybook/tree/HEAD/code/renderers/web-components) and [@storybook/web-components-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/web-components-vite).


Updates `@storybook/addon-docs` from 9.1.1 to 9.1.2
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v9.1.2/code/addons/docs)

Updates `@storybook/addon-links` from 9.1.1 to 9.1.2
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v9.1.2/code/addons/links)

Updates `@storybook/web-components` from 9.1.1 to 9.1.2
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v9.1.2/code/renderers/web-components)

Updates `@storybook/web-components-vite` from 9.1.1 to 9.1.2
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v9.1.2/code/frameworks/web-components-vite)

Updates `storybook` from 9.1.1 to 9.1.2
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v9.1.2/code/core)

---
updated-dependencies:
- dependency-name: "@storybook/addon-docs"
  dependency-version: 9.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/addon-links"
  dependency-version: 9.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/web-components"
  dependency-version: 9.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: "@storybook/web-components-vite"
  dependency-version: 9.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
- dependency-name: storybook
  dependency-version: 9.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: storybook
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 11:59:51 +01:00
dependabot[bot]
23285ad664 core: bump goauthentik.io/api/v3 from 3.2025064.8 to 3.2025100.1 (#16161)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2025064.8 to 3.2025100.1.
- [Release notes](https://github.com/goauthentik/client-go/releases)
- [Changelog](https://github.com/goauthentik/client-go/blob/main/model_version_history.go)
- [Commits](https://github.com/goauthentik/client-go/compare/v3.2025064.8...v3.2025100.1)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2025100.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 11:59:24 +01:00
dependabot[bot]
91ab9503fd web: bump the esbuild group across 2 directories with 4 updates (#16162)
Bumps the esbuild group with 1 update in the /packages/esbuild-plugin-live-reload directory: [esbuild](https://github.com/evanw/esbuild).
Bumps the esbuild group with 1 update in the /web directory: [esbuild](https://github.com/evanw/esbuild).


Updates `esbuild` from 0.25.8 to 0.25.9
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.8...v0.25.9)

Updates `@esbuild/darwin-arm64` from 0.25.8 to 0.25.9
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.8...v0.25.9)

Updates `@esbuild/linux-arm64` from 0.25.8 to 0.25.9
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.8...v0.25.9)

Updates `@esbuild/linux-x64` from 0.25.8 to 0.25.9
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.8...v0.25.9)

Updates `esbuild` from 0.25.8 to 0.25.9
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.8...v0.25.9)

Updates `@esbuild/darwin-arm64` from 0.25.8 to 0.25.9
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.8...v0.25.9)

Updates `@esbuild/linux-arm64` from 0.25.8 to 0.25.9
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.8...v0.25.9)

Updates `@esbuild/linux-x64` from 0.25.8 to 0.25.9
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.25.8...v0.25.9)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-version: 0.25.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/darwin-arm64"
  dependency-version: 0.25.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/linux-arm64"
  dependency-version: 0.25.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/linux-x64"
  dependency-version: 0.25.9
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: esbuild
  dependency-version: 0.25.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/darwin-arm64"
  dependency-version: 0.25.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/linux-arm64"
  dependency-version: 0.25.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: esbuild
- dependency-name: "@esbuild/linux-x64"
  dependency-version: 0.25.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: esbuild
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 11:58:58 +01:00
dependabot[bot]
fb7802e6af web: bump the wdio group across 1 directory with 3 updates (#16163)
Bumps the wdio group with 3 updates in the /web directory: [@wdio/browser-runner](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-browser-runner), [@wdio/cli](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-cli) and [@wdio/spec-reporter](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-spec-reporter).


Updates `@wdio/browser-runner` from 9.19.0 to 9.19.1
- [Release notes](https://github.com/webdriverio/webdriverio/releases)
- [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webdriverio/webdriverio/commits/v9.19.1/packages/wdio-browser-runner)

Updates `@wdio/cli` from 9.19.0 to 9.19.1
- [Release notes](https://github.com/webdriverio/webdriverio/releases)
- [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webdriverio/webdriverio/commits/v9.19.1/packages/wdio-cli)

Updates `@wdio/spec-reporter` from 9.19.0 to 9.19.1
- [Release notes](https://github.com/webdriverio/webdriverio/releases)
- [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webdriverio/webdriverio/commits/v9.19.1/packages/wdio-spec-reporter)

---
updated-dependencies:
- dependency-name: "@wdio/browser-runner"
  dependency-version: 9.19.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: wdio
- dependency-name: "@wdio/cli"
  dependency-version: 9.19.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: wdio
- dependency-name: "@wdio/spec-reporter"
  dependency-version: 9.19.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: wdio
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 11:58:46 +01:00
authentik-automation[bot]
0f13a63528 core, web: update translations (#16175)
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>
2025-08-14 11:57:52 +01:00
dependabot[bot]
36daf4b519 core: bump github.com/getsentry/sentry-go from 0.35.0 to 0.35.1 (#16176)
Bumps [github.com/getsentry/sentry-go](https://github.com/getsentry/sentry-go) from 0.35.0 to 0.35.1.
- [Release notes](https://github.com/getsentry/sentry-go/releases)
- [Changelog](https://github.com/getsentry/sentry-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-go/compare/v0.35.0...v0.35.1)

---
updated-dependencies:
- dependency-name: github.com/getsentry/sentry-go
  dependency-version: 0.35.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 11:57:44 +01:00
dependabot[bot]
5cc4793b84 lifecycle/aws: bump aws-cdk from 2.1024.0 to 2.1025.0 in /lifecycle/aws (#16177)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1024.0 to 2.1025.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1025.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1025.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 11:57:36 +01:00
dependabot[bot]
a6063d4af4 core: bump library/golang from 1.24-bookworm to 1.25-bookworm (#16178)
Bumps library/golang from 1.24-bookworm to 1.25-bookworm.

---
updated-dependencies:
- dependency-name: library/golang
  dependency-version: 1.25-bookworm
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 11:57:24 +01:00
dependabot[bot]
8f450e6e14 core: bump astral-sh/uv from 0.8.9 to 0.8.10 (#16179)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.8.9 to 0.8.10.
- [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.8.9...0.8.10)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.8.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-14 11:57:15 +01:00
Dominic R
a1fc0605e2 website/integrations: nextcloud: Cleanup SAML service config (#16066)
* wip

* wip

* wip
2025-08-14 10:44:34 +01:00
Teffen Ellis
c886e4ff6b web: Fix issue where clicking a list item scrolls container. (#16174) 2025-08-13 21:30:58 +00:00
Marc 'risson' Schmitt
f91ebc2ad5 ci: release tag: fix missing env variables (#16172) 2025-08-13 21:09:41 +01:00
Jens L.
dbe7bfe58b tasks: add sentry dramatiq integration (#16167) 2025-08-13 18:53:12 +01:00
Teffen Ellis
05d4d207d7 web: Fix hidden textarea required attribute. (#16168)
* web: Fix hidden textarea `required` attribute.

* web: Fix missing flag property.

* web: Clarify field error reporting.
2025-08-13 12:31:00 -04:00
Marc 'risson' Schmitt
11efc75451 ci: release: consolidation bump version and on tag (#16164)
Co-authored-by: Dominic R <dominic@sdko.org>
2025-08-13 18:21:12 +02:00
authentik-automation[bot]
4d2d020be1 web: bump API Client version (#16152)
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>
2025-08-13 14:48:57 +01:00
Marc 'risson' Schmitt
9c0905d76d ci: fix docker hub credentials (#16165) 2025-08-13 15:18:39 +02:00
Marc 'risson' Schmitt
3ca94b2198 root: fix custom packages installation in docker (#16157) 2025-08-13 12:24:21 +00:00
Marc 'risson' Schmitt
dbf51fb11f ci: release publish: fix missing permissions (#16155) 2025-08-13 13:22:35 +01:00
Marc 'risson' Schmitt
ad69eb955f ci: docker push: fix version missing dash (#16153) 2025-08-13 13:22:14 +01:00
transifex-integration[bot]
c867ebc014 translate: Updates for file web/xliff/en.xlf in fr (#16160)
Translate web/xliff/en.xlf in fr

100% translated source file: 'web/xliff/en.xlf'
on 'fr'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-08-13 12:06:38 +00:00
authentik-automation[bot]
adea1e460c core, web: update translations (#16159)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-08-13 00:38:30 +00:00
Marc 'risson' Schmitt
846c58e617 root: fix custom packages installation in docker (#16150) 2025-08-12 21:29:56 +00:00
Marcelo Elizeche Landó
352079fc3c core: bump redis from 6.2.0 to v6.3.0 (#15983) 2025-08-12 23:20:40 +02:00
dependabot[bot]
6786391732 core: bump github.com/redis/go-redis/v9 from 9.11.0 to 9.12.1 (#16121)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 23:19:52 +02:00
dependabot[bot]
4b3d08154d core: bump astral-sh/uv from 0.8.8 to 0.8.9 (#16120)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 23:19:33 +02:00
authentik-automation[bot]
130fe4cac7 root: bump version to 2025.10.0-rc1 (#16149)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-08-12 21:17:14 +00:00
165 changed files with 6994 additions and 1989 deletions

View File

@@ -33,17 +33,12 @@ packages/prettier-config @goauthentik/frontend
packages/tsconfig @goauthentik/frontend
# Web
web/ @goauthentik/frontend
tests/wdio/ @goauthentik/frontend
# Locale
locale/ @goauthentik/backend @goauthentik/frontend
web/xliff/ @goauthentik/backend @goauthentik/frontend
# Docs & Website
docs/ @goauthentik/docs
# TODO Remove after moving website to docs
# Docs
website/ @goauthentik/docs
CODE_OF_CONDUCT.md @goauthentik/docs
# Security
SECURITY.md @goauthentik/security @goauthentik/docs
# TODO Remove after moving website to docs
website/security/ @goauthentik/security @goauthentik/docs
docs/security/ @goauthentik/security @goauthentik/docs

View File

@@ -26,7 +26,7 @@ RUN npm run build && \
npm run build:sfe
# Stage 2: Build go proxy
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS go-builder
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.25-bookworm AS go-builder
ARG TARGETOS
ARG TARGETARCH
@@ -76,9 +76,9 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
/bin/sh -c "GEOIPUPDATE_LICENSE_KEY_FILE=/run/secrets/GEOIPUPDATE_LICENSE_KEY /usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
# Stage 4: Download uv
FROM ghcr.io/astral-sh/uv:0.8.8 AS uv
FROM ghcr.io/astral-sh/uv:0.8.13 AS uv
# Stage 5: Base python image
FROM ghcr.io/goauthentik/fips-python:3.13.6-slim-bookworm-fips AS python-base
FROM ghcr.io/goauthentik/fips-python:3.13.7-slim-bookworm-fips AS python-base
ENV VENV_PATH="/ak-root/.venv" \
PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \

View File

@@ -25,7 +25,28 @@ Even if the issue is not a CVE, we still greatly appreciate your help in hardeni
## Reporting a Vulnerability
To report a vulnerability, send an email to [security@goauthentik.io](mailto:security@goauthentik.io). Be sure to include relevant information like which version you've found the issue in, instructions on how to reproduce the issue, and anything else that might make it easier for us to find the issue.
If you discover a potential vulnerability, please report it responsibly through one of the following channels:
- **Email**: [security@goauthentik.io](mailto:security@goauthentik.io)
- **GitHub**: Submit a private security advisory via our [repositorys advisory portal](https://github.com/goauthentik/authentik/security/advisories/new)
When submitting a report, please include as much detail as possible, such as:
- **Affected version(s)**: The version of authentik where the issue was identified.
- **Steps to reproduce**: A clear description or proof of concept to help us verify the issue.
- **Impact assessment**: How the vulnerability could be exploited and its potential effect.
- **Additional information**: Logs, configuration details (if relevant), or any suggested mitigations.
We kindly ask that you do not disclose the vulnerability publicly until we have confirmed and addressed the issue.
Our team will:
- Acknowledge receipt of your report as quickly as possible.
- Keep you updated on the investigation and resolution progress.
## Researcher Recognition
We value contributions from the security community. For each valid report, we will publish a dedicated entry on our Security Advisory page that optionally includes the reporters name (or preferred alias). Please note that while we do not currently offer monetary bounties, we are committed to giving researchers appropriate credit for their efforts in keeping authentik secure.
## Severity levels

View File

@@ -3,7 +3,7 @@
from functools import lru_cache
from os import environ
VERSION = "2025.8.0"
VERSION = "2025.10.0-rc1"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@@ -21,8 +21,6 @@ from rest_framework.serializers import (
raise_errors_on_nested_writes,
)
from authentik.rbac.permissions import assign_initial_permissions
def is_dict(value: Any):
"""Ensure a value is a dictionary, useful for JSONFields"""
@@ -52,15 +50,6 @@ class ModelSerializer(BaseModelSerializer):
serializer_field_mapping = BaseModelSerializer.serializer_field_mapping.copy()
serializer_field_mapping[models.JSONField] = JSONDictField
def create(self, validated_data):
instance = super().create(validated_data)
request = self.context.get("request")
if request and hasattr(request, "user") and not request.user.is_anonymous:
assign_initial_permissions(request.user, instance)
return instance
def update(self, instance: Model, validated_data):
raise_errors_on_nested_writes("update", self, validated_data)
info = model_meta.get_field_info(instance)

View File

@@ -154,6 +154,7 @@ worker:
consumer_listen_timeout: "seconds=30"
task_max_retries: 20
task_default_time_limit: "minutes=10"
lock_purge_interval: "minutes=1"
task_purge_interval: "days=1"
task_expiration: "days=30"
scheduler_interval: "seconds=60"

View File

@@ -76,6 +76,7 @@ class OutpostConfig:
kubernetes_ingress_annotations: dict[str, str] = field(default_factory=dict)
kubernetes_ingress_secret_name: str = field(default="authentik-outpost-tls")
kubernetes_ingress_class_name: str | None = field(default=None)
kubernetes_ingress_path_type: str | None = field(default=None)
kubernetes_httproute_annotations: dict[str, str] = field(default_factory=dict)
kubernetes_httproute_parent_refs: list[dict[str, str]] = field(default_factory=list)
kubernetes_service_type: str = field(default="ClusterIP")
@@ -151,7 +152,7 @@ class OutpostServiceConnection(ScheduledModel, models.Model):
state = cache.get(self.state_key, None)
if not state:
outpost_service_connection_monitor.send_with_options(args=(self.pk), rel_obj=self)
outpost_service_connection_monitor.send_with_options(args=(self.pk,), rel_obj=self)
return OutpostServiceConnectionState("", False)
return state

View File

@@ -11,7 +11,8 @@ def migrate_sessions(apps, schema_editor, model):
AuthenticatedSession = apps.get_model("authentik_core", "AuthenticatedSession")
db_alias = schema_editor.connection.alias
for obj in Model.objects.using(db_alias).all():
objs = list(Model.objects.using(db_alias).select_related("old_session").all())
for obj in objs:
if not obj.old_session:
continue
obj.session = (

View File

@@ -23,7 +23,12 @@ def user_session_deleted_oauth_backchannel_logout_and_tokens_removal(
backchannel_logout_notification_dispatch.send(
revocations=[
(token.provider_id, token.id_token.iss, token.session.user.uid)
(
token.provider_id,
token.id_token.iss,
token.id_token.sub,
instance.session.session_key,
)
for token in access_tokens
],
)

View File

@@ -14,13 +14,19 @@ LOGGER = get_logger()
@actor(description=_("Send a back-channel logout request to the registered client"))
def send_backchannel_logout_request(provider_pk: int, iss: str, sub: str = None) -> bool:
def send_backchannel_logout_request(
provider_pk: int,
iss: str,
sub: str | None = None,
session_key: str | None = None,
) -> bool:
"""Send a back-channel logout request to the registered client
Args:
provider_pk: The OAuth2 provider's primary key
iss: The issuer URL for the logout token
sub: The subject identifier to include in the logout token
session_key: The authentik session key to hash and include in the logout token
Returns:
bool: True if the request was sent successfully, False otherwise
@@ -33,11 +39,10 @@ def send_backchannel_logout_request(provider_pk: int, iss: str, sub: str = None)
return
# Generate the logout token
logout_token = create_logout_token(iss, provider, None, sub)
logout_token = create_logout_token(provider, iss, sub, session_key)
# Get the back-channel logout URI from the provider's dedicated backchannel_logout_uri field
# Back-channel logout requires explicit configuration - no fallback to redirect URIs
backchannel_logout_uri = provider.backchannel_logout_uri
if not backchannel_logout_uri:
self.info("No back-channel logout URI found for provider")
@@ -60,9 +65,9 @@ def send_backchannel_logout_request(provider_pk: int, iss: str, sub: str = None)
def backchannel_logout_notification_dispatch(revocations: list, **kwargs):
"""Handle backchannel logout notifications dispatched via signal"""
for revocation in revocations:
provider_pk, iss, sub = revocation
provider_pk, iss, sub, session_key = revocation
provider = OAuth2Provider.objects.filter(pk=provider_pk).first()
send_backchannel_logout_request.send_with_options(
args=(provider_pk, iss, sub),
args=(provider_pk, iss, sub, session_key),
rel_obj=provider,
)

View File

@@ -217,17 +217,17 @@ class HttpResponseRedirectScheme(HttpResponseRedirect):
def create_logout_token(
iss: str,
provider: OAuth2Provider,
session_key: str | None = None,
iss: str,
sub: str | None = None,
session_key: str | None = None,
) -> str:
"""Create a logout token for Back-Channel Logout
As per https://openid.net/specs/openid-connect-backchannel-1_0.html
"""
LOGGER.debug("Creating logout token", provider=provider, session_key=session_key, sub=sub)
LOGGER.debug("Creating logout token", provider=provider, sub=sub)
# Create the logout token payload
payload = {

View File

@@ -127,6 +127,9 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]):
and self.controller.outpost.config.kubernetes_ingress_secret_name
):
tls_hosts.append(external_host_name.hostname)
path_type = "Prefix"
if self.controller.outpost.config.kubernetes_ingress_path_type:
path_type = self.controller.outpost.config.kubernetes_ingress_path_type
if proxy_provider.mode in [
ProxyMode.FORWARD_SINGLE,
ProxyMode.FORWARD_DOMAIN,
@@ -143,7 +146,7 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]):
),
),
path="/outpost.goauthentik.io",
path_type="Prefix",
path_type=path_type,
)
]
),
@@ -161,7 +164,7 @@ class IngressReconciler(KubernetesObjectReconciler[V1Ingress]):
),
),
path="/",
path_type="Prefix",
path_type=path_type,
)
]
),

View File

@@ -0,0 +1,69 @@
"""InitialPermissions middleware"""
from collections.abc import Callable
from contextvars import ContextVar
from functools import partial
from django.db.models import Model
from django.db.models.signals import post_save
from django.http import HttpRequest, HttpResponse
from authentik.core.models import User
from authentik.rbac.permissions import assign_initial_permissions
_CTX_REQUEST = ContextVar[HttpRequest | None]("authentik_initial_permissions_request", default=None)
class InitialPermissionsMiddleware:
"""Register a handler for duration of request-response that assigns InitialPermissions"""
get_response: Callable[[HttpRequest], HttpResponse]
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
self.get_response = get_response
def get_uid(self, request_id: str) -> str:
return f"InitialPermissionMiddleware-{request_id}"
def connect(self, request: HttpRequest):
if not hasattr(request, "request_id"):
return
post_save.connect(
partial(self.post_save_handler, request=request),
dispatch_uid=self.get_uid(request.request_id),
weak=False,
)
def disconnect(self, request: HttpRequest):
if not hasattr(request, "request_id"):
return
post_save.disconnect(dispatch_uid=self.get_uid(request.request_id))
def __call__(self, request: HttpRequest) -> HttpResponse:
_CTX_REQUEST.set(request)
self.connect(request)
response = self.get_response(request)
self.disconnect(request)
_CTX_REQUEST.set(None)
return response
def process_exception(self, request: HttpRequest, exception: Exception):
self.disconnect(request)
def post_save_handler(
self,
request: HttpRequest,
instance: Model,
created: bool,
**_,
):
if not created:
return
if request.request_id != _CTX_REQUEST.get().request_id:
return
user: User = request.user
if not user or user.is_anonymous:
return
assign_initial_permissions(user, instance)

View File

@@ -5,9 +5,12 @@ from django.db.models import Model
from guardian.shortcuts import assign_perm
from rest_framework.permissions import BasePermission, DjangoObjectPermissions
from rest_framework.request import Request
from structlog.stdlib import get_logger
from authentik.rbac.models import InitialPermissions, InitialPermissionsMode
LOGGER = get_logger()
class ObjectPermissions(DjangoObjectPermissions):
"""RBAC Permissions"""
@@ -71,4 +74,10 @@ def assign_initial_permissions(user, instance: Model):
if initial_permissions.mode == InitialPermissionsMode.USER
else initial_permissions.role.group
)
LOGGER.debug(
"Adding initial permission",
initial_permission=permission,
subject=assign_to,
object=instance,
)
assign_perm(permission, assign_to, instance)

View File

@@ -4,7 +4,6 @@ import importlib
from collections import OrderedDict
from hashlib import sha512
from pathlib import Path
from tempfile import gettempdir
import orjson
from sentry_sdk import set_tag
@@ -266,6 +265,7 @@ MIDDLEWARE = [
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"authentik.core.middleware.ImpersonateMiddleware",
"authentik.rbac.middleware.InitialPermissionsMiddleware",
]
MIDDLEWARE_LAST = [
"django_prometheus.middleware.PrometheusAfterMiddleware",
@@ -368,6 +368,9 @@ DRAMATIQ = {
"broker_class": "authentik.tasks.broker.Broker",
"channel_prefix": "authentik",
"task_model": "authentik.tasks.models.Task",
"lock_purge_interval": timedelta_from_string(
CONFIG.get("worker.lock_purge_interval")
).total_seconds(),
"task_purge_interval": timedelta_from_string(
CONFIG.get("worker.task_purge_interval")
).total_seconds(),
@@ -424,7 +427,6 @@ DRAMATIQ = {
(
"authentik.tasks.middleware.MetricsMiddleware",
{
"multiproc_dir": str(Path(gettempdir()) / "authentik_prometheus_tmp"),
"prefix": "authentik",
},
),

View File

@@ -198,7 +198,10 @@ class AuthenticatorDuoStageViewSet(UsedByMixin, ModelViewSet):
return {"error": "", "count": created}
except RuntimeError as exc:
LOGGER.warning("failed to get users from duo", exc=exc)
return {"error": str(exc), "count": created}
return {
"error": "An internal error occurred while importing devices.",
"count": created,
}
class DuoDeviceSerializer(ModelSerializer):

View File

@@ -168,6 +168,8 @@ class AuthenticatorDuoStageTests(FlowTestCase):
client_secret=generate_id(),
api_hostname=generate_id(),
)
# Test missing admin credentials
response = self.client.post(
reverse(
"authentik_api:authenticatorduostage-import-devices-automatic",
@@ -178,6 +180,31 @@ class AuthenticatorDuoStageTests(FlowTestCase):
)
self.assertEqual(response.status_code, 400)
# Test internal error handling
stage.admin_integration_key = generate_id()
stage.admin_secret_key = generate_id()
stage.save()
with patch(
"duo_client.admin.Admin.get_users_iterator",
MagicMock(side_effect=RuntimeError("Duo API error")),
):
response = self.client.post(
reverse(
"authentik_api:authenticatorduostage-import-devices-automatic",
kwargs={
"pk": str(stage.pk),
},
),
)
self.assertEqual(response.status_code, 400)
self.assertJSONEqual(
response.content,
{
"error": "An internal error occurred while importing devices.",
"count": 0,
},
)
def test_api_import_automatic(self):
"""test `import_devices_automatic`"""
self.client.force_login(self.user)

View File

@@ -35,7 +35,12 @@ class Command(TenantCommand):
template_context={},
)
try:
send_mail(message.__dict__, stage.pk)
if not stage.use_global_settings:
message.from_email = stage.from_address
send_mail.send(message.__dict__, stage.pk).get_result(block=True)
self.stdout.write(self.style.SUCCESS(f"Test email sent to {options['to']}"))
finally:
if delete_stage:
stage.delete()

View File

@@ -0,0 +1,66 @@
"""Test email management commands"""
from unittest.mock import patch
from django.core import mail
from django.core.mail.backends.locmem import EmailBackend
from django.core.management import call_command
from django.test import TestCase
from authentik.core.tests.utils import create_test_admin_user
from authentik.stages.email.models import EmailStage
class TestEmailManagementCommands(TestCase):
"""Test email management commands"""
def setUp(self):
self.user = create_test_admin_user()
def test_test_email_command_with_stage(self):
"""Test test_email command with specified stage"""
EmailStage.objects.create(
name="test-stage",
from_address="test@authentik.local",
host="localhost",
port=25,
)
with patch("authentik.stages.email.models.EmailStage.backend_class", EmailBackend):
call_command("test_email", "test@example.com", stage="test-stage")
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "authentik Test-Email")
self.assertEqual(mail.outbox[0].to, ["test@example.com"])
def test_test_email_command_with_global_settings(self):
"""Test test_email command with global settings"""
# Mock the backend to use Django's locmem backend
with patch("authentik.stages.email.models.EmailStage.backend_class", EmailBackend):
call_command("test_email", "test@example.com")
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "authentik Test-Email")
self.assertEqual(mail.outbox[0].to, ["test@example.com"])
def test_test_email_command_invalid_stage(self):
"""Test test_email command with invalid stage"""
call_command("test_email", "test@example.com", stage="nonexistent")
self.assertEqual(len(mail.outbox), 0)
def test_test_email_command_with_custom_from(self):
"""Test test_email command respects custom from address"""
EmailStage.objects.create(
name="test-stage",
from_address="custom@authentik.local",
host="localhost",
port=25,
)
with patch("authentik.stages.email.models.EmailStage.backend_class", EmailBackend):
call_command("test_email", "test@example.com", stage="test-stage")
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].from_email, "custom@authentik.local")
self.assertEqual(mail.outbox[0].to, ["test@example.com"])

View File

@@ -0,0 +1,10 @@
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = "ak createsuperuser should not be used. Instead, use ak create_admin_group"
def handle(self, *args, **options): # noqa: ANN001, D401
raise RuntimeError(
"ak createsuperuser should not be used. Instead, use ak create_admin_group"
)

View File

@@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://goauthentik.io/blueprints/schema.json",
"type": "object",
"title": "authentik 2025.8.0 Blueprint schema",
"title": "authentik 2025.10.0-rc1 Blueprint schema",
"required": [
"version",
"entries"

View File

@@ -5,7 +5,7 @@ metadata:
blueprints.goauthentik.io/system-bootstrap: "true"
blueprints.goauthentik.io/system: "true"
blueprints.goauthentik.io/description: |
This blueprint configures the default admin user and group, and configures them for the [Automated install](https://goauthentik.io/docs/installation/automated-install).
This blueprint configures the default admin user and group, and configures them for the [Automated install](https://docs.goauthentik.io/docs/install-config/automated-install?utm_source=bootstrap_blueprint).
context:
username: akadmin
group_name: authentik Admins

View File

@@ -48,7 +48,7 @@ services:
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.8.0}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.10.0-rc1}
ports:
- ${COMPOSE_PORT_HTTP:-9000}:9000
- ${COMPOSE_PORT_HTTPS:-9443}:9443
@@ -72,7 +72,7 @@ services:
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_REDIS__HOST: redis
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.8.0}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.10.0-rc1}
restart: unless-stopped
user: root
volumes:

8
go.mod
View File

@@ -6,7 +6,7 @@ require (
beryju.io/ldap v0.1.0
github.com/avast/retry-go/v4 v4.6.1
github.com/coreos/go-oidc/v3 v3.15.0
github.com/getsentry/sentry-go v0.35.0
github.com/getsentry/sentry-go v0.35.1
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
github.com/go-ldap/ldap/v3 v3.4.11
github.com/go-openapi/runtime v0.28.0
@@ -23,13 +23,13 @@ require (
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
github.com/pires/go-proxyproto v0.8.1
github.com/prometheus/client_golang v1.23.0
github.com/redis/go-redis/v9 v9.11.0
github.com/redis/go-redis/v9 v9.12.1
github.com/sethvargo/go-envconfig v1.3.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0
github.com/stretchr/testify v1.11.0
github.com/wwt/guac v1.3.2
goauthentik.io/api/v3 v3.2025064.8
goauthentik.io/api/v3 v3.2025100.2
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
golang.org/x/oauth2 v0.30.0
golang.org/x/sync v0.16.0

16
go.sum
View File

@@ -26,8 +26,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/getsentry/sentry-go v0.35.0 h1:+FJNlnjJsZMG3g0/rmmP7GiKjQoUF5EXfEtBwtPtkzY=
github.com/getsentry/sentry-go v0.35.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
github.com/getsentry/sentry-go v0.35.1 h1:iopow6UVLE2aXu46xKVIs8Z9D/YZkJrHkgozrxa+tOQ=
github.com/getsentry/sentry-go v0.35.1/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
@@ -148,8 +148,8 @@ github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2
github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/redis/go-redis/v9 v9.11.0 h1:E3S08Gl/nJNn5vkxd2i78wZxWAPNZgUNTp8WIJUAiIs=
github.com/redis/go-redis/v9 v9.11.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg=
github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -169,8 +169,8 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8=
github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/wwt/guac v1.3.2 h1:sH6OFGa/1tBs7ieWBVlZe7t6F5JAOWBry/tqQL/Vup4=
github.com/wwt/guac v1.3.2/go.mod h1:eKm+NrnK7A88l4UBEcYNpZQGMpZRryYKoz4D/0/n1C0=
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
@@ -185,8 +185,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
goauthentik.io/api/v3 v3.2025064.8 h1:wgegkPUtGSrOR7+Rnd0cxLVU0cEea87BatjESa6BJv0=
goauthentik.io/api/v3 v3.2025064.8/go.mod h1:82lqAz4jxzl6Cg0YDbhNtvvTG2rm6605ZhdJFnbbsl8=
goauthentik.io/api/v3 v3.2025100.2 h1:OF8qEpn6PzZFlB16RzL51RSIyFOY234gAWfd8/kjzhc=
goauthentik.io/api/v3 v3.2025100.2/go.mod h1:82lqAz4jxzl6Cg0YDbhNtvvTG2rm6605ZhdJFnbbsl8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=

View File

@@ -1 +1 @@
2025.8.0
2025.10.0-rc1

View File

@@ -0,0 +1,91 @@
// https://github.com/gorilla/handlers/issues/259#issuecomment-2671695039
package web
import (
"bufio"
"net"
"net/http"
"github.com/gorilla/handlers"
)
// compressHandler is an HTTP handler that adds the Content-Encoding header
// back to responses when removed by the http.FileServer.
//
// handlers.CompressHandler(newCompressHandler(http.FileServer(...)))
type compressHandler struct {
// handler is an HTTP handler, usually an http.FileServer.
handler http.Handler
}
var _ http.Handler = &compressHandler{}
func NewCompressHandler(handler http.Handler) http.Handler {
h := &compressHandler{
handler: handler,
}
return handlers.CompressHandler(h)
}
func (h *compressHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// The wrapped response writer saves the incoming content encoding so
// it can be restored when writing the response headers.
cw := &compressedResponseWriter{
encoding: w.Header().Get("Content-Encoding"),
fixed: false,
responseWriter: w,
}
h.handler.ServeHTTP(cw, r)
}
// compressedResponseWriter is an http.ResponseWriter that ensures that a
// previously-set Content-Encoding header is in place before writing the
// response.
type compressedResponseWriter struct {
encoding string
fixed bool
responseWriter http.ResponseWriter
}
var _ http.ResponseWriter = &compressedResponseWriter{}
func (w *compressedResponseWriter) Header() http.Header {
return w.responseWriter.Header()
}
func (w *compressedResponseWriter) fixContentEncoding() {
if w.fixed {
return
}
w.fixed = true
// The Go 1.23 http.FileServer() removes headers like Content-Encoding
// from error responses. This breaks gzip and deflate encoding.
// https://github.com/gorilla/handlers/issues/259
// https://github.com/golang/go/issues/66343
if w.encoding == "gzip" || w.encoding == "deflate" {
if w.Header().Get("Content-Encoding") == "" {
w.Header().Set("Content-Encoding", w.encoding)
}
}
}
func (w *compressedResponseWriter) Write(data []byte) (int, error) {
w.fixContentEncoding()
return w.responseWriter.Write(data)
}
func (w *compressedResponseWriter) WriteHeader(statusCode int) {
w.fixContentEncoding()
w.responseWriter.WriteHeader(statusCode)
}
func (w *compressedResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if hj, ok := w.responseWriter.(http.Hijacker); ok {
return hj.Hijack()
}
return nil, nil, http.ErrNotSupported
}
// Ensure our compressedResponseWriter implements the necessary interfaces.
var _ http.ResponseWriter = &compressedResponseWriter{}
var _ http.Hijacker = &compressedResponseWriter{}

View File

@@ -5,6 +5,7 @@ import (
"encoding/pem"
"errors"
"fmt"
"io"
"net/http"
"net/http/httputil"
"net/url"
@@ -15,6 +16,7 @@ import (
"goauthentik.io/internal/config"
"goauthentik.io/internal/utils/sentry"
"goauthentik.io/internal/utils/web"
staticWeb "goauthentik.io/web"
)
var (
@@ -88,19 +90,81 @@ func (ws *WebServer) configureProxy() {
}
func (ws *WebServer) proxyErrorHandler(rw http.ResponseWriter, req *http.Request, err error) {
if !errors.Is(err, ErrAuthentikStarting) {
ws.log.WithError(err).Warning("failed to proxy to backend")
accept := req.Header.Get("Accept")
header := rw.Header()
if errors.Is(err, ErrAuthentikStarting) {
header.Set("Retry-After", "5")
if strings.Contains(accept, "application/json") {
header.Set("Content-Type", "application/json")
err = json.NewEncoder(rw).Encode(map[string]string{
"error": "authentik starting",
})
if err != nil {
ws.log.WithError(err).Warning("failed to write error message")
return
}
} else if strings.Contains(accept, "text/html") {
header.Set("Content-Type", "text/html")
rw.WriteHeader(http.StatusServiceUnavailable)
loadingSplashFile, err := staticWeb.StaticDir.Open("standalone/loading/startup.html")
if err != nil {
ws.log.WithError(err).Warning("failed to open startup splash screen")
return
}
loadingSplashHTML, err := io.ReadAll(loadingSplashFile)
if err != nil {
ws.log.WithError(err).Warning("failed to read startup splash screen")
return
}
_, err = rw.Write(loadingSplashHTML)
if err != nil {
ws.log.WithError(err).Warning("failed to write startup splash screen")
return
}
} else {
header.Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusServiceUnavailable)
// Fallback to just a status message
_, err = rw.Write([]byte("authentik starting"))
if err != nil {
ws.log.WithError(err).Warning("failed to write initializing HTML")
}
}
return
}
rw.WriteHeader(http.StatusBadGateway)
ws.log.WithError(err).Warning("failed to proxy to backend")
em := fmt.Sprintf("failed to connect to authentik backend: %v", err)
// return json if the client asks for json
if req.Header.Get("Accept") == "application/json" {
if strings.Contains(accept, "application/json") {
header.Set("Content-Type", "application/json")
rw.WriteHeader(http.StatusBadGateway)
err = json.NewEncoder(rw).Encode(map[string]string{
"error": em,
})
} else {
header.Set("Content-Type", "text/plain")
rw.WriteHeader(http.StatusBadGateway)
_, err = rw.Write([]byte(em))
}
if err != nil {
ws.log.WithError(err).Warning("failed to write error message")
}

View File

@@ -17,9 +17,7 @@ func (ws *WebServer) configureStatic() {
// Setup routers
staticRouter := ws.loggingRouter.NewRoute().Subrouter()
staticRouter.Use(ws.staticHeaderMiddleware)
indexLessRouter := staticRouter.NewRoute().Subrouter()
// Specifically disable index
indexLessRouter.Use(web.DisableIndex)
staticRouter.Use(web.DisableIndex)
distFs := http.FileServer(http.Dir("./web/dist"))
@@ -31,18 +29,18 @@ func (ws *WebServer) configureStatic() {
return h
}
indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/static/dist/").Handler(pathStripper(
staticRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/static/dist/").Handler(pathStripper(
distFs,
"static/dist/",
config.Get().Web.Path,
))
indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/static/authentik/").Handler(pathStripper(
staticRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/static/authentik/").Handler(pathStripper(
http.FileServer(http.Dir("./web/authentik")),
"static/authentik/",
config.Get().Web.Path,
))
indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/flow/{flow_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
staticRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/flow/{flow_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
pathStripper(
@@ -51,9 +49,9 @@ func (ws *WebServer) configureStatic() {
config.Get().Web.Path,
).ServeHTTP(rw, r)
})
indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/admin/assets").Handler(http.StripPrefix(fmt.Sprintf("%sif/admin", config.Get().Web.Path), distFs))
indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/user/assets").Handler(http.StripPrefix(fmt.Sprintf("%sif/user", config.Get().Web.Path), distFs))
indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/rac/{app_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
staticRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/admin/assets").Handler(http.StripPrefix(fmt.Sprintf("%sif/admin", config.Get().Web.Path), distFs))
staticRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/user/assets").Handler(http.StripPrefix(fmt.Sprintf("%sif/user", config.Get().Web.Path), distFs))
staticRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/rac/{app_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
pathStripper(
@@ -66,7 +64,7 @@ func (ws *WebServer) configureStatic() {
// Media files, if backend is file
if config.Get().Storage.Media.Backend == "file" {
fsMedia := http.FileServer(http.Dir(config.Get().Storage.Media.File.Path))
indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/media/").Handler(pathStripper(
staticRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/media/").Handler(pathStripper(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox")
fsMedia.ServeHTTP(w, r)

View File

@@ -12,7 +12,6 @@ import (
"path"
"time"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/gorilla/securecookie"
"github.com/pires/go-proxyproto"
@@ -60,7 +59,7 @@ func NewWebServer() *WebServer {
l := log.WithField("logger", "authentik.router")
mainHandler := mux.NewRouter()
mainHandler.Use(web.ProxyHeaders())
mainHandler.Use(handlers.CompressHandler)
mainHandler.Use(web.NewCompressHandler)
loggingHandler := mainHandler.NewRoute().Subrouter()
loggingHandler.Use(web.NewLoggingHandler(l, nil))

View File

@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
# Stage 1: Build
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS builder
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.25-bookworm AS builder
ARG TARGETOS
ARG TARGETARCH

View File

@@ -68,6 +68,11 @@ function prepare_debug {
chown authentik:authentik /unittest.xml
}
if [[ -z "${PROMETHEUS_MULTIPROC_DIR}" ]]; then
export PROMETHEUS_MULTIPROC_DIR="${TMPDIR:-/tmp}"
fi
mkdir -p "${PROMETHEUS_MULTIPROC_DIR}"
if [[ "$(python -m authentik.lib.config debugger 2>/dev/null)" == "True" ]]; then
prepare_debug
fi

View File

@@ -9,7 +9,7 @@
"version": "0.0.0",
"license": "MIT",
"devDependencies": {
"aws-cdk": "^2.1024.0",
"aws-cdk": "^2.1026.0",
"cross-env": "^10.0.0"
},
"engines": {
@@ -24,9 +24,9 @@
"license": "MIT"
},
"node_modules/aws-cdk": {
"version": "2.1024.0",
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1024.0.tgz",
"integrity": "sha512-hY0iVT2gPX/QOQXL7RSP2sqIRI/4BYU27vSmbhZxLEj//c3pkMkd9QpIHj7gOhyWC2gf6n5JuYPw27Dgw8FEdA==",
"version": "2.1026.0",
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1026.0.tgz",
"integrity": "sha512-JdXR20s9gMHY3niweK5/D9tILLG8u2FOyJjWgSaNZGJ+pq9u0sBFxufXPO4VxJzDitGFOIW5VvQThXP+Y2VrVA==",
"dev": true,
"license": "Apache-2.0",
"bin": {

View File

@@ -10,7 +10,7 @@
"node": ">=20"
},
"devDependencies": {
"aws-cdk": "^2.1024.0",
"aws-cdk": "^2.1026.0",
"cross-env": "^10.0.0"
}
}

View File

@@ -26,7 +26,7 @@ Parameters:
Description: authentik Docker image
AuthentikVersion:
Type: String
Default: 2025.8.0
Default: 2025.10.0-rc1
Description: authentik Docker image tag
AuthentikServerCPU:
Type: Number

View File

@@ -33,15 +33,12 @@ wait_for_db()
_tmp = Path(gettempdir())
worker_class = "lifecycle.worker.DjangoUvicornWorker"
worker_tmp_dir = str(_tmp.joinpath("authentik_gunicorn_tmp"))
prometheus_tmp_dir = str(_tmp.joinpath("authentik_prometheus_tmp"))
os.makedirs(worker_tmp_dir, exist_ok=True)
os.makedirs(prometheus_tmp_dir, exist_ok=True)
bind = f"unix://{str(_tmp.joinpath('authentik-core.sock'))}"
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
os.environ.setdefault("PROMETHEUS_MULTIPROC_DIR", prometheus_tmp_dir)
preload_app = True

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-08-11 00:12+0000\n"
"POT-Creation-Date: 2025-08-18 00:11+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -790,6 +790,12 @@ msgstr ""
msgid "Email"
msgstr ""
#: authentik/events/models.py
msgid ""
"Only send notification once, for example when sending a webhook into a chat "
"channel."
msgstr ""
#: authentik/events/models.py
msgid ""
"Customize the body of the request. Mapping should return data that is JSON-"
@@ -802,12 +808,6 @@ msgid ""
"of key-value pairs"
msgstr ""
#: authentik/events/models.py
msgid ""
"Only send notification once, for example when sending a webhook into a chat "
"channel."
msgstr ""
#: authentik/events/models.py
msgid "Severity"
msgstr ""
@@ -2905,10 +2905,6 @@ msgstr ""
msgid "Duo Devices"
msgstr ""
#: authentik/stages/authenticator_email/models.py
msgid "Email OTP"
msgstr ""
#: authentik/stages/authenticator_email/models.py
#: authentik/stages/email/models.py
msgid ""
@@ -3269,6 +3265,14 @@ msgstr ""
msgid "Account Confirmation"
msgstr ""
#: authentik/stages/email/models.py
msgid "Email OTP"
msgstr ""
#: authentik/stages/email/models.py
msgid "Event Notification"
msgstr ""
#: authentik/stages/email/models.py
msgid ""
"The time window used to count recent account recovery attempts. If the "

Binary file not shown.

Binary file not shown.

Binary file not shown.

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@goauthentik/authentik",
"version": "2025.8.0",
"version": "2025.10.0-rc1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@goauthentik/authentik",
"version": "2025.8.0",
"version": "2025.10.0-rc1",
"dependencies": {
"@eslint/js": "^9.31.0",
"@typescript-eslint/eslint-plugin": "^8.38.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@goauthentik/authentik",
"version": "2025.8.0",
"version": "2025.10.0-rc1",
"private": true,
"type": "module",
"dependencies": {

View File

@@ -237,6 +237,9 @@ class _PostgresConsumer(Consumer):
# Override because dramatiq doesn't allow us setting this manually
self.timeout = Conf().worker["consumer_listen_timeout"]
self.lock_purge_interval = timezone.timedelta(seconds=Conf().lock_purge_interval)
self.lock_purge_last_run = timezone.now()
self.task_purge_interval = timezone.timedelta(seconds=Conf().task_purge_interval)
self.task_purge_last_run = timezone.now() - self.task_purge_interval
@@ -378,6 +381,8 @@ class _PostgresConsumer(Consumer):
# Force creation of listen connection
_ = self.listen_connection
self._purge_locks()
processing = len(self.in_processing)
if processing >= self.prefetch:
# Wait and don't consume the message, other worker will be faster
@@ -415,24 +420,26 @@ class _PostgresConsumer(Consumer):
)
# No message to process
self._purge_locks()
self._auto_purge()
self._scheduler()
return None
def _purge_locks(self):
if timezone.now() - self.lock_purge_last_run < self.lock_purge_interval:
return
while True:
try:
message_id = self.unlock_queue.get(block=False)
except Empty:
return
break
self.logger.debug("Unlocking message", message_id=message_id)
with self.connection.cursor() as cursor:
cursor.execute(
"SELECT pg_advisory_unlock(%s)", (self._get_message_lock_id(message_id),)
)
self.unlock_queue.task_done()
self.lock_purge_last_run = timezone.now()
def _auto_purge(self):
if timezone.now() - self.task_purge_last_run < self.task_purge_interval:
@@ -444,6 +451,7 @@ class _PostgresConsumer(Consumer):
result_expiry__lte=timezone.now(),
).delete()
self.logger.info("Purged messages in all queues", count=count)
self.task_purge_last_run = timezone.now()
def _scheduler(self):
if not self.scheduler:
@@ -451,6 +459,7 @@ class _PostgresConsumer(Consumer):
if timezone.now() - self.scheduler_last_run < self.scheduler_interval:
return
self.scheduler.run()
self.schedule_last_run = timezone.now()
@raise_connection_error
def close(self):
@@ -465,4 +474,7 @@ class _PostgresConsumer(Consumer):
if self._listen_connection is not None:
conn = self._listen_connection
self._listen_connection = None
conn.close()
try:
conn.close()
except DatabaseError:
pass

View File

@@ -56,6 +56,10 @@ class Conf:
def task_model(self) -> str:
return self.conf["task_model"]
@property
def lock_purge_interval(self) -> int:
return self.conf.get("lock_purge_interval", 60)
@property
def task_purge_interval(self) -> int:
# 24 hours

View File

@@ -26,7 +26,7 @@ class HTTPServer(BaseHTTPServer):
self.socket.close()
host, port = self.server_address[:2]
if host == "0.0.0.0": # nosec
if host == "0.0.0.0" and socket.has_dualstack_ipv6(): # nosec
host = "::" # nosec
# Strip IPv6 brackets
@@ -36,7 +36,9 @@ class HTTPServer(BaseHTTPServer):
self.server_address = (host, port)
self.address_family = (
socket.AF_INET6 if isinstance(ip_address(host), IPv6Address) else socket.AF_INET
socket.AF_INET6
if socket.has_dualstack_ipv6() and isinstance(ip_address(host), IPv6Address)
else socket.AF_INET
)
self.socket = socket.create_server(
@@ -141,7 +143,6 @@ class MetricsMiddleware(Middleware):
def __init__(
self,
prefix: str,
multiproc_dir: str,
labels: list[str] | None = None,
):
super().__init__()
@@ -151,9 +152,6 @@ class MetricsMiddleware(Middleware):
self.delayed_messages = set()
self.message_start_times = {}
os.makedirs(multiproc_dir, exist_ok=True)
os.environ.setdefault("PROMETHEUS_MULTIPROC_DIR", multiproc_dir)
@property
def forks(self):
from django_dramatiq_postgres.forks import worker_metrics

View File

@@ -10,8 +10,7 @@
"license": "MIT",
"dependencies": {
"deepmerge-ts": "^7.1.5",
"prism-react-renderer": "^2.4.1",
"react-dom": ">=18"
"prism-react-renderer": "^2.4.1"
},
"devDependencies": {
"@docusaurus/theme-common": "^3.8.1",
@@ -35,7 +34,8 @@
"@docusaurus/theme-common": "^3.8.1",
"@docusaurus/theme-search-algolia": "^3.8.1",
"@docusaurus/types": "^3.8.0",
"react": ">=18"
"react": ">=18",
"react-dom": ">=18"
},
"peerDependenciesMeta": {
"@docusaurus/theme-search-algolia": {
@@ -43,6 +43,9 @@
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
@@ -4643,9 +4646,9 @@
"license": "MIT"
},
"node_modules/@types/react": {
"version": "19.1.8",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz",
"integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==",
"version": "19.1.10",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz",
"integrity": "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==",
"dev": true,
"license": "MIT",
"dependencies": {

View File

@@ -132,9 +132,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz",
"integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
"integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==",
"cpu": [
"ppc64"
],
@@ -149,9 +149,9 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz",
"integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz",
"integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==",
"cpu": [
"arm"
],
@@ -166,9 +166,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz",
"integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz",
"integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==",
"cpu": [
"arm64"
],
@@ -183,9 +183,9 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz",
"integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz",
"integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==",
"cpu": [
"x64"
],
@@ -200,9 +200,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz",
"integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz",
"integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==",
"cpu": [
"arm64"
],
@@ -217,9 +217,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz",
"integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz",
"integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==",
"cpu": [
"x64"
],
@@ -234,9 +234,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz",
"integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz",
"integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==",
"cpu": [
"arm64"
],
@@ -251,9 +251,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz",
"integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz",
"integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==",
"cpu": [
"x64"
],
@@ -268,9 +268,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz",
"integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz",
"integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==",
"cpu": [
"arm"
],
@@ -285,9 +285,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz",
"integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz",
"integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==",
"cpu": [
"arm64"
],
@@ -302,9 +302,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz",
"integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz",
"integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==",
"cpu": [
"ia32"
],
@@ -319,9 +319,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz",
"integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz",
"integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==",
"cpu": [
"loong64"
],
@@ -336,9 +336,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz",
"integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz",
"integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==",
"cpu": [
"mips64el"
],
@@ -353,9 +353,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz",
"integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz",
"integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==",
"cpu": [
"ppc64"
],
@@ -370,9 +370,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz",
"integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz",
"integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==",
"cpu": [
"riscv64"
],
@@ -387,9 +387,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz",
"integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz",
"integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==",
"cpu": [
"s390x"
],
@@ -404,9 +404,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz",
"integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz",
"integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==",
"cpu": [
"x64"
],
@@ -421,9 +421,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz",
"integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz",
"integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==",
"cpu": [
"arm64"
],
@@ -438,9 +438,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz",
"integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz",
"integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==",
"cpu": [
"x64"
],
@@ -455,9 +455,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz",
"integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz",
"integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==",
"cpu": [
"arm64"
],
@@ -472,9 +472,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz",
"integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz",
"integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==",
"cpu": [
"x64"
],
@@ -489,9 +489,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz",
"integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz",
"integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==",
"cpu": [
"arm64"
],
@@ -506,9 +506,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz",
"integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz",
"integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==",
"cpu": [
"x64"
],
@@ -523,9 +523,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz",
"integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz",
"integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==",
"cpu": [
"arm64"
],
@@ -540,9 +540,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz",
"integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz",
"integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==",
"cpu": [
"ia32"
],
@@ -557,9 +557,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz",
"integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz",
"integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==",
"cpu": [
"x64"
],
@@ -904,9 +904,9 @@
}
},
"node_modules/@types/node": {
"version": "24.2.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz",
"integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==",
"version": "24.3.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz",
"integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1269,9 +1269,9 @@
}
},
"node_modules/esbuild": {
"version": "0.25.8",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz",
"integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==",
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
"integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -1282,32 +1282,32 @@
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.25.8",
"@esbuild/android-arm": "0.25.8",
"@esbuild/android-arm64": "0.25.8",
"@esbuild/android-x64": "0.25.8",
"@esbuild/darwin-arm64": "0.25.8",
"@esbuild/darwin-x64": "0.25.8",
"@esbuild/freebsd-arm64": "0.25.8",
"@esbuild/freebsd-x64": "0.25.8",
"@esbuild/linux-arm": "0.25.8",
"@esbuild/linux-arm64": "0.25.8",
"@esbuild/linux-ia32": "0.25.8",
"@esbuild/linux-loong64": "0.25.8",
"@esbuild/linux-mips64el": "0.25.8",
"@esbuild/linux-ppc64": "0.25.8",
"@esbuild/linux-riscv64": "0.25.8",
"@esbuild/linux-s390x": "0.25.8",
"@esbuild/linux-x64": "0.25.8",
"@esbuild/netbsd-arm64": "0.25.8",
"@esbuild/netbsd-x64": "0.25.8",
"@esbuild/openbsd-arm64": "0.25.8",
"@esbuild/openbsd-x64": "0.25.8",
"@esbuild/openharmony-arm64": "0.25.8",
"@esbuild/sunos-x64": "0.25.8",
"@esbuild/win32-arm64": "0.25.8",
"@esbuild/win32-ia32": "0.25.8",
"@esbuild/win32-x64": "0.25.8"
"@esbuild/aix-ppc64": "0.25.9",
"@esbuild/android-arm": "0.25.9",
"@esbuild/android-arm64": "0.25.9",
"@esbuild/android-x64": "0.25.9",
"@esbuild/darwin-arm64": "0.25.9",
"@esbuild/darwin-x64": "0.25.9",
"@esbuild/freebsd-arm64": "0.25.9",
"@esbuild/freebsd-x64": "0.25.9",
"@esbuild/linux-arm": "0.25.9",
"@esbuild/linux-arm64": "0.25.9",
"@esbuild/linux-ia32": "0.25.9",
"@esbuild/linux-loong64": "0.25.9",
"@esbuild/linux-mips64el": "0.25.9",
"@esbuild/linux-ppc64": "0.25.9",
"@esbuild/linux-riscv64": "0.25.9",
"@esbuild/linux-s390x": "0.25.9",
"@esbuild/linux-x64": "0.25.9",
"@esbuild/netbsd-arm64": "0.25.9",
"@esbuild/netbsd-x64": "0.25.9",
"@esbuild/openbsd-arm64": "0.25.9",
"@esbuild/openbsd-x64": "0.25.9",
"@esbuild/openharmony-arm64": "0.25.9",
"@esbuild/sunos-x64": "0.25.9",
"@esbuild/win32-arm64": "0.25.9",
"@esbuild/win32-ia32": "0.25.9",
"@esbuild/win32-x64": "0.25.9"
}
},
"node_modules/escape-string-regexp": {
@@ -2728,9 +2728,9 @@
}
},
"node_modules/typedoc-plugin-markdown": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.8.0.tgz",
"integrity": "sha512-BQqXnT9PETe6WEFf8bcsvvGEGQHbwTo/BFyY+RUIsSB05Y0Wn56iF+fK1PY2OKJJIhV4kp4dp7osaP9Bm5a0Zw==",
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.8.1.tgz",
"integrity": "sha512-ug7fc4j0SiJxSwBGLncpSo8tLvrT9VONvPUQqQDTKPxCoFQBADLli832RGPtj6sfSVJebNSrHZQRUdEryYH/7g==",
"dev": true,
"license": "MIT",
"engines": {

View File

@@ -502,17 +502,17 @@
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.0.tgz",
"integrity": "sha512-bhEz6OZeUR+O/6yx9Jk6ohX6H9JSFTaiY0v9/PuKT3oGK0rn0jNplLmyFUGV+a9gfYnVNwGDwS/UkLIuXNb2Rw==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.40.0.tgz",
"integrity": "sha512-w/EboPlBwnmOBtRbiOvzjD+wdiZdgFeo17lkltrtn7X37vagKKWJABvyfsJXTlHe6XBzugmYgd4A4nW+k8Mixw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.39.0",
"@typescript-eslint/type-utils": "8.39.0",
"@typescript-eslint/utils": "8.39.0",
"@typescript-eslint/visitor-keys": "8.39.0",
"@typescript-eslint/scope-manager": "8.40.0",
"@typescript-eslint/type-utils": "8.40.0",
"@typescript-eslint/utils": "8.40.0",
"@typescript-eslint/visitor-keys": "8.40.0",
"graphemer": "^1.4.0",
"ignore": "^7.0.0",
"natural-compare": "^1.4.0",
@@ -526,7 +526,7 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^8.39.0",
"@typescript-eslint/parser": "^8.40.0",
"eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
@@ -542,16 +542,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.0.tgz",
"integrity": "sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.40.0.tgz",
"integrity": "sha512-jCNyAuXx8dr5KJMkecGmZ8KI61KBUhkCob+SD+C+I5+Y1FWI2Y3QmY4/cxMCC5WAsZqoEtEETVhUiUMIGCf6Bw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.39.0",
"@typescript-eslint/types": "8.39.0",
"@typescript-eslint/typescript-estree": "8.39.0",
"@typescript-eslint/visitor-keys": "8.39.0",
"@typescript-eslint/scope-manager": "8.40.0",
"@typescript-eslint/types": "8.40.0",
"@typescript-eslint/typescript-estree": "8.40.0",
"@typescript-eslint/visitor-keys": "8.40.0",
"debug": "^4.3.4"
},
"engines": {
@@ -567,14 +567,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.39.0.tgz",
"integrity": "sha512-CTzJqaSq30V/Z2Og9jogzZt8lJRR5TKlAdXmWgdu4hgcC9Kww5flQ+xFvMxIBWVNdxJO7OifgdOK4PokMIWPew==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.40.0.tgz",
"integrity": "sha512-/A89vz7Wf5DEXsGVvcGdYKbVM9F7DyFXj52lNYUDS1L9yJfqjW/fIp5PgMuEJL/KeqVTe2QSbXAGUZljDUpArw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.39.0",
"@typescript-eslint/types": "^8.39.0",
"@typescript-eslint/tsconfig-utils": "^8.40.0",
"@typescript-eslint/types": "^8.40.0",
"debug": "^4.3.4"
},
"engines": {
@@ -589,14 +589,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.39.0.tgz",
"integrity": "sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.40.0.tgz",
"integrity": "sha512-y9ObStCcdCiZKzwqsE8CcpyuVMwRouJbbSrNuThDpv16dFAj429IkM6LNb1dZ2m7hK5fHyzNcErZf7CEeKXR4w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.39.0",
"@typescript-eslint/visitor-keys": "8.39.0"
"@typescript-eslint/types": "8.40.0",
"@typescript-eslint/visitor-keys": "8.40.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -607,9 +607,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.0.tgz",
"integrity": "sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.40.0.tgz",
"integrity": "sha512-jtMytmUaG9d/9kqSl/W3E3xaWESo4hFDxAIHGVW/WKKtQhesnRIJSAJO6XckluuJ6KDB5woD1EiqknriCtAmcw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -624,15 +624,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.39.0.tgz",
"integrity": "sha512-6B3z0c1DXVT2vYA9+z9axjtc09rqKUPRmijD5m9iv8iQpHBRYRMBcgxSiKTZKm6FwWw1/cI4v6em35OsKCiN5Q==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.40.0.tgz",
"integrity": "sha512-eE60cK4KzAc6ZrzlJnflXdrMqOBaugeukWICO2rB0KNvwdIMaEaYiywwHMzA1qFpTxrLhN9Lp4E/00EgWcD3Ow==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.39.0",
"@typescript-eslint/typescript-estree": "8.39.0",
"@typescript-eslint/utils": "8.39.0",
"@typescript-eslint/types": "8.40.0",
"@typescript-eslint/typescript-estree": "8.40.0",
"@typescript-eslint/utils": "8.40.0",
"debug": "^4.3.4",
"ts-api-utils": "^2.1.0"
},
@@ -649,9 +649,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.0.tgz",
"integrity": "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.40.0.tgz",
"integrity": "sha512-ETdbFlgbAmXHyFPwqUIYrfc12ArvpBhEVgGAxVYSwli26dn8Ko+lIo4Su9vI9ykTZdJn+vJprs/0eZU0YMAEQg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -663,16 +663,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.0.tgz",
"integrity": "sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.40.0.tgz",
"integrity": "sha512-k1z9+GJReVVOkc1WfVKs1vBrR5MIKKbdAjDTPvIK3L8De6KbFfPFt6BKpdkdk7rZS2GtC/m6yI5MYX+UsuvVYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/project-service": "8.39.0",
"@typescript-eslint/tsconfig-utils": "8.39.0",
"@typescript-eslint/types": "8.39.0",
"@typescript-eslint/visitor-keys": "8.39.0",
"@typescript-eslint/project-service": "8.40.0",
"@typescript-eslint/tsconfig-utils": "8.40.0",
"@typescript-eslint/types": "8.40.0",
"@typescript-eslint/visitor-keys": "8.40.0",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
@@ -731,16 +731,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.39.0.tgz",
"integrity": "sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.40.0.tgz",
"integrity": "sha512-Cgzi2MXSZyAUOY+BFwGs17s7ad/7L+gKt6Y8rAVVWS+7o6wrjeFN4nVfTpbE25MNcxyJ+iYUXflbs2xR9h4UBg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/scope-manager": "8.39.0",
"@typescript-eslint/types": "8.39.0",
"@typescript-eslint/typescript-estree": "8.39.0"
"@typescript-eslint/scope-manager": "8.40.0",
"@typescript-eslint/types": "8.40.0",
"@typescript-eslint/typescript-estree": "8.40.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -755,13 +755,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.0.tgz",
"integrity": "sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.40.0.tgz",
"integrity": "sha512-8CZ47QwalyRjsypfwnbI3hKy5gJDPmrkLjkgMxhi0+DZZ2QNx2naS6/hWoVYUHU7LU2zleF68V9miaVZvhFfTA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.39.0",
"@typescript-eslint/types": "8.40.0",
"eslint-visitor-keys": "^4.2.1"
},
"engines": {
@@ -4709,16 +4709,16 @@
}
},
"node_modules/typescript-eslint": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.39.0.tgz",
"integrity": "sha512-lH8FvtdtzcHJCkMOKnN73LIn6SLTpoojgJqDAxPm1jCR14eWSGPX8ul/gggBdPMk/d5+u9V854vTYQ8T5jF/1Q==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.40.0.tgz",
"integrity": "sha512-Xvd2l+ZmFDPEt4oj1QEXzA4A2uUK6opvKu3eGN9aGjB8au02lIVcLyi375w94hHyejTOmzIU77L8ol2sRg9n7Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.39.0",
"@typescript-eslint/parser": "8.39.0",
"@typescript-eslint/typescript-estree": "8.39.0",
"@typescript-eslint/utils": "8.39.0"
"@typescript-eslint/eslint-plugin": "8.40.0",
"@typescript-eslint/parser": "8.40.0",
"@typescript-eslint/typescript-estree": "8.40.0",
"@typescript-eslint/utils": "8.40.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"

View File

@@ -385,9 +385,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.2.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.1.tgz",
"integrity": "sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==",
"version": "24.3.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz",
"integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==",
"dev": true,
"license": "MIT",
"dependencies": {

View File

@@ -17,7 +17,7 @@ COPY web .
RUN npm run build-proxy
# Stage 2: Build
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS builder
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.25-bookworm AS builder
ARG TARGETOS
ARG TARGETARCH

View File

@@ -1,12 +1,12 @@
[project]
name = "authentik"
version = "2025.8.0"
version = "2025.10.0-rc1"
description = ""
authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
requires-python = "==3.13.*"
dependencies = [
"argon2-cffi==25.1.0",
"channels==4.3.0",
"channels==4.3.1",
"channels-redis==4.3.0",
"cryptography==45.0.5",
"dacite==1.9.2",
@@ -79,7 +79,7 @@ dev = [
"aws-cdk-lib==2.188.0",
"bandit==1.8.3",
"black==25.1.0",
"channels[daphne]==4.3.0",
"channels[daphne]==4.3.1",
"codespell==2.4.1",
"colorama==0.4.6",
"constructs==10.4.2",

View File

@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
# Stage 1: Build
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS builder
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.25-bookworm AS builder
ARG TARGETOS
ARG TARGETARCH

View File

@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
# Stage 1: Build
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS builder
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.25-bookworm AS builder
ARG TARGETOS
ARG TARGETARCH

View File

@@ -1,7 +1,7 @@
openapi: 3.0.3
info:
title: authentik
version: 2025.8.0
version: 2025.10.0-rc1
description: Making authentication simple.
contact:
email: hello@goauthentik.io

View File

@@ -1,13 +1,13 @@
services:
chrome:
platform: linux/x86_64
image: docker.io/selenium/standalone-chrome:138.0
image: docker.io/selenium/standalone-chrome:139.0
volumes:
- /dev/shm:/dev/shm
network_mode: host
restart: always
mailpit:
image: docker.io/axllent/mailpit:v1.27.4
image: docker.io/axllent/mailpit:v1.27.6
ports:
- 1025:1025
- 8025:8025

View File

@@ -10,6 +10,7 @@ from docker.types.healthcheck import Healthcheck
from authentik.core.tests.utils import create_test_flow
from authentik.crypto.models import CertificateKeyPair
from authentik.lib.config import CONFIG
from authentik.outposts.models import (
DockerServiceConnection,
Outpost,
@@ -88,6 +89,7 @@ class TestProxyDocker(DockerTestCase, ChannelsLiveServerTestCase):
pass
@pytest.mark.timeout(120)
@CONFIG.patch("outposts.container_image_base", "ghcr.io/goauthentik/dev-proxy:gh-main")
def test_docker_controller(self):
"""test that deployment requires update"""
controller = DockerController(self.outpost, self.service_connection)

20
uv.lock generated
View File

@@ -1,5 +1,5 @@
version = 1
revision = 3
revision = 2
requires-python = "==3.13.*"
[manifest]
@@ -159,7 +159,7 @@ wheels = [
[[package]]
name = "authentik"
version = "2025.8.0"
version = "2025.10.0rc1"
source = { editable = "." }
dependencies = [
{ name = "argon2-cffi" },
@@ -260,7 +260,7 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "argon2-cffi", specifier = "==25.1.0" },
{ name = "channels", specifier = "==4.3.0" },
{ name = "channels", specifier = "==4.3.1" },
{ name = "channels-redis", specifier = "==4.3.0" },
{ name = "cryptography", specifier = "==45.0.5" },
{ name = "dacite", specifier = "==1.9.2" },
@@ -333,7 +333,7 @@ dev = [
{ name = "aws-cdk-lib", specifier = "==2.188.0" },
{ name = "bandit", specifier = "==1.8.3" },
{ name = "black", specifier = "==25.1.0" },
{ name = "channels", extras = ["daphne"], specifier = "==4.3.0" },
{ name = "channels", extras = ["daphne"], specifier = "==4.3.1" },
{ name = "codespell", specifier = "==2.4.1" },
{ name = "colorama", specifier = "==0.4.6" },
{ name = "constructs", specifier = "==10.4.2" },
@@ -652,15 +652,15 @@ wheels = [
[[package]]
name = "channels"
version = "4.3.0"
version = "4.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "asgiref" },
{ name = "django" },
]
sdist = { url = "https://files.pythonhosted.org/packages/72/04/6768c7a887f9c593c4d49f99130c8aec4ea06e750bc17c306b689f6caf3b/channels-4.3.0.tar.gz", hash = "sha256:7db32c61dcd88eada1647e6c6f6ad2eb724b75d4852eeff26ad1c51ccd1a37f7", size = 26816, upload-time = "2025-07-28T13:52:50.334Z" }
sdist = { url = "https://files.pythonhosted.org/packages/12/a0/46450fcf9e56af18a6b0440ba49db6635419bb7bc84142c35f4143b1a66c/channels-4.3.1.tar.gz", hash = "sha256:97413ffd674542db08e16a9ef09cd86ec0113e5f8125fbd33cf0854adcf27cdb", size = 26896, upload-time = "2025-08-01T13:25:19.952Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/7c/59/0866202ee593e1b0dab0b472ebb8169e1b2b7886ad3008d193da2bbe10cb/channels-4.3.0-py3-none-any.whl", hash = "sha256:0497f3affb95e621b37d6bae1b6a5d9e8e1e1221007a2566f280091cf30ffcce", size = 31238, upload-time = "2025-07-28T13:52:49.117Z" },
{ url = "https://files.pythonhosted.org/packages/89/1c/eae1c2a8c195760376e7f65d0bdcc3e966695d29cfbe5c54841ce5c71408/channels-4.3.1-py3-none-any.whl", hash = "sha256:b091d4b26f91d807de3e84aead7ba785314f27eaf5bac31dd51b1c956b883859", size = 31286, upload-time = "2025-08-01T13:25:18.845Z" },
]
[package.optional-dependencies]
@@ -2736,11 +2736,11 @@ wheels = [
[[package]]
name = "redis"
version = "6.2.0"
version = "6.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ea/9a/0551e01ba52b944f97480721656578c8a7c46b51b99d66814f85fe3a4f3e/redis-6.2.0.tar.gz", hash = "sha256:e821f129b75dde6cb99dd35e5c76e8c49512a5a0d8dfdc560b2fbd44b85ca977", size = 4639129, upload-time = "2025-05-28T05:01:18.91Z" }
sdist = { url = "https://files.pythonhosted.org/packages/21/cd/030274634a1a052b708756016283ea3d84e91ae45f74d7f5dcf55d753a0f/redis-6.3.0.tar.gz", hash = "sha256:3000dbe532babfb0999cdab7b3e5744bcb23e51923febcfaeb52c8cfb29632ef", size = 4647275, upload-time = "2025-08-05T08:12:31.648Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/13/67/e60968d3b0e077495a8fee89cf3f2373db98e528288a48f1ee44967f6e8c/redis-6.2.0-py3-none-any.whl", hash = "sha256:c8ddf316ee0aab65f04a11229e94a64b2618451dab7a67cb2f77eb799d872d5e", size = 278659, upload-time = "2025-05-28T05:01:16.955Z" },
{ url = "https://files.pythonhosted.org/packages/df/a7/2fe45801534a187543fc45d28b3844d84559c1589255bc2ece30d92dc205/redis-6.3.0-py3-none-any.whl", hash = "sha256:92f079d656ded871535e099080f70fab8e75273c0236797126ac60242d638e9b", size = 280018, upload-time = "2025-08-05T08:12:30.093Z" },
]
[[package]]

1309
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@goauthentik/web",
"version": "2025.8.0",
"version": "2025.10.0-rc1",
"license": "MIT",
"private": true,
"scripts": {
@@ -111,20 +111,20 @@
"@open-wc/lit-helpers": "^0.7.0",
"@openlayers-elements/core": "^0.4.0",
"@openlayers-elements/maps": "^0.4.0",
"@patternfly/elements": "^4.1.0",
"@patternfly/elements": "^4.2.0",
"@patternfly/patternfly": "^4.224.2",
"@sentry/browser": "^10.3.0",
"@sentry/browser": "^10.5.0",
"@spotlightjs/spotlight": "^3.0.2",
"@storybook/addon-docs": "^9.1.1",
"@storybook/addon-links": "^9.1.1",
"@storybook/web-components": "^9.1.1",
"@storybook/web-components-vite": "^9.1.1",
"@storybook/addon-docs": "^9.1.2",
"@storybook/addon-links": "^9.1.2",
"@storybook/web-components": "^9.1.2",
"@storybook/web-components-vite": "^9.1.2",
"@types/codemirror": "^5.60.16",
"@types/grecaptcha": "^3.0.9",
"@types/guacamole-common-js": "^1.5.3",
"@types/guacamole-common-js": "^1.5.4",
"@types/mocha": "^10.0.10",
"@types/node": "^24.2.1",
"@types/react": "^19.1.8",
"@types/node": "^24.3.0",
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"@typescript-eslint/eslint-plugin": "^8.38.0",
"@typescript-eslint/parser": "^8.38.0",
@@ -135,12 +135,12 @@
"chartjs-adapter-date-fns": "^3.0.0",
"codemirror": "^6.0.2",
"construct-style-sheets-polyfill": "^3.1.0",
"core-js": "^3.44.0",
"core-js": "^3.45.1",
"country-flag-icons": "^1.5.19",
"date-fns": "^4.1.0",
"deepmerge-ts": "^7.1.5",
"dompurify": "^3.2.6",
"esbuild": "^0.25.8",
"esbuild": "^0.25.9",
"esbuild-plugin-copy": "^2.1.1",
"esbuild-plugin-polyfill-node": "^0.3.0",
"esbuild-plugins-node-modules-polyfill": "^1.7.1",
@@ -156,7 +156,7 @@
"lit": "^3.3.1",
"lit-analyzer": "^2.0.3",
"md-front-matter": "^1.0.4",
"mermaid": "^11.9.0",
"mermaid": "^11.10.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.6.2",
"pseudolocale": "^2.1.0",
@@ -177,7 +177,7 @@
"ts-pattern": "^5.8.0",
"turnstile-types": "^1.2.3",
"typescript": "^5.8.3",
"typescript-eslint": "^8.39.0",
"typescript-eslint": "^8.40.0",
"unist-util-visit": "^5.0.0",
"webcomponent-qr-code": "^1.3.0",
"wireit": "^0.14.12",
@@ -187,14 +187,14 @@
"@esbuild/darwin-arm64": "^0.25.4",
"@esbuild/linux-arm64": "^0.25.4",
"@esbuild/linux-x64": "^0.25.4",
"@rollup/rollup-darwin-arm64": "^4.46.2",
"@rollup/rollup-linux-arm64-gnu": "^4.46.2",
"@rollup/rollup-linux-x64-gnu": "^4.46.2",
"@wdio/browser-runner": "^9.19.0",
"@wdio/cli": "^9.19.0",
"@wdio/spec-reporter": "^9.19.0",
"@rollup/rollup-darwin-arm64": "^4.46.3",
"@rollup/rollup-linux-arm64-gnu": "^4.46.3",
"@rollup/rollup-linux-x64-gnu": "^4.46.3",
"@wdio/browser-runner": "^9.19.1",
"@wdio/cli": "^9.19.1",
"@wdio/spec-reporter": "^9.19.1",
"@web/test-runner": "^0.20.2",
"chromedriver": "^139.0.0"
"chromedriver": "^139.0.1"
},
"wireit": {
"build": {

View File

@@ -47,7 +47,7 @@
"dependencies": {
"@goauthentik/prettier-config": "^3.1.0",
"@goauthentik/tsconfig": "^1.0.4",
"@types/node": "^24.2.1",
"@types/node": "^24.3.0",
"prettier": "^3.6.2",
"typescript": "^5.8.3"
},

View File

@@ -10,7 +10,7 @@
"watch": "rollup -w -c rollup.config.mjs --bundleConfigAsCjs"
},
"dependencies": {
"@goauthentik/api": "^2024.6.0-1719577139",
"@goauthentik/api": "^2025.10.0-rc1-1755254677",
"@goauthentik/core": "^1.0.0",
"@rollup/plugin-commonjs": "^28.0.6",
"@rollup/plugin-node-resolve": "^16.0.1",
@@ -23,7 +23,7 @@
"formdata-polyfill": "^4.0.10",
"jquery": "^3.7.1",
"prettier": "^3.5.3",
"rollup": "^4.46.2",
"rollup": "^4.46.3",
"rollup-plugin-copy": "^3.5.0",
"weakmap-polyfill": "^2.0.4"
},

View File

@@ -48,6 +48,11 @@ const BASE_ESBUILD_OPTIONS = {
plugins: [
copy({
assets: [
{
from: path.join(path.dirname(EntryPoint.StandaloneLoading.in), "startup", "**"),
to: path.dirname(EntryPoint.StandaloneLoading.out),
},
{
from: path.join(patternflyPath, "patternfly.min.css"),
to: ".",

View File

@@ -66,7 +66,7 @@ export class AdminOverviewPage extends AdminOverviewBase {
quickActions: QuickAction[] = [
[msg("Create a new application"), paramURL("/core/applications", { createWizard: true })],
[msg("Check the logs"), paramURL("/events/log")],
[msg("Explore integrations"), "https://goauthentik.io/integrations/", true],
[msg("Explore integrations"), "https://integrations.goauthentik.io/", true],
[msg("Manage users"), paramURL("/identity/users")],
[
msg("Check the release notes"),

View File

@@ -33,23 +33,7 @@ const DEFAULT_REPUTATION_UPPER_LIMIT = 5;
@customElement("ak-admin-settings-form")
export class AdminSettingsForm extends Form<SettingsRequest> {
//
// Custom property accessors in Lit 2 require a manual call to requestUpdate(). See:
// https://lit.dev/docs/v2/components/properties/#accessors-custom
//
set settings(value: Settings | undefined) {
this._settings = value;
this.requestUpdate();
}
@property({ type: Object })
get settings() {
return this._settings;
}
private _settings?: Settings;
static styles: CSSResult[] = [
public static styles: CSSResult[] = [
...super.styles,
PFList,
css`
@@ -59,25 +43,33 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
`,
];
@property({ attribute: false })
public settings!: Settings;
getSuccessMessage(): string {
return msg("Successfully updated settings.");
}
async send(data: SettingsRequest): Promise<Settings> {
async send(settingsRequest: SettingsRequest): Promise<Settings> {
const result = await new AdminApi(DEFAULT_CONFIG).adminSettingsUpdate({
settingsRequest: data,
settingsRequest,
});
this.dispatchEvent(new CustomEvent("ak-admin-setting-changed"));
return result;
}
renderForm(): TemplateResult {
const { settings } = this;
return html`
<ak-text-input
name="avatars"
label=${msg("Avatars")}
value="${ifDefined(this._settings?.avatars)}"
value="${ifDefined(settings.avatars)}"
input-hint="code"
required
.bighelp=${html`
<p class="pf-c-form__helper-text">
${msg(
@@ -137,27 +129,26 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
)}
</p>
`}
required
>
</ak-text-input>
<ak-switch-input
name="defaultUserChangeName"
label=${msg("Allow users to change name")}
?checked="${this._settings?.defaultUserChangeName}"
?checked=${settings.defaultUserChangeName}
help=${msg("Enable the ability for users to change their name.")}
>
</ak-switch-input>
<ak-switch-input
name="defaultUserChangeEmail"
label=${msg("Allow users to change email")}
?checked="${this._settings?.defaultUserChangeEmail}"
?checked=${settings.defaultUserChangeEmail}
help=${msg("Enable the ability for users to change their email.")}
>
</ak-switch-input>
<ak-switch-input
name="defaultUserChangeUsername"
label=${msg("Allow users to change username")}
?checked="${this._settings?.defaultUserChangeUsername}"
?checked=${settings.defaultUserChangeUsername}
help=${msg("Enable the ability for users to change their username.")}
>
</ak-switch-input>
@@ -166,7 +157,7 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
label=${msg("Event retention")}
input-hint="code"
required
value="${ifDefined(this._settings?.eventRetention)}"
value="${ifDefined(settings.eventRetention)}"
.bighelp=${html`<p class="pf-c-form__helper-text">
${msg("Duration after which events will be deleted from the database.")}
</p>
@@ -188,19 +179,19 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
label=${msg("Reputation: lower limit")}
required
name="reputationLowerLimit"
value="${this._settings?.reputationLowerLimit ?? DEFAULT_REPUTATION_LOWER_LIMIT}"
value="${settings.reputationLowerLimit ?? DEFAULT_REPUTATION_LOWER_LIMIT}"
help=${msg("Reputation cannot decrease lower than this value. Zero or negative.")}
></ak-number-input>
<ak-number-input
label=${msg("Reputation: upper limit")}
required
name="reputationUpperLimit"
value="${this._settings?.reputationUpperLimit ?? DEFAULT_REPUTATION_UPPER_LIMIT}"
value="${settings.reputationUpperLimit ?? DEFAULT_REPUTATION_UPPER_LIMIT}"
help=${msg("Reputation cannot increase higher than this value. Zero or positive.")}
></ak-number-input>
<ak-form-element-horizontal label=${msg("Footer links")} name="footerLinks">
<ak-array-input
.items=${this._settings?.footerLinks ?? []}
.items=${settings.footerLinks ?? []}
.newItem=${() => ({ name: "", href: "" })}
.row=${(f?: FooterLink) =>
akFooterLinkInput({
@@ -219,7 +210,7 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
<ak-switch-input
name="gdprCompliance"
label=${msg("GDPR compliance")}
?checked="${this._settings?.gdprCompliance}"
?checked=${settings.gdprCompliance}
help=${msg(
"When enabled, all the events caused by a user will be deleted upon the user's deletion.",
)}
@@ -228,14 +219,14 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
<ak-switch-input
name="impersonation"
label=${msg("Impersonation")}
?checked="${this._settings?.impersonation}"
?checked=${settings.impersonation}
help=${msg("Globally enable/disable impersonation.")}
>
</ak-switch-input>
<ak-switch-input
name="impersonationRequireReason"
label=${msg("Require reason for impersonation")}
?checked="${this._settings?.impersonationRequireReason}"
?checked=${settings.impersonationRequireReason}
help=${msg("Require administrators to provide a reason for impersonating a user.")}
>
</ak-switch-input>
@@ -244,7 +235,7 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
label=${msg("Default token duration")}
input-hint="code"
required
value="${ifDefined(this._settings?.defaultTokenDuration)}"
value="${ifDefined(settings.defaultTokenDuration)}"
.bighelp=${html`<p class="pf-c-form__helper-text">
${msg("Default duration for generated tokens")}
</p>
@@ -255,13 +246,13 @@ export class AdminSettingsForm extends Form<SettingsRequest> {
label=${msg("Default token length")}
required
name="defaultTokenLength"
value="${this._settings?.defaultTokenLength ?? 60}"
value="${settings.defaultTokenLength ?? 60}"
help=${msg("Default length of generated tokens")}
></ak-number-input>
<ak-form-element-horizontal label=${msg("Flags")} name="flags" required>
<ak-codemirror
mode=${CodeMirrorMode.YAML}
value="${YAML.stringify(this._settings?.flags ?? {})}"
value="${YAML.stringify(settings?.flags ?? {})}"
>
</ak-codemirror>
<p class="pf-c-form__helper-text">

View File

@@ -5,6 +5,10 @@ import { groupBy } from "#common/utils";
import { AKElement } from "#elements/Base";
import { AKLabel } from "#components/ak-label";
import { IDGenerator } from "#packages/core/id";
import { Provider, ProvidersAllListRequest, ProvidersApi } from "@goauthentik/api";
import { html, nothing } from "lit";
@@ -38,11 +42,13 @@ export class AkProviderInput extends AKElement {
return this;
}
//#region Properties
@property({ type: String })
name!: string;
@property({ type: String })
label = "";
label?: string;
@property({ type: Number })
value?: number;
@@ -60,14 +66,26 @@ export class AkProviderInput extends AKElement {
super();
this.selected = this.selected.bind(this);
}
/**
* A unique ID to associate with the input and label.
* @property
*/
@property({ type: String, reflect: false })
public fieldID?: string = IDGenerator.elementID().toString();
selected(item: Provider) {
return this.value !== undefined && this.value === item.pk;
}
//#endregion
render() {
return html` <ak-form-element-horizontal label=${this.label} name=${this.name}>
return html` <ak-form-element-horizontal name=${this.name}>
<div slot="label" class="pf-c-form__group-label">
${AKLabel({ htmlFor: this.fieldID, required: this.required }, this.label)}
</div>
<ak-search-select
.fieldID=${this.fieldID}
.selected=${this.selected}
.fetchObjects=${fetch}
.renderElement=${renderElement}

View File

@@ -44,6 +44,7 @@ export class BrandForm extends ModelForm<Brand, string> {
}
async send(data: Brand): Promise<Brand> {
data.attributes ??= {};
if (this.instance?.brandUuid) {
return new CoreApi(DEFAULT_CONFIG).coreBrandsUpdate({
brandUuid: this.instance.brandUuid,

View File

@@ -53,15 +53,15 @@ export class CertificateKeyPairForm extends ModelForm<CertificateKeyPair, string
name="certificateData"
input-hint="code"
placeholder="-----BEGIN CERTIFICATE-----"
required
?revealed=${this.instance === undefined}
?required=${!this.instance}
?revealed=${!this.instance}
help=${msg("PEM-encoded Certificate data.")}
></ak-secret-textarea-input>
<ak-secret-textarea-input
label=${msg("Private Key")}
name="keyData"
input-hint="code"
?revealed=${this.instance === undefined}
?revealed=${!this.instance}
help=${msg(
"Optional Private Key. If this is set, you can use this keypair for encryption.",
)}

View File

@@ -66,7 +66,7 @@ export class EnterpriseLicenseForm extends ModelForm<License, string> {
</ak-form-element-horizontal>
<ak-secret-textarea-input
name="key"
?revealed=${this.instance === undefined}
?revealed=${!this.instance}
label=${msg("License key")}
input-hint="code"
>

View File

@@ -53,6 +53,7 @@ export class GroupForm extends ModelForm<Group, string> {
}
async send(data: Group): Promise<Group> {
data.attributes ??= {};
if (this.instance?.pk) {
return new CoreApi(DEFAULT_CONFIG).coreGroupsPartialUpdate({
groupUuid: this.instance.pk,
@@ -145,7 +146,7 @@ export class GroupForm extends ModelForm<Group, string> {
)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("Attributes")} required name="attributes">
<ak-form-element-horizontal label=${msg("Attributes")} name="attributes">
<ak-codemirror
mode=${CodeMirrorMode.YAML}
value="${YAML.stringify(this.instance?.attributes ?? {})}"

View File

@@ -1,4 +1,8 @@
import { APIError } from "#common/errors/network";
import { MessageLevel } from "#common/messages";
import { ModelForm } from "#elements/forms/ModelForm";
import { APIMessage } from "#elements/messages/Message";
import { msg } from "@lit/localize";
@@ -8,4 +12,14 @@ export abstract class BaseProviderForm<T> extends ModelForm<T, number> {
? msg("Successfully updated provider.")
: msg("Successfully created provider.");
}
protected override formatAPIErrorMessage(error: APIError): APIMessage {
return {
level: MessageLevel.error,
...super.formatAPIErrorMessage(error),
message: this.instance
? msg("An error occurred while updating the provider.")
: msg("An error occurred while creating the provider."),
};
}
}

View File

@@ -195,7 +195,7 @@ export function renderForm(
.redirectURI=${redirectURI}
name="oauth2-redirect-uri"
style="width: 100%"
inputID="redirect-uri-${idx}"
input-id="redirect-uri-${idx}"
></ak-provider-oauth2-redirect-uri>`;
}}
>

View File

@@ -71,10 +71,10 @@ export class SAMLProviderViewPage extends AKElement {
metadata?: SAMLMetadata;
@state()
signer?: CertificateKeyPair;
signer: CertificateKeyPair | null = null;
@state()
verifier?: CertificateKeyPair;
verifier: CertificateKeyPair | null = null;
@state()
previewUser?: User;
@@ -97,7 +97,7 @@ export class SAMLProviderViewPage extends AKElement {
super();
this.addEventListener(EVENT_REFRESH, () => {
if (!this.provider?.pk) return;
this.providerID = this.provider?.pk;
this.fetchProvider(this.provider.pk);
});
}
@@ -117,20 +117,32 @@ export class SAMLProviderViewPage extends AKElement {
}
fetchSigningCertificate(kpUuid: string) {
this.fetchCertificate(kpUuid).then((kp) => (this.signer = kp));
this.fetchCertificate(kpUuid).then((kp) => {
this.signer = kp;
this.requestUpdate("signer");
});
}
fetchVerificationCertificate(kpUuid: string) {
this.fetchCertificate(kpUuid).then((kp) => (this.verifier = kp));
this.fetchCertificate(kpUuid).then((kp) => {
this.verifier = kp;
this.requestUpdate("verifier");
});
}
fetchProvider(id: number) {
new ProvidersApi(DEFAULT_CONFIG).providersSamlRetrieve({ id }).then((prov) => {
this.provider = prov;
if (this.provider.signingKp) {
// Clear existing signing certificate if the provider has none
if (!this.provider.signingKp) {
this.signer = null;
} else {
this.fetchSigningCertificate(this.provider.signingKp);
}
if (this.provider.verificationKp) {
// Clear existing verification certificate if the provider has none
if (!this.provider.verificationKp) {
this.verifier = null;
} else {
this.fetchVerificationCertificate(this.provider.verificationKp);
}
});

View File

@@ -259,7 +259,7 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
<ak-secret-textarea-input
name="syncKeytab"
label=${msg("Sync keytab")}
?revealed=${this.instance === undefined}
?revealed=${!this.instance}
help=${msg(
"Keytab used to authenticate to the KDC for syncing. Optional if Sync password or Sync credentials cache is provided. Must be base64 encoded or in the form TYPE:residual.",
)}
@@ -287,7 +287,7 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
<ak-secret-textarea-input
name="spnegoKeytab"
label=${msg("SPNEGO keytab")}
?revealed=${this.instance === undefined}
?revealed=${!this.instance}
help=${msg(
"Keytab used for SPNEGO. Optional if SPNEGO credentials cache is provided. Must be base64 encoded or in the form TYPE:residual.",
)}

View File

@@ -442,8 +442,8 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
name="consumerSecret"
input-hint="code"
help=${msg("Also known as Client Secret.")}
required
?revealed=${this.instance === undefined}
?required=${!this.instance}
?revealed=${!this.instance}
></ak-secret-textarea-input>
<ak-form-element-horizontal label=${msg("Scopes")} name="additionalScopes">
<input
@@ -530,9 +530,8 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
</ak-form-element-horizontal>
</div>
</ak-form-group>
<ak-form-group>
<span slot="header"> ${msg("Advanced settings")} </span>
<div slot="body" class="pf-c-form">
<ak-form-group label=${msg("Advanced settings")}>
<div class="pf-c-form">
<ak-form-element-horizontal
label=${msg("Policy engine mode")}
required

View File

@@ -414,9 +414,8 @@ export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSo
</ak-form-element-horizontal>
</div>
</ak-form-group>
<ak-form-group>
<span slot="header"> ${msg("Advanced settings")} </span>
<div slot="body" class="pf-c-form">
<ak-form-group label=${msg("Advanced settings")}>
<div class="pf-c-form">
<ak-form-element-horizontal
label=${msg("Policy engine mode")}
required

View File

@@ -574,9 +574,8 @@ export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSo
</ak-form-element-horizontal>
</div>
</ak-form-group>
<ak-form-group>
<span slot="header"> ${msg("Advanced settings")} </span>
<div slot="body" class="pf-c-form">
<ak-form-group label=${msg("Advanced settings")}>
<div class="pf-c-form">
<ak-form-element-horizontal
label=${msg("Policy engine mode")}
required

View File

@@ -180,11 +180,7 @@ export class UserForm extends ModelForm<User, number> {
required
/>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Attributes")}
?required=${false}
name="attributes"
>
<ak-form-element-horizontal label=${msg("Attributes")} name="attributes">
<ak-codemirror
mode=${CodeMirrorMode.YAML}
value="${YAML.stringify(

View File

@@ -1,20 +1,29 @@
import "#components/ak-text-input";
import { DEFAULT_CONFIG } from "#common/api/config";
import { globalAK } from "#common/global";
import { MessageLevel } from "#common/messages";
import { Form } from "#elements/forms/Form";
import { APIMessage } from "#elements/messages/Message";
import { CoreApi, ImpersonationRequest } from "@goauthentik/api";
import { msg } from "@lit/localize";
import { msg, str } from "@lit/localize";
import { html, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
@customElement("ak-user-impersonate-form")
export class UserImpersonateForm extends Form<ImpersonationRequest> {
@property({ type: Number })
instancePk?: number;
public instancePk?: number;
protected override formatAPISuccessMessage(): APIMessage | null {
return {
level: MessageLevel.success,
message: msg(str`Impersonating user...`),
description: msg("This may take a few seconds."),
};
}
async send(data: ImpersonationRequest): Promise<void> {
return new CoreApi(DEFAULT_CONFIG)
@@ -23,7 +32,7 @@ export class UserImpersonateForm extends Form<ImpersonationRequest> {
impersonationRequest: data,
})
.then(() => {
window.location.href = globalAK().api.base;
window.location.reload();
});
}
@@ -31,7 +40,12 @@ export class UserImpersonateForm extends Form<ImpersonationRequest> {
return html`<ak-text-input
name="reason"
label=${msg("Reason")}
help=${msg("Reason for impersonating the user")}
autocomplete="off"
placeholder=${msg("Reason for impersonating the user")}
help=${msg(
"A brief explanation of why you are impersonating the user. This will be included in audit logs.",
)}
required
></ak-text-input>`;
}
}

View File

@@ -6,6 +6,8 @@ import {
ValidationErrorFromJSON,
} from "@goauthentik/api";
import { sentenceCase } from "change-case";
//#region HTTP
/**
@@ -233,3 +235,25 @@ export async function parseAPIResponseError<T extends APIError = APIError>(
}
//#endregion
//#region Validation errors
/**
* Pluck a field error from a validation error.
*
* This is used to create a fallback error message when the API returns
* a validation error that isn't associated with field within the form.
*
* We can still show the error message, to at least give the user some feedback.
*/
export function pluckFallbackFieldErrors(parsedError: APIError): string[] {
for (const [fieldName, fieldErrors] of Object.entries(parsedError)) {
if (Array.isArray(fieldErrors)) {
return [`${sentenceCase(fieldName)}: ${fieldErrors.join(", ")}`];
}
}
return [];
}
//#endregion

View File

@@ -121,7 +121,9 @@ export function renderStaticHTMLUnsafe(untrustedHTML: unknown): string {
render(untrustedHTML, container);
const result = container.innerHTML;
const result = container.innerHTML
// Remove all comments as they can interfere with the styles.
.replaceAll("<!---->", "")
.replaceAll(/<!--\?lit\$\d+\$-->/g, "");
return result;
}

View File

@@ -5,12 +5,12 @@ import { SlottedTemplateResult } from "../elements/types";
import { AKElement, type AKElementProps } from "#elements/Base";
import { ErrorProp } from "#components/ak-field-errors";
import { AKLabel } from "#components/ak-label";
import { IDGenerator } from "@goauthentik/core/id";
import { html, nothing, TemplateResult } from "lit";
import { property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
export interface HorizontalLightComponentProps<T> extends AKElementProps {
name: string;
@@ -40,6 +40,8 @@ export abstract class HorizontalLightComponent<T>
return this;
}
//#region Properties
/**
* The name attribute for the form element
* @property
@@ -61,7 +63,7 @@ export abstract class HorizontalLightComponent<T>
* @attribute
*/
@property({ type: Boolean, reflect: true })
required = false;
public required?: boolean;
/**
* Help text to display below the form element. Optional
@@ -96,10 +98,9 @@ export abstract class HorizontalLightComponent<T>
* @property
*/
@property({ attribute: false })
errorMessages: string[] = [];
public errorMessages?: ErrorProp[];
/**
* @attribute
* @property
*/
@property({ attribute: false })
@@ -114,11 +115,21 @@ export abstract class HorizontalLightComponent<T>
@property({ type: String, attribute: "input-hint" })
inputHint?: string;
protected renderControl() {
throw new Error("Must be implemented in a subclass");
}
/**
* A unique ID to associate with the input and label.
* @property
*/
@property({ type: String, reflect: false })
public fieldID?: string = IDGenerator.elementID().toString();
protected fieldID = IDGenerator.elementID().toString();
//#endregion
//#region Rendering
/**
* Render the control element, e.g. an input, textarea, select, etc.
*/
protected abstract renderControl(): SlottedTemplateResult;
protected renderHelp(): SlottedTemplateResult | SlottedTemplateResult[] {
const bigHelp: SlottedTemplateResult[] = Array.isArray(this.bighelp)
@@ -133,14 +144,19 @@ export abstract class HorizontalLightComponent<T>
render() {
return html`<ak-form-element-horizontal
fieldID=${this.fieldID}
label=${ifDefined(this.label)}
.fieldID=${this.fieldID}
?required=${this.required}
?hidden=${this.hidden}
name=${this.name}
.errorMessages=${this.errorMessages}
>
<div slot="label" class="pf-c-form__group-label">
${AKLabel({ htmlFor: this.fieldID, required: this.required }, this.label)}
</div>
${this.renderControl()} ${this.renderHelp()}
</ak-form-element-horizontal> `;
}
//#endregion
}

View File

@@ -125,6 +125,7 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
public override renderControl() {
return html`<input
id=${ifDefined(this.fieldID)}
@input=${(ev: Event) => this.handleTouch(ev)}
type="text"
value=${ifDefined(this.value)}

View File

@@ -17,6 +17,7 @@ export class AkTextareaInput extends HorizontalLightComponent<string> {
// Prevent the leading spaces added by Prettier's whitespace algo
// prettier-ignore
return html`<textarea
id=${ifDefined(this.fieldID)}
@input=${setValue}
class="pf-c-form-control"
?required=${this.required}

View File

@@ -154,11 +154,17 @@ export class ListSelect extends AKElement implements IListSelect {
return elementCount === 0 ? -1 : checkIndex();
}
/**
* Highlight the currently focused item.
*
* @todo
* This doesn't quite work as intended, but this component will likely
* be refined after the PatternFly upgrade.
*/
private highlightFocusedItem() {
this.displayedElements.forEach((item) => {
item.classList.remove("ak-highlight-item");
item.removeAttribute("aria-selected");
item.tabIndex = -1;
});
const currentElement = this.currentElement;
if (!currentElement) {
@@ -168,7 +174,6 @@ export class ListSelect extends AKElement implements IListSelect {
// This is currently a radio emulation; "selected" is true here.
// If this were a checkbox emulation (i.e. multi), "checked" would be appropriate.
currentElement.setAttribute("aria-selected", "true");
currentElement.scrollIntoView({ block: "center", behavior: "smooth" });
}
@bound

View File

@@ -9,7 +9,7 @@ import { html } from "lit";
const ACTIONS: QuickAction[] = [
["Create a new application", "/core/applications"],
["Check the logs", "/events/log"],
["Explore integrations", "https://goauthentik.io/integrations/", true],
["Explore integrations", "https://integrations.goauthentik.io/", true],
["Manage users", "/identity/users"],
["Check the release notes", "https://goauthentik.io/docs/releases/", true],
];

View File

@@ -11,7 +11,7 @@ import { html } from "lit";
const ACTIONS: QuickAction[] = [
["Create a new application", "/core/applications"],
["Check the logs", "/events/log"],
["Explore integrations", "https://goauthentik.io/integrations/", true],
["Explore integrations", "https://integrations.goauthentik.io/", true],
["Manage users", "/identity/users"],
["Check the release notes", "https://goauthentik.io/docs/releases/", true],
];

View File

@@ -1,5 +1,10 @@
import { EVENT_REFRESH } from "#common/constants";
import { parseAPIResponseError, pluckErrorDetail } from "#common/errors/network";
import {
APIError,
parseAPIResponseError,
pluckErrorDetail,
pluckFallbackFieldErrors,
} from "#common/errors/network";
import { MessageLevel } from "#common/messages";
import { dateToUTC } from "#common/temporal";
@@ -8,13 +13,14 @@ import { AKElement } from "#elements/Base";
import { reportValidityDeep } from "#elements/forms/FormGroup";
import { PreventFormSubmit } from "#elements/forms/helpers";
import { HorizontalFormElement } from "#elements/forms/HorizontalFormElement";
import { APIMessage } from "#elements/messages/Message";
import { showMessage } from "#elements/messages/MessageContainer";
import { SlottedTemplateResult } from "#elements/types";
import { createFileMap, isNamedElement, NamedElement } from "#elements/utils/inputs";
import { ErrorProp } from "#components/ak-field-errors";
import { instanceOfValidationError } from "@goauthentik/api";
import { instanceOfValidationError, ValidationError } from "@goauthentik/api";
import { snakeCase } from "change-case";
@@ -143,6 +149,41 @@ export function serializeForm<T = Record<string, unknown>>(elements: Iterable<AK
return json as unknown as T;
}
//#region Validation Reporting
/**
* Assign all input-related errors to their respective elements.
*/
function reportInvalidFields(
parsedError: ValidationError,
elements: Iterable<HorizontalFormElement>,
): HorizontalFormElement[] {
const invalidFields: HorizontalFormElement[] = [];
for (const element of elements) {
element.requestUpdate();
const elementName = element.name;
if (!elementName) continue;
const snakeProperty = snakeCase(elementName);
const errorMessages: ErrorProp[] = parsedError[snakeProperty] ?? [];
element.errorMessages = errorMessages;
if (Array.isArray(errorMessages) && errorMessages.length) {
invalidFields.push(element);
}
}
return invalidFields;
}
//#endregion
//#region Form
/**
* Form
*
@@ -180,8 +221,8 @@ export abstract class Form<T = Record<string, unknown>> extends AKElement {
//#region Properties
@property()
public successMessage = "";
@property({ type: String })
public successMessage?: string;
@property({ type: String })
public autocomplete?: AutoFill;
@@ -226,11 +267,38 @@ export abstract class Form<T = Record<string, unknown>> extends AKElement {
/**
* An overridable method for returning a success message after a successful submission.
*
* @deprecated Use `formatAPISuccessMessage` instead.
*/
protected getSuccessMessage(): string {
protected getSuccessMessage(): string | undefined {
return this.successMessage;
}
/**
* An overridable method for returning a formatted message after a successful submission.
*/
protected formatAPISuccessMessage(response: unknown): APIMessage | null {
const message = this.getSuccessMessage();
if (!message) return null;
return {
level: MessageLevel.success,
message,
};
}
/**
* An overridable method for returning a formatted error message after a failed submission.
*/
protected formatAPIErrorMessage(error: APIError): APIMessage | null {
return {
message: msg("There was an error submitting the form."),
description: pluckErrorDetail(error, pluckFallbackFieldErrors(error)[0]),
level: MessageLevel.error,
};
}
//#region Public methods
public reset(): void {
@@ -246,6 +314,8 @@ export abstract class Form<T = Record<string, unknown>> extends AKElement {
return createFileMap<T>(this.shadowRoot?.querySelectorAll("ak-form-element-horizontal"));
}
//#region Validation
public checkValidity(): boolean {
return !!this.form?.checkValidity?.();
}
@@ -261,6 +331,10 @@ export abstract class Form<T = Record<string, unknown>> extends AKElement {
return reportValidityDeep(form);
}
//#endregion
//#region Submission
/**
* Convert the elements of the form to JSON.[4]
*/
@@ -273,6 +347,7 @@ export abstract class Form<T = Record<string, unknown>> extends AKElement {
return serializeForm<T>(elements);
}
/**
* Serialize and send the form to the destination. The `send()` method must be overridden for
* this to work. If processing the data results in an error, we catch the error, distribute
@@ -287,10 +362,7 @@ export abstract class Form<T = Record<string, unknown>> extends AKElement {
return this.send(data)
.then((response) => {
showMessage({
level: MessageLevel.success,
message: this.getSuccessMessage(),
});
showMessage(this.formatAPISuccessMessage(response));
this.dispatchEvent(
new CustomEvent(EVENT_REFRESH, {
@@ -307,60 +379,32 @@ export abstract class Form<T = Record<string, unknown>> extends AKElement {
}
const parsedError = await parseAPIResponseError(error);
let errorMessage = pluckErrorDetail(error);
let focused = false;
if (instanceOfValidationError(parsedError)) {
// assign all input-related errors to their elements
const elements =
this.shadowRoot?.querySelectorAll<HorizontalFormElement>(
"ak-form-element-horizontal",
) || [];
const invalidFields = reportInvalidFields(
parsedError,
this.renderRoot.querySelectorAll("ak-form-element-horizontal"),
);
for (const element of elements) {
element.requestUpdate();
const focusTarget = Iterator.from(invalidFields)
.map(({ focusTarget }) => focusTarget)
.find(Boolean);
const elementName = element.name;
if (!elementName) continue;
const snakeProperty = snakeCase(elementName);
const errorMessages: ErrorProp[] = parsedError[snakeProperty] ?? [];
element.errorMessages = errorMessages;
const { controlledElement } = element;
if (!focused && Array.isArray(errorMessages) && errorMessages.length) {
if (
controlledElement?.checkVisibility() &&
controlledElement instanceof HTMLElement
) {
focused = true;
requestAnimationFrame(() => {
return controlledElement.focus?.();
});
}
}
}
if (parsedError.nonFieldErrors) {
if (focusTarget) {
requestAnimationFrame(() => focusTarget.focus());
} else if (Array.isArray(parsedError.nonFieldErrors)) {
this.nonFieldErrors = parsedError.nonFieldErrors;
}
} else {
this.nonFieldErrors = pluckFallbackFieldErrors(parsedError);
errorMessage = msg("Invalid update request.");
// Only change the message when we have `detail`.
// Everything else is handled in the form.
if ("detail" in parsedError) {
errorMessage = parsedError.detail;
console.error(
"authentik/forms: API rejected the form submission due to an invalid field that doesn't appear to be in the form. This is likely a bug in authentik.",
parsedError,
);
}
}
showMessage({
message: errorMessage,
level: MessageLevel.error,
});
showMessage(this.formatAPIErrorMessage(parsedError), true);
// Rethrow the error so the form doesn't close.
throw error;
@@ -369,6 +413,8 @@ export abstract class Form<T = Record<string, unknown>> extends AKElement {
//#endregion
//#endregion
//#region Render
public renderFormWrapper(): TemplateResult {

View File

@@ -1,70 +0,0 @@
import { AKElement } from "#elements/Base";
import { ErrorDetail } from "@goauthentik/api";
import { CSSResult, html, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators.js";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
/**
* This is used in two places outside of Flow, and in both cases is used primarily to
* display content, not take input. It displays the TOTP QR code, and the static
* recovery tokens. But it's used a lot in Flow.
*/
@customElement("ak-form-element")
export class FormElement extends AKElement {
static styles: CSSResult[] = [PFBase, PFForm, PFFormControl];
@property()
label?: string;
@property({ type: Boolean })
required = false;
@property({ attribute: false })
set errors(value: ErrorDetail[] | undefined) {
this._errors = value;
const hasError = (value || []).length > 0;
this.querySelectorAll("input").forEach((input) => {
input.setAttribute("aria-invalid", hasError.toString());
});
this.requestUpdate();
}
_errors?: ErrorDetail[];
updated(): void {
this.querySelectorAll<HTMLInputElement>("input[autofocus]").forEach((input) => {
input.focus();
});
}
render(): TemplateResult {
return html`<div class="pf-c-form__group">
<label class="pf-c-form__label">
<span class="pf-c-form__label-text">${this.label}</span>
${this.required
? html`<span class="pf-c-form__label-required" aria-hidden="true">*</span>`
: html``}
</label>
<slot></slot>
${(this._errors || []).map((error) => {
return html`<p class="pf-c-form__helper-text pf-m-error">
<span class="pf-c-form__helper-text-icon">
<i class="fas fa-exclamation-circle" aria-hidden="true"></i> </span
>${error.string}
</p>`;
})}
</div>`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ak-form-element": FormElement;
}
}

View File

@@ -70,7 +70,20 @@ export class HorizontalFormElement extends AKElement {
//#endregion
public controlledElement: NamedElement | AkControlElement | null = null;
#controlledElement: AkControlElement | NamedElement | null = null;
/**
* The element that should be focused when the form is submitted.
*/
public get focusTarget(): AkControlElement | NamedElement<HTMLElement> | null {
if (!(this.#controlledElement instanceof HTMLElement)) {
return null;
}
if (!this.#controlledElement.checkVisibility()) return null;
return this.#controlledElement;
}
//#region Lifecycle
@@ -79,8 +92,8 @@ export class HorizontalFormElement extends AKElement {
}
public override updated(changedProperties: PropertyValues<this>): void {
if (changedProperties.has("errorMessages") && this.controlledElement) {
this.controlledElement.setAttribute(
if (changedProperties.has("errorMessages") && this.#controlledElement) {
this.#controlledElement.setAttribute(
"aria-invalid",
this.errorMessages?.length ? "true" : "false",
);
@@ -99,12 +112,13 @@ export class HorizontalFormElement extends AKElement {
for (const element of this.querySelectorAll("*")) {
// Is this element capable of being named?
if (!isControlElement(element) && !isNameableElement(element)) continue;
// And does the element already match the name?
if (element.getAttribute("name") === this.name) continue;
element.setAttribute("name", this.name);
this.#controlledElement = element;
if (element.getAttribute("name") !== this.name) {
element.setAttribute("name", this.name);
}
this.controlledElement = element;
break;
}
}

View File

@@ -82,7 +82,18 @@ export class SearchSelectBase<T> extends AkControlElement<string> implements ISe
// Used to inform the form of the name of the object
@property()
name?: string;
public name?: string;
/**
* A unique ID to associate with the input and label.
* @property
*/
@property({ type: String, reflect: false })
public fieldID?: string;
// Used to inform the form of the input label.
@property()
public label?: string;
// The textual placeholder for the search's <input> object, if currently empty. Used as the
// native <input> object's `placeholder` field.
@@ -255,6 +266,7 @@ export class SearchSelectBase<T> extends AkControlElement<string> implements ISe
return html`<ak-search-select-view
managed
.fieldID=${this.fieldID}
.options=${options}
value=${ifDefined(value)}
?blankable=${this.blankable}

View File

@@ -27,7 +27,11 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
*
* @todo Consider making this a static method on singleton {@linkcode MessageContainer}
*/
export function showMessage(message: APIMessage, unique = false): void {
export function showMessage(message: APIMessage | null, unique = false): void {
if (!message) {
return;
}
const container = document.querySelector<MessageContainer>("ak-message-container");
if (!container) {
@@ -35,7 +39,10 @@ export function showMessage(message: APIMessage, unique = false): void {
}
if (!message.message.trim()) {
message.message = msg("Error");
console.warn("authentik/messages: `showMessage` received an empty message", message);
message.message = msg("An unknown error occurred");
message.description ??= msg("Please check the browser console for more details.");
}
container.addMessage(message, unique);

View File

@@ -45,7 +45,7 @@ export function isNameableElement(element: Element): element is NamedElement {
return false;
}
return NameableElements.has(element.tagName);
return NameableElements.has(element.tagName) || element.getAttribute("name") !== null;
}
/**

View File

@@ -3,7 +3,6 @@ import { AKElement } from "#elements/Base";
import { msg } from "@lit/localize";
import { css, CSSResult, html, nothing } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css";
@@ -18,24 +17,44 @@ export class FormStatic extends AKElement {
static styles: CSSResult[] = [
PFAvatar,
css`
/* Form with user */
.form-control-static {
margin-top: var(--pf-global--spacer--sm);
margin-block-start: var(--pf-global--spacer--sm);
display: flex;
align-items: center;
justify-content: space-between;
}
.form-control-static .avatar {
display: flex;
align-items: center;
}
.form-control-static img {
margin-right: var(--pf-global--spacer--xs);
}
.form-control-static a {
padding-top: var(--pf-global--spacer--xs);
padding-bottom: var(--pf-global--spacer--xs);
line-height: var(--pf-global--spacer--xl);
gap: var(--pf-global--spacer--sm);
.pf-c-avatar {
flex: 0 0 auto;
}
.primary-content {
display: flex;
align-items: center;
flex: 1 1 auto;
gap: 1rem;
}
.username {
flex: 1 1 auto;
text-align: left;
max-width: 20rem;
text-overflow: ellipsis;
overflow-wrap: break-word;
display: box;
display: -webkit-box;
line-clamp: 3;
-webkit-line-clamp: 3;
box-orient: vertical;
-webkit-box-orient: vertical;
overflow: hidden;
}
.links {
flex: 0 0 auto;
text-align: right;
}
}
`,
];
@@ -44,17 +63,22 @@ export class FormStatic extends AKElement {
if (!this.user) {
return nothing;
}
return html`
<div class="form-control-static">
<div class="avatar">
<img
class="pf-c-avatar"
src="${ifDefined(this.userAvatar)}"
alt="${msg("User's avatar")}"
/>
${this.user}
<div class="primary-content">
${this.userAvatar
? html`<img
class="pf-c-avatar"
src=${this.userAvatar}
alt=${msg("User's avatar")}
/>`
: nothing}
<div class="username" aria-label=${msg("Username")}>${this.user}</div>
</div>
<div class="links">
<slot name="link"></slot>
</div>
<slot name="link"></slot>
</div>
`;
}

View File

@@ -1,9 +1,10 @@
import "#elements/forms/FormElement";
import { AKElement } from "#elements/Base";
import { bound } from "#elements/decorators/bound";
import { isActiveElement } from "#elements/utils/focus";
import { AKFormErrors, ErrorProp } from "#components/ak-field-errors";
import { AKLabel } from "#components/ak-label";
import { msg } from "@lit/localize";
import { html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators.js";
@@ -11,6 +12,7 @@ import { classMap } from "lit/directives/class-map.js";
import { createRef, ref, Ref } from "lit/directives/ref.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-group.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
@@ -39,7 +41,7 @@ const Visibility = {
@customElement("ak-flow-input-password")
export class InputPassword extends AKElement {
static styles = [PFBase, PFInputGroup, PFFormControl, PFButton];
static styles = [PFBase, PFForm, PFInputGroup, PFFormControl, PFButton];
//#region Properties
@@ -49,7 +51,7 @@ export class InputPassword extends AKElement {
* @attr
*/
@property({ type: String, attribute: "input-id" })
inputId = "ak-stage-password-input";
public inputID = "ak-stage-password-input";
/**
* The name of the input field.
@@ -86,8 +88,8 @@ export class InputPassword extends AKElement {
/**
* The errors for the input field.
*/
@property({ type: Object })
errors: Record<string, string> = {};
@property({ attribute: false })
public errors?: ErrorProp[];
/**
* Whether to allow the user to toggle the visibility of the password.
@@ -306,37 +308,32 @@ export class InputPassword extends AKElement {
}
render() {
return html` <ak-form-element
label="${this.label}"
required
class="pf-c-form__group"
.errors=${this.errors}
>
<div class="pf-c-form__group-control">
<div class="pf-c-input-group">
<input
type=${this.passwordVisible ? "text" : "password"}
id=${this.inputId}
name=${this.name}
placeholder=${this.placeholder}
autocomplete="current-password"
class="${classMap({
"pf-c-form-control": true,
"pf-m-icon": true,
"pf-m-caps-lock": this.capsLock,
})}"
required
aria-invalid=${this.errors?.length ? "true" : "false"}
value=${this.initialValue}
${ref(this.inputRef)}
/>
return html` ${AKLabel({ required: true, htmlFor: this.inputID }, this.label)}
<div class="pf-c-form__group">
<div class="pf-c-form__group-control">
<div class="pf-c-input-group">
<input
type=${this.passwordVisible ? "text" : "password"}
id=${this.inputID}
name=${this.name}
placeholder=${this.placeholder}
autocomplete="current-password"
class="${classMap({
"pf-c-form-control": true,
"pf-m-icon": true,
"pf-m-caps-lock": this.capsLock,
})}"
required
aria-invalid=${this.errors?.length ? "true" : "false"}
value=${this.initialValue}
${ref(this.inputRef)}
/>
${this.renderVisibilityToggle()}
${this.renderVisibilityToggle()}
</div>
${AKFormErrors({ errors: this.errors })} ${this.renderHelperText()}
</div>
${this.renderHelperText()}
</div>
</ak-form-element>`;
</div>`;
}
//#endregion

View File

@@ -1,7 +1,9 @@
import "#elements/forms/FormElement";
import "#flow/FormStatic";
import "#flow/components/ak-flow-card";
import { AKFormErrors } from "#components/ak-field-errors";
import { AKLabel } from "#components/ak-label";
import { BaseStage } from "#flow/stages/base";
import {
@@ -16,6 +18,7 @@ import { customElement } from "lit/decorators.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-group.css";
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFTitle from "@patternfly/patternfly/components/Title/title.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
@@ -25,15 +28,24 @@ export class OAuth2DeviceCode extends BaseStage<
OAuthDeviceCodeChallenge,
OAuthDeviceCodeChallengeResponseRequest
> {
static styles: CSSResult[] = [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton];
static styles: CSSResult[] = [
PFBase,
PFLogin,
PFForm,
PFFormControl,
PFTitle,
PFButton,
PFInputGroup,
];
render(): TemplateResult {
return html`<ak-flow-card .challenge=${this.challenge}>
<form
class="pf-c-form"
@submit=${this.submitForm}
>
<form class="pf-c-form" @submit=${this.submitForm}>
<div class="pf-c-form__group">
${AKLabel({ required: true, htmlFor: "device-code-input" }, msg("Device Code"))}
<input
id="device-code-input"
type="text"
name="code"
inputmode="numeric"
@@ -45,7 +57,8 @@ export class OAuth2DeviceCode extends BaseStage<
value=""
required
/>
</ak-form-element>
${AKFormErrors({ errors: this.challenge.responseErrors?.code })}
</div>
<div class="pf-c-form__group pf-m-action">
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">

View File

@@ -1,4 +1,3 @@
import "#elements/forms/FormElement";
import "#flow/FormStatic";
import "#flow/components/ak-flow-card";

View File

@@ -1,7 +1,9 @@
import "#elements/forms/FormElement";
import "#flow/FormStatic";
import "#flow/components/ak-flow-card";
import { AKFormErrors } from "#components/ak-field-errors";
import { AKLabel } from "#components/ak-label";
import { BaseStage } from "#flow/stages/base";
import {
@@ -18,6 +20,7 @@ import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-group.css";
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFTitle from "@patternfly/patternfly/components/Title/title.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
@@ -33,6 +36,7 @@ export class AuthenticatorEmailStage extends BaseStage<
PFLogin,
PFForm,
PFFormControl,
PFInputGroup,
PFTitle,
PFButton,
];
@@ -51,13 +55,13 @@ export class AuthenticatorEmailStage extends BaseStage<
>
</div>
</ak-form-static>
<ak-form-element
label="${msg("Configure your email")}"
required
class="pf-c-form__group"
.errors=${(this.challenge?.responseErrors || {}).email}
>
<div class="pf-c-form__group">
${AKLabel(
{ required: true, htmlFor: "email-input" },
msg("Configure your email"),
)}
<input
id="email-input"
type="email"
name="email"
placeholder="${msg("Please enter your email address.")}"
@@ -66,7 +70,8 @@ export class AuthenticatorEmailStage extends BaseStage<
class="pf-c-form-control"
required
/>
</ak-form-element>
${AKFormErrors({ errors: this.challenge.responseErrors?.email })}
</div>
${this.renderNonFieldErrors()}
<div class="pf-c-form__group pf-m-action">
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
@@ -93,13 +98,10 @@ export class AuthenticatorEmailStage extends BaseStage<
A verification token has been sent to your configured email address
${ifDefined(this.challenge.email)}
<form class="pf-c-form" @submit=${this.submitForm}>
<ak-form-element
label="${msg("Code")}"
required
class="pf-c-form__group"
.errors=${(this.challenge?.responseErrors || {}).code}
>
<div class="pf-c-form__group">
${AKLabel({ required: true, htmlFor: "code-input" }, msg("Code"))}
<input
id="code-input"
type="text"
name="code"
inputmode="numeric"
@@ -110,7 +112,8 @@ export class AuthenticatorEmailStage extends BaseStage<
class="pf-c-form-control"
required
/>
</ak-form-element>
${AKFormErrors({ errors: this.challenge.responseErrors?.code })}
</div>
${this.renderNonFieldErrors()}
<div class="pf-c-form__group pf-m-action">
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">

View File

@@ -1,7 +1,9 @@
import "#elements/forms/FormElement";
import "#flow/FormStatic";
import "#flow/components/ak-flow-card";
import { AKFormErrors } from "#components/ak-field-errors";
import { AKLabel } from "#components/ak-label";
import { BaseStage } from "#flow/stages/base";
import {
@@ -18,6 +20,7 @@ import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-group.css";
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFTitle from "@patternfly/patternfly/components/Title/title.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
@@ -33,15 +36,18 @@ export class AuthenticatorSMSStage extends BaseStage<
PFLogin,
PFForm,
PFFormControl,
PFInputGroup,
PFTitle,
PFButton,
];
renderPhoneNumber(): TemplateResult {
return html`<ak-flow-card .challenge=${this.challenge}>
<form
class="pf-c-form"
@submit=${this.submitForm}
<form class="pf-c-form" @submit=${this.submitForm}>
<ak-form-static
class="pf-c-form__group"
userAvatar=${this.challenge.pendingUserAvatar}
user=${this.challenge.pendingUser}
>
<div slot="link">
<a href="${ifDefined(this.challenge.flowInfo?.cancelUrl)}"
@@ -49,12 +55,12 @@ export class AuthenticatorSMSStage extends BaseStage<
>
</div>
</ak-form-static>
<ak-form-element
label="${msg("Phone number")}"
required
class="pf-c-form__group"
.errors=${(this.challenge?.responseErrors || {}).phone_number}
>
<div class="pf-c-form__group">
${AKLabel(
{ required: true, htmlFor: "phone-number-input" },
msg("Phone number"),
)}
<input
type="tel"
name="phoneNumber"
@@ -64,7 +70,8 @@ export class AuthenticatorSMSStage extends BaseStage<
class="pf-c-form-control"
required
/>
</ak-form-element>
${AKFormErrors({ errors: this.challenge.responseErrors?.phone_number })}
</div>
${this.renderNonFieldErrors()}
<div class="pf-c-form__group pf-m-action">
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
@@ -89,13 +96,10 @@ export class AuthenticatorSMSStage extends BaseStage<
>
</div>
</ak-form-static>
<ak-form-element
label="${msg("Code")}"
required
class="pf-c-form__group"
.errors=${(this.challenge?.responseErrors || {}).code}
>
<div class="pf-c-form__group">
${AKLabel({ required: true, htmlFor: "sms-code-input" }, msg("Code"))}
<input
id="sms-code-input"
type="text"
name="code"
inputmode="numeric"
@@ -106,7 +110,8 @@ export class AuthenticatorSMSStage extends BaseStage<
class="pf-c-form-control"
required
/>
</ak-form-element>
${AKFormErrors({ errors: this.challenge.responseErrors?.code })}
</div>
${this.renderNonFieldErrors()}
<div class="pf-c-form__group pf-m-action">
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">

View File

@@ -1,4 +1,3 @@
import "#elements/forms/FormElement";
import "#flow/FormStatic";
import "#flow/components/ak-flow-card";
@@ -17,6 +16,7 @@ import { ifDefined } from "lit/directives/if-defined.js";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import PFInputGroup from "@patternfly/patternfly/components/InputGroup/input-group.css";
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFTitle from "@patternfly/patternfly/components/Title/title.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
@@ -31,6 +31,7 @@ export class AuthenticatorStaticStage extends BaseStage<
PFLogin,
PFForm,
PFFormControl,
PFInputGroup,
PFTitle,
PFButton,
css`
@@ -64,13 +65,13 @@ export class AuthenticatorStaticStage extends BaseStage<
>
</div>
</ak-form-static>
<ak-form-element label="" class="pf-c-form__group">
<div class="pf-c-form__group">
<ul>
${this.challenge.codes.map((token) => {
return html`<li class="pf-m-monospace">${token}</li>`;
})}
</ul>
</ak-form-element>
</div>
<p>${msg("Make sure to keep these tokens in a safe place.")}</p>
<div class="pf-c-form__group pf-m-action">

Some files were not shown because too many files have changed in this diff Show More