Compare commits

...

176 Commits

Author SHA1 Message Date
faf8bf591f providers/saml: configuration for default NameID Policy
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-18 11:39:28 +02:00
52115f9345 core, web: update translations (#15102)
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-06-18 11:15:00 +02:00
b476551f13 web: bump @sentry/browser from 9.29.0 to 9.30.0 in /web in the sentry group across 1 directory (#15104)
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 9.29.0 to 9.30.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/9.29.0...9.30.0)

---
updated-dependencies:
- dependency-name: "@sentry/browser"
  dependency-version: 9.30.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-06-18 11:14:24 +02:00
f9563c25cd core: bump github.com/jellydator/ttlcache/v3 from 3.3.0 to 3.4.0 (#15105)
Bumps [github.com/jellydator/ttlcache/v3](https://github.com/jellydator/ttlcache) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/jellydator/ttlcache/releases)
- [Commits](https://github.com/jellydator/ttlcache/compare/v3.3.0...v3.4.0)

---
updated-dependencies:
- dependency-name: github.com/jellydator/ttlcache/v3
  dependency-version: 3.4.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-06-18 11:14:15 +02:00
0067e6e155 website: bump @types/lodash from 4.17.17 to 4.17.18 in /website (#15106)
Bumps [@types/lodash](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/lodash) from 4.17.17 to 4.17.18.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/lodash)

---
updated-dependencies:
- dependency-name: "@types/lodash"
  dependency-version: 4.17.18
  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-06-18 11:14:08 +02:00
ce183929d4 website/integrations: zipline: add offline_access scope (#15099)
Closes https://github.com/goauthentik/authentik/issues/15098

Signed-off-by: Dominic R <dominic@sdko.org>
2025-06-17 16:15:07 -05:00
2fdf345271 website/docs: Add steps to troubleshoot /initial-setup/ (#15011)
* Add steps to troubleshoot /initial-setup/

* fix linting

* Apply suggestions from code review

Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>

* Apply suggestions from code review

Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>

* add email part

* Apply suggestions from code review

Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>

* Apply suggestions from code review

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>

* change wording

---------

Signed-off-by: Marcelo Elizeche Landó <marce@melizeche.com>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-06-17 08:40:14 -05:00
bbcf8418b4 core, web: update translations (#15084)
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-06-17 13:50:05 +02:00
dc57be46f4 website: bump the eslint group in /website with 3 updates (#15085)
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.34.0 to 8.34.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.34.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.34.0 to 8.34.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.34.1/packages/parser)

Updates `typescript-eslint` from 8.34.0 to 8.34.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.34.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.34.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.34.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.34.1
  dependency-type: direct:development
  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-06-17 13:31:27 +02:00
d68b3ba516 website: bump @types/node from 24.0.1 to 24.0.3 in /website (#15086)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.0.1 to 24.0.3.
- [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.0.3
  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-06-17 13:31:20 +02:00
a9c46cfcbd website: bump postcss from 8.5.5 to 8.5.6 in /website (#15087)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.5 to 8.5.6.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.5...8.5.6)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.6
  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-06-17 13:31:12 +02:00
c50353ebf6 core: bump webauthn from 2.5.2 to 2.6.0 (#15089)
Bumps [webauthn](https://github.com/duo-labs/py_webauthn) from 2.5.2 to 2.6.0.
- [Release notes](https://github.com/duo-labs/py_webauthn/releases)
- [Changelog](https://github.com/duo-labs/py_webauthn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/duo-labs/py_webauthn/compare/v2.5.2...v2.6.0)

---
updated-dependencies:
- dependency-name: webauthn
  dependency-version: 2.6.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-06-17 13:30:57 +02:00
db6be9e1b6 core: bump goauthentik.io/api/v3 from 3.2025061.2 to 3.2025062.1 (#15090)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2025061.2 to 3.2025062.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.2025061.2...v3.2025062.1)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2025062.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-06-17 13:30:50 +02:00
a74892886d web: bump the eslint group across 2 directories with 3 updates (#15091)
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.34.0 to 8.34.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.34.1/packages/typescript-eslint)

Updates `@typescript-eslint/eslint-plugin` from 8.34.0 to 8.34.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.34.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.34.0 to 8.34.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.34.1/packages/parser)

Updates `typescript-eslint` from 8.34.0 to 8.34.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.34.1/packages/typescript-eslint)

Updates `@typescript-eslint/eslint-plugin` from 8.34.0 to 8.34.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.34.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.34.0 to 8.34.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.34.1/packages/parser)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.34.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.34.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.34.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.34.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.34.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.34.1
  dependency-type: direct:development
  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-06-17 13:30:42 +02:00
74cd4c2236 translate: Updates for file web/xliff/en.xlf in zh_CN (#15074)
Translate web/xliff/en.xlf in zh_CN

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-17 13:28:56 +02:00
ef3bd7e77b translate: Updates for file web/xliff/en.xlf in zh-Hans (#15075)
Translate web/xliff/en.xlf in zh-Hans

100% translated source file: 'web/xliff/en.xlf'
on 'zh-Hans'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-17 13:28:42 +02:00
3f5ad2baa4 ci: fix post-release e2e builds failing (#15082)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-17 09:10:26 +02:00
24805f087b web: bump API Client version (#15079)
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-06-17 01:51:07 +02:00
9464b422a3 web/common: fix uiConfig not merged correctly (#15080)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-17 01:36:39 +02:00
da6d4ede51 root: backport version bump 2025.6.2 (#15078)
release: 2025.6.2
2025-06-17 00:21:39 +02:00
cecad5bfd3 website/integrations: add note to nextcloud OIDC config (#15073)
Add note to OIDC config
2025-06-16 16:47:16 +00:00
bc4b07d57b web/admin: remove all special cases of slug handling, replace with a "smart slug" component (#14983)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* web/components: Remove all special cases of slug handling, replace with a "smart slug" component

This commit removes all special handling for the `slug` attribute in our text. A variant of the text
input control that can handle formatting-as-slugs has replaced all the slugificiation code; simply
drop it onto a page and tell it the (must be unique) selector from which to get the data to be
slugified. It only looks up one tier of the DOM so be careful that both the text input and its slug
accessory occupy the same DOM context.

## Details

### The Component

Now that we know a (lot) more about Lit, this component has been slightly updated to meet our
current standards.

- web/src/components/ak-slug-input.ts

Changes made:

- The "listen for the source object" has been moved to the `firstUpdated`, so that it no longer has
  to wait for the end of a render.
 - The `dirtyFlag` handler now uses the `@input` syntax.
- Updated the slug formatter to permit trailing dashes.
- Uses the `@bound` decorator, eliminating the need to do binding in the constructor (and so
  eliminating the constructor completely).

### Component uses:

The following components were revised to use `ak-slug-input` instead of a plain text input with the
slug-handling added by our forms manager.

- applications/ApplicationForm.ts
- flows/FlowForm.ts
- sources/kerberos/KerberosSourceForm.ts
- sources/ldap/LDAPSourceForm.ts
- sources/oauth/OAuthSourceForm.ts
- sources/plex/PlexSourceForm.ts
- sources/saml/SAMLSourceForm.ts
- sources/scim/SCIMSourceForm.ts

### Remove the redundant special slug handling code

- web/src/elements/forms/Form.ts
- web/src/elements/forms/HorizontalFormElement.ts

### A special case among special cases

- web/src/admin/stages/invitation/InvitationForm.ts

This form is our one case where we have a slug input field with no corresponding text source. Adding
a simple event handler to validate the value whenever it changed and write back a "clean" slug was
the most straightforward solution. I added a help line; it seemed "surprising" to ask someone for a
name and not follow the same rules as "names" everywhere else in our UI without explanation.

* After writing the commit message, I realized some of the comments I made MUST be added to the component.

* The `source` attribute needed its own comment to indicate that a `query()` compatible selector is expected.

* Added public/private/protected/# indicators to all fields.  Trying to balance between getting it 'right' and leaving an opening for harmonizing style-sharing and state-sharing between (text / textarea), slug, password and (visible / hidden / secret).

* Removed the ids as requested; the default "look for this" matches the original behavior without requiring it be hard-coded and unchangable.
2025-06-16 09:04:00 -07:00
e85d2d0096 Web/cleanup/empty state better slot handling (#14289)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* web: remove Lit syntax from always true attributes

## What

Replaces instances of `?loading=${true}` and `?loading="${true}"` with `loading`

## Why

The Lit syntax is completely unnecessary when the attribute's state is constant, and it's a few
(just a few) extra CPU cycles for Lit to process that.

More to the point, it annoys me.

## How

```
$ perl -pi.bak -e 's/\?loading=\$\{true\}/loading/' $(rg -l '\?loading=\$\{true\}')
$ find . -name '*.bak' -exec rm {} \;
$ perl -pi.bak -e 's/\?loading="\$\{true\}"/loading/' $(rg -l '\?loading="\$\{true\}"')
$ find . -name '*.bak' -exec rm {} \;
```

* Prettier had opinions

* web: move optional textual information out of attributes and into slots

## What

Replaces instances of:

```
<ak-empty-state header=${msg(...)}></ak-empty-state>
```

with

```
<ak-empty-state><span slot="header">${msg(...)}</span></ak-empty-state>
```

## Why

1. It's correct.
2. It lets us elide the decorations for any slots we aren't using.
3. It's preparation for moving to Patternfly 5
4. It annoyed me.

## How

Since we already have Patternfly Elements installed, we have access to the PFE-Core, which has the
unbelievable useful `SlotsController`.  Using it, I created a conditional render template that will
only put in the header, body, and primary slots if there is something in the lightDOM requesting
those slots.  The conditional template will still put the spinner in if the header is not provided
but the loading state is true.

I then had to edit all the places where this is used. For about 30 of them, this script sufficed:

```
perl -pi.bak -e 's/header="?(\$\{msg\([^)]+\)\})"?>/><span slot="header">\1<\/span>/' \
     $(rg -l `<ak-empty-state[^>]header')

```

The other six had to be done by hand.  I have tested a handful of the automatic ones, and all of the
ones that were edited manually.  I'm pleasantly surprised that the textual rules [are inherited by
the slots as expected](https://htmlwithsuperpowers.netlify.app/styling/inheritable.htm).
2025-06-16 08:17:11 -07:00
be1dd3103b website/docs: release notes for 2025.6.2 (#15065)
* website/docs: release notes for `2025.6.2`

* fixup! website/docs: release notes for `2025.6.2`
2025-06-16 17:01:56 +02:00
5dfde5e1d3 website/docs: remove commented out config options (#15064)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-16 16:35:23 +02:00
7cb1e6d81e website/docs: postgres troubleshooting: get PGPASSWORD from POSTGRES_PASSWORD_FILE (#15039) 2025-06-16 15:00:23 +02:00
d7c3129b1c core: bump goauthentik/fips-python from 3.13.4-slim-bookworm-fips to 3.13.5-slim-bookworm-fips (#15058)
core: bump goauthentik/fips-python

Bumps goauthentik/fips-python from 3.13.4-slim-bookworm-fips to 3.13.5-slim-bookworm-fips.

---
updated-dependencies:
- dependency-name: goauthentik/fips-python
  dependency-version: 3.13.5-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-06-16 12:28:39 +02:00
2a1d33021b website: bump the eslint group in /website with 2 updates (#15059)
Bumps the eslint group in /website with 2 updates: [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) and [eslint](https://github.com/eslint/eslint).


Updates `@eslint/js` from 9.28.0 to 9.29.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/commits/v9.29.0/packages/js)

Updates `eslint` from 9.28.0 to 9.29.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.28.0...v9.29.0)

---
updated-dependencies:
- dependency-name: "@eslint/js"
  dependency-version: 9.29.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: eslint
  dependency-version: 9.29.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-16 12:28:21 +02:00
f273e49ae6 web: bump the wdio group across 1 directory with 3 updates (#14593)
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.4.1 to 9.14.0
- [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.14.0/packages/wdio-browser-runner)

Updates `@wdio/cli` from 9.4.1 to 9.14.0
- [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.14.0/packages/wdio-cli)

Updates `@wdio/spec-reporter` from 9.1.2 to 9.14.0
- [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.14.0/packages/wdio-spec-reporter)

---
updated-dependencies:
- dependency-name: "@wdio/browser-runner"
  dependency-version: 9.14.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: wdio
- dependency-name: "@wdio/cli"
  dependency-version: 9.14.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: wdio
- dependency-name: "@wdio/spec-reporter"
  dependency-version: 9.14.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: wdio
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-16 12:28:10 +02:00
cc31957900 web: bump @sentry/browser from 9.28.1 to 9.29.0 in /web in the sentry group across 1 directory (#15061)
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 9.28.1 to 9.29.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/9.28.1...9.29.0)

---
updated-dependencies:
- dependency-name: "@sentry/browser"
  dependency-version: 9.29.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-06-16 12:27:30 +02:00
b1ccdecc8e web: bump the eslint group across 2 directories with 2 updates (#15062)
Bumps the eslint group with 1 update in the /packages/eslint-config directory: [eslint](https://github.com/eslint/eslint).
Bumps the eslint group with 1 update in the /web directory: [eslint](https://github.com/eslint/eslint).


Updates `eslint` from 9.28.0 to 9.29.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.28.0...v9.29.0)

Updates `@eslint/js` from 9.28.0 to 9.29.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/commits/v9.29.0/packages/js)

Updates `eslint` from 9.28.0 to 9.29.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.28.0...v9.29.0)

Updates `@eslint/js` from 9.28.0 to 9.29.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/commits/v9.29.0/packages/js)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 9.29.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: "@eslint/js"
  dependency-version: 9.29.0
  dependency-type: indirect
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: eslint
  dependency-version: 9.29.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: "@eslint/js"
  dependency-version: 9.29.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-16 12:27:17 +02:00
34031003a4 core: bump axllent/mailpit from v1.26.0 to v1.26.1 in /tests/e2e (#15060)
Bumps axllent/mailpit from v1.26.0 to v1.26.1.

---
updated-dependencies:
- dependency-name: axllent/mailpit
  dependency-version: v1.26.1
  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-06-16 12:27:01 +02:00
055e1d1025 core: bump pydantic from 2.11.5 to 2.11.7 (#15063)
Bumps [pydantic](https://github.com/pydantic/pydantic) from 2.11.5 to 2.11.7.
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.11.5...v2.11.7)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-version: 2.11.7
  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-06-16 12:26:52 +02:00
59a804273e providers/oauth2: bug fixes from conformance testing (#15056)
* check authorize request param earlier

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

* fix basic suite?

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

* another actual fix; don't return access_token when using response_type id_token

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

* only run basic+implicit for now, fix other tests

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

# Conflicts:
#	tests/openid_conformance/test_conformance.py

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-16 12:23:18 +02:00
bce70a1796 website/integrations: change nextcloud scope name to avoid confusion (#15050)
changed "profile" to "nextcloud"

Signed-off-by: Marlin <77961876+Keksmo@users.noreply.github.com>
2025-06-16 03:10:53 +02:00
e86c40a00c web/flow: cleanup WebAuthn helper functions (#14460)
* pass #1

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

* pass #2

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

* add polyfill

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-16 02:39:50 +02:00
20e07486ee web/elements: fix typo in localeComparator (#15054)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-16 01:37:38 +02:00
0cb7cf2c96 stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#15049)
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-06-15 23:54:50 +02:00
07736a90b2 translate: Updates for file locale/en/LC_MESSAGES/django.po in es (#15047)
* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

* Translate locale/en/LC_MESSAGES/django.po in es

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'es'.

---------

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-15 22:48:33 +02:00
ec28a86259 core, web: update translations (#15048)
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-06-15 22:48:21 +02:00
260800c60b blueprints: add section support for organisation (#15045)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-15 20:49:21 +02:00
ee4780394d core, web: update translations (#15043)
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-06-14 02:44:35 +02:00
23b746941f web/admin: adopt ak-hidden-text (#15042)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-14 02:22:14 +02:00
3c2ce40afd web/admin: Text and Textarea Fields that "hide" their contents until prompted (#15024)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* web/admin: Provide `hidden` text and textarea components

## Details

This commit provides two new elements (technically, since they're API-unaware), one for `<input
type="text">`, and one for `<textarea>`, that provide for the ability to create fields that are (or
can be) hidden. A new boolean attribute, `revealed`, shows the state of the component (the content
is therefore *not* revealed by default).

It also includes a third new element, `ak-visibility-toggle`, that creates a hide/show toggle with
all the right icons, styling, and eventing.  It's straightforward, and isolating it improved the
DX of everything that uses that feature by quite a bit.

Storybook stories (with autodoc documentation) have been provided for `ak-hidden-text-input`,
`ak-hidden-textarea-input`, and `ak-visibility-toggle`.

## Maintenance Notice

As a maintenance detail, the field `ak-private-text` has been renamed `ak-secret-text` to reflect
its usage, and the places where it was used have all been changed to reflect that update.

* web/component: embed styling (for now) to handle the lightDom/shadowDom/slot conflicts in HorizontalLightComponent and HorizontalFormElement

* Comments and Types. I really shouldn't have to catch this stuff with my eyeballs.

* fix typo

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-06-14 01:48:34 +02:00
2aceed285e providers/rac: fixes prompt data not being merged with connection_settings (#15037)
* Fixes line that pulls in prompt data

* fallback to old settings

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-06-13 18:54:20 +02:00
81e5fef667 website/docs: also hide the postgres pool_options setting (#15023) 2025-06-13 13:36:52 +00:00
7aa6593760 blueprints: sort schema items (#15022) 2025-06-13 13:34:49 +00:00
c40a17beb9 website: bump the build group in /website with 6 updates (#15027)
Bumps the build group in /website with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [@swc/core-darwin-arm64](https://github.com/swc-project/swc) | `1.12.0` | `1.12.1` |
| [@swc/core-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.12.0` | `1.12.1` |
| [@swc/core-linux-x64-gnu](https://github.com/swc-project/swc) | `1.12.0` | `1.12.1` |
| [@swc/html-darwin-arm64](https://github.com/swc-project/swc) | `1.12.0` | `1.12.1` |
| [@swc/html-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.12.0` | `1.12.1` |
| [@swc/html-linux-x64-gnu](https://github.com/swc-project/swc) | `1.12.0` | `1.12.1` |


Updates `@swc/core-darwin-arm64` from 1.12.0 to 1.12.1
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.12.0...v1.12.1)

Updates `@swc/core-linux-arm64-gnu` from 1.12.0 to 1.12.1
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.12.0...v1.12.1)

Updates `@swc/core-linux-x64-gnu` from 1.12.0 to 1.12.1
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.12.0...v1.12.1)

Updates `@swc/html-darwin-arm64` from 1.12.0 to 1.12.1
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.12.0...v1.12.1)

Updates `@swc/html-linux-arm64-gnu` from 1.12.0 to 1.12.1
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.12.0...v1.12.1)

Updates `@swc/html-linux-x64-gnu` from 1.12.0 to 1.12.1
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.12.0...v1.12.1)

---
updated-dependencies:
- dependency-name: "@swc/core-darwin-arm64"
  dependency-version: 1.12.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-linux-arm64-gnu"
  dependency-version: 1.12.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-version: 1.12.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-darwin-arm64"
  dependency-version: 1.12.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-linux-arm64-gnu"
  dependency-version: 1.12.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-linux-x64-gnu"
  dependency-version: 1.12.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-13 14:44:06 +02:00
335c9fbc10 core: bump astral-sh/uv from 0.7.12 to 0.7.13 (#15028)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.7.12 to 0.7.13.
- [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.7.12...0.7.13)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.7.13
  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-06-13 14:44:04 +02:00
51b53caf61 core: bump twilio from 9.6.2 to 9.6.3 (#15029)
Bumps [twilio](https://github.com/twilio/twilio-python) from 9.6.2 to 9.6.3.
- [Release notes](https://github.com/twilio/twilio-python/releases)
- [Changelog](https://github.com/twilio/twilio-python/blob/main/CHANGES.md)
- [Commits](https://github.com/twilio/twilio-python/compare/9.6.2...9.6.3)

---
updated-dependencies:
- dependency-name: twilio
  dependency-version: 9.6.3
  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-06-13 14:44:01 +02:00
989100a900 core: bump sentry-sdk from 2.29.1 to 2.30.0 (#15030)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 2.29.1 to 2.30.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.29.1...2.30.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-version: 2.30.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-06-13 14:43:58 +02:00
8e1531d051 core: bump kubernetes from 32.0.1 to 33.1.0 (#15031)
Bumps [kubernetes](https://github.com/kubernetes-client/python) from 32.0.1 to 33.1.0.
- [Release notes](https://github.com/kubernetes-client/python/releases)
- [Changelog](https://github.com/kubernetes-client/python/blob/v33.1.0/CHANGELOG.md)
- [Commits](https://github.com/kubernetes-client/python/compare/v32.0.1...v33.1.0)

---
updated-dependencies:
- dependency-name: kubernetes
  dependency-version: 33.1.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-06-13 14:43:22 +02:00
f6f37d6d92 core, web: update translations (#15026)
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-06-13 02:21:16 +02:00
5b6ca70f22 web: bump the sentry group across 1 directory with 2 updates (#15025)
Bumps the sentry group with 2 updates in the /web directory: [@sentry/browser](https://github.com/getsentry/sentry-javascript) and @spotlightjs/spotlight.


Updates `@sentry/browser` from 9.28.0 to 9.28.1
- [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/9.28.0...9.28.1)

Updates `@spotlightjs/spotlight` from 2.13.3 to 3.0.0

---
updated-dependencies:
- dependency-name: "@sentry/browser"
  dependency-version: 9.28.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: sentry
- dependency-name: "@spotlightjs/spotlight"
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: sentry
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-13 02:09:40 +02:00
a74674c3d6 translate: Updates for file web/xliff/en.xlf in zh_CN (#15018)
Translate web/xliff/en.xlf in zh_CN

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-13 02:08:55 +02:00
f46984dec4 lifecycle/aws: bump aws-cdk from 2.1018.0 to 2.1018.1 in /lifecycle/aws (#15016)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1018.0 to 2.1018.1.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1018.1/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1018.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-06-13 02:08:34 +02:00
c7963e4af7 website: bump postcss from 8.5.4 to 8.5.5 in /website (#15013)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.4 to 8.5.5.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.4...8.5.5)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.5
  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-06-13 02:08:21 +02:00
6e30b11974 website: bump @types/node from 24.0.0 to 24.0.1 in /website (#15014)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 24.0.0 to 24.0.1.
- [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.0.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-06-13 02:08:11 +02:00
13bd4069e4 core: fix transaction test case (#15021)
* move patched ct to root

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

* use our transaction test case as base

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

* fix...?

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

* well apparently that works

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-13 01:48:26 +02:00
3b913ac5ef translate: Updates for file web/xliff/en.xlf in zh-Hans (#15019)
Translate web/xliff/en.xlf in zh-Hans

100% translated source file: 'web/xliff/en.xlf'
on 'zh-Hans'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-12 14:03:15 +02:00
fed094b317 website/docs: correct minor version in release notes (#15012)
Signed-off-by: Zeik0s <35345686+Zeik0s@users.noreply.github.com>
2025-06-11 22:13:53 +00:00
88d83c10a4 root: test label handling and error reporting in PytestTestRunner (#14000)
* root: test label handling and error reporting in PytestTestRunner

- Added a check for empty test labels and return a clear error instead of failing silently.
- Improved handling of dotted module paths + included support for single-module names.
- Replaced a RuntimeError with a printed error message when a test label can't be resolved.
- Wrapped the pytest.main call in a try/except to catch unexpected errors and print them nicely.

* Fix handling for test file without extension and lint

* oops

* little improvments too
2025-06-11 19:14:38 +02:00
5af2378738 outposts/ldap: Handle comma-separated attributes in LDAP search requests (#15000)
Closes https://github.com/goauthentik/authentik/issues/13539

When LDAP clients like Jira submit search requests with comma-separated attributes
(e.g., ["uid,cn,sn"] instead of ["uid", "cn", "sn"]), the LDAP outpost would return
an "Operations Error". Ths fix adds attribute normalization to properly handle
both formats by splitting comma separated attributes into individual entries.

Tests pass:
```
=== RUN   TestNormalizeAttributes
=== RUN   TestNormalizeAttributes/Empty_input
=== RUN   TestNormalizeAttributes/No_commas
=== RUN   TestNormalizeAttributes/Single_comma-separated_string
=== RUN   TestNormalizeAttributes/Mixed_input
=== RUN   TestNormalizeAttributes/With_spaces
=== RUN   TestNormalizeAttributes/Empty_parts
=== RUN   TestNormalizeAttributes/Single_element
=== RUN   TestNormalizeAttributes/Only_commas
=== RUN   TestNormalizeAttributes/Multiple_comma-separated_attributes
=== RUN   TestNormalizeAttributes/Case_preservation
=== RUN   TestNormalizeAttributes/Leading_and_trailing_spaces
=== RUN   TestNormalizeAttributes/Real-world_LDAP_attribute_examples
=== RUN   TestNormalizeAttributes/Jira-style_attribute_format
=== RUN   TestNormalizeAttributes/Single_string_with_single_attribute
=== RUN   TestNormalizeAttributes/Mix_of_standard_and_operational_attributes
--- PASS: TestNormalizeAttributes (0.00s)
    --- PASS: TestNormalizeAttributes/Empty_input (0.00s)
    --- PASS: TestNormalizeAttributes/No_commas (0.00s)
    --- PASS: TestNormalizeAttributes/Single_comma-separated_string (0.00s)
    --- PASS: TestNormalizeAttributes/Mixed_input (0.00s)
    --- PASS: TestNormalizeAttributes/With_spaces (0.00s)
    --- PASS: TestNormalizeAttributes/Empty_parts (0.00s)
    --- PASS: TestNormalizeAttributes/Single_element (0.00s)
    --- PASS: TestNormalizeAttributes/Only_commas (0.00s)
    --- PASS: TestNormalizeAttributes/Multiple_comma-separated_attributes (0.00s)
    --- PASS: TestNormalizeAttributes/Case_preservation (0.00s)
    --- PASS: TestNormalizeAttributes/Leading_and_trailing_spaces (0.00s)
    --- PASS: TestNormalizeAttributes/Real-world_LDAP_attribute_examples (0.00s)
    --- PASS: TestNormalizeAttributes/Jira-style_attribute_format (0.00s)
    --- PASS: TestNormalizeAttributes/Single_string_with_single_attribute (0.00s)
    --- PASS: TestNormalizeAttributes/Mix_of_standard_and_operational_attributes (0.00s)
PASS
ok      goauthentik.io/internal/outpost/ldap/search     0.194s
```
2025-06-11 18:16:40 +02:00
6ec745ddc0 website/integrations: standardize application slug placeholder in docs (#15007)
Standardizes application slug placeholder in docs
2025-06-11 16:52:21 +01:00
a44375a9d8 core: bump django from 5.1.10 to 5.1.11 (#14997) 2025-06-11 17:26:52 +02:00
3bf9cf681a web/elements: Add light mode custom css handling (#14944)
* fix(ui): Add light mode custom css handling

Signed-off-by: CodeMax IT Solutions Pvt. Ltd. <137166088+cdmx1@users.noreply.github.com>

* Update Base.ts

Signed-off-by: CodeMax IT Solutions Pvt. Ltd. <137166088+cdmx1@users.noreply.github.com>

---------

Signed-off-by: CodeMax IT Solutions Pvt. Ltd. <137166088+cdmx1@users.noreply.github.com>
2025-06-11 15:03:05 +02:00
b8cf0e5dc4 website/docs: add host header dynamic property mapping (#15006)
* Adds the property mapping and updates some language in the doc

* Typos
2025-06-11 13:50:18 +01:00
2180bdf7c2 core, web: update translations (#14999)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-06-11 12:35:18 +00:00
8af2d189d9 website/docs: fixes misplaced sentence (#14998)
fixes misplaced sentence

Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-06-11 07:17:03 -05:00
66f96a280e website/docs: note usage of is_restored by source stage (#13422) 2025-06-11 13:52:26 +02:00
09d5c6fa43 website: bump the build group in /website with 6 updates (#15001)
Bumps the build group in /website with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [@swc/core-darwin-arm64](https://github.com/swc-project/swc) | `1.11.31` | `1.12.0` |
| [@swc/core-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.31` | `1.12.0` |
| [@swc/core-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.31` | `1.12.0` |
| [@swc/html-darwin-arm64](https://github.com/swc-project/swc) | `1.11.31` | `1.12.0` |
| [@swc/html-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.31` | `1.12.0` |
| [@swc/html-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.31` | `1.12.0` |


Updates `@swc/core-darwin-arm64` from 1.11.31 to 1.12.0
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.31...v1.12.0)

Updates `@swc/core-linux-arm64-gnu` from 1.11.31 to 1.12.0
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.31...v1.12.0)

Updates `@swc/core-linux-x64-gnu` from 1.11.31 to 1.12.0
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.31...v1.12.0)

Updates `@swc/html-darwin-arm64` from 1.11.31 to 1.12.0
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.31...v1.12.0)

Updates `@swc/html-linux-arm64-gnu` from 1.11.31 to 1.12.0
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.31...v1.12.0)

Updates `@swc/html-linux-x64-gnu` from 1.11.31 to 1.12.0
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.31...v1.12.0)

---
updated-dependencies:
- dependency-name: "@swc/core-darwin-arm64"
  dependency-version: 1.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@swc/core-linux-arm64-gnu"
  dependency-version: 1.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-version: 1.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@swc/html-darwin-arm64"
  dependency-version: 1.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@swc/html-linux-arm64-gnu"
  dependency-version: 1.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
- dependency-name: "@swc/html-linux-x64-gnu"
  dependency-version: 1.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: build
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-11 12:23:47 +02:00
6eb4e78b22 web: bump @sentry/browser from 9.27.0 to 9.28.0 in /web in the sentry group across 1 directory (#15002)
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 9.27.0 to 9.28.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/9.27.0...9.28.0)

---
updated-dependencies:
- dependency-name: "@sentry/browser"
  dependency-version: 9.28.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-06-11 12:23:36 +02:00
c3eada8d33 core: bump msgraph-sdk from 1.32.0 to 1.33.0 (#15003)
Bumps [msgraph-sdk](https://github.com/microsoftgraph/msgraph-sdk-python) from 1.32.0 to 1.33.0.
- [Release notes](https://github.com/microsoftgraph/msgraph-sdk-python/releases)
- [Changelog](https://github.com/microsoftgraph/msgraph-sdk-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoftgraph/msgraph-sdk-python/compare/v1.32.0...v1.33.0)

---
updated-dependencies:
- dependency-name: msgraph-sdk
  dependency-version: 1.33.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-06-11 12:22:53 +02:00
48130a7463 core: bump google-api-python-client from 2.171.0 to 2.172.0 (#15004)
Bumps [google-api-python-client](https://github.com/googleapis/google-api-python-client) from 2.171.0 to 2.172.0.
- [Release notes](https://github.com/googleapis/google-api-python-client/releases)
- [Commits](https://github.com/googleapis/google-api-python-client/compare/v2.171.0...v2.172.0)

---
updated-dependencies:
- dependency-name: google-api-python-client
  dependency-version: 2.172.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-06-11 12:22:44 +02:00
9ffb2443f6 web/admin: fix language in certificate import (#14953)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* web/admin: fix language in certificate import modal

There are two buttons on the CertificateKeyPairList: "Create" and "Generate".  This language is confusing, as it is unclear what the difference between those two options could be.  The
second generates and stores a new key pair; the first only creates an entry in our database for an existing pair generated externally. After a short conversation, changing it to
"Import" seemed like a safe option.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

---------

Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-06-10 18:49:15 +02:00
0b4aed7a3d website/integrations: add new categories and update sidebar info (#14995)
* Added categories and moved docs

* Moved more docs

* move a couple more things

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

* auto-sort categories

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

* Updated sidebar info

* Add path to integrations file

* Moves meshcentral to device management. Moves cloudflare access and globalprotect to networking

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-06-10 17:18:09 +01:00
86dd1a96f6 brands: fix custom_css being escaped (#14994)
* brands: fix custom_css being escaped

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

* escape adequately

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-10 17:19:38 +02:00
0ce017b77e web/admin: show selected policy engine mode on bindings pages, allow setting it on sources (#12963)
* web/admin: show select policy engine mode on bindings pages, allow setting it in sources

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>

* slight cleanup

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

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-06-10 16:17:31 +02:00
e22e79f310 website/integrations: add bitwarden (#14922)
* Add doc and update sidebar

* WIP

* WIP

* SAML configuration complete

* Capitalisation

* Added OIDC instructions

* Update website/integrations/services/bitwarden/index.mdx

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

* Update website/integrations/services/bitwarden/index.mdx

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

* Update website/integrations/services/bitwarden/index.mdx

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

* Applied Dominic's suggestions

* Update website/integrations/services/bitwarden/index.mdx

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

* Update website/integrations/services/bitwarden/index.mdx

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

* Applied suggestion from Dominic

* Update website/integrations/services/bitwarden/index.mdx

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

* Update website/integrations/services/bitwarden/index.mdx

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

* Update website/integrations/services/bitwarden/index.mdx

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

* Update website/integrations/services/bitwarden/index.mdx

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

* Applied Tana's suggestions

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-06-10 08:35:13 -05:00
ac575aecfa core: bump goauthentik.io/api/v3 from 3.2025061.1 to 3.2025061.2 (#14986)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2025061.1 to 3.2025061.2.
- [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.2025061.1...v3.2025061.2)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2025061.2
  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-06-10 14:57:49 +02:00
fd61fb31b5 website: bump @types/node from 22.15.30 to 24.0.0 in /website (#14988)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.15.30 to 24.0.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.0.0
  dependency-type: direct:development
  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-06-10 14:57:42 +02:00
d7f6e5b79d website: bump the eslint group in /website with 3 updates (#14987)
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.33.1 to 8.34.0
- [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.34.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.33.1 to 8.34.0
- [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.34.0/packages/parser)

Updates `typescript-eslint` from 8.33.1 to 8.34.0
- [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.34.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.34.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.34.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.34.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-10 14:56:07 +02:00
09ded2a19a web: bump the eslint group across 2 directories with 3 updates (#14991)
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.33.1 to 8.34.0
- [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.34.0/packages/typescript-eslint)

Updates `@typescript-eslint/eslint-plugin` from 8.33.1 to 8.34.0
- [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.34.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.33.1 to 8.34.0
- [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.34.0/packages/parser)

Updates `typescript-eslint` from 8.33.1 to 8.34.0
- [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.34.0/packages/typescript-eslint)

Updates `@typescript-eslint/eslint-plugin` from 8.33.1 to 8.34.0
- [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.34.0/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.33.1 to 8.34.0
- [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.34.0/packages/parser)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-10 14:55:58 +02:00
6d4c9a3446 website/integrations: fix typos, update language and styling (#14978)
* Typo and improved language

* Changes "admin" to "administrator" and updates indentation

* Updates miniflux to newer styling

* Combines two notes at beginning of jellyfin doc into one

* Replaces all "your application slug" with "application_slug" and replaces tags that are no longer in use

* Replaces tags that are no longer in use

* Updates immich indentation, application_slug and removes tags

* Updated bookstack indentation, tags and application slug

* Removes kbd and em tags, and updates the application slug

* Gix metadata header in bookstack doc

* Lint fix miniflux

* ArgoCD indentation

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
2025-06-10 12:48:49 +01:00
74b5380f32 website/integrations: add 1password (#14815)
* Add doc and update sidebar

* Begin document

* WIP

* Typo

* Added automated user privisioning steps

* Added note about redirect URIs

* Update website/integrations/services/1password/index.mdx

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

* Update website/integrations/services/1password/index.mdx

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

* Update website/integrations/services/1password/index.mdx

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

* Update website/integrations/services/1password/index.mdx

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

* Update website/integrations/services/1password/index.mdx

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

* Updated based on recommendations from Dominic

* Update website/integrations/services/1password/index.mdx

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

* Update website/integrations/services/1password/index.mdx

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

* Update website/integrations/services/1password/index.mdx

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: Dominic R <dominic@sdko.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-06-10 11:43:43 +00:00
c65b3e8ae5 website/integrations: add nextcloud ldap config and update doc to new styling (#14866)
* Initial changes

* Added LDAP config

* WIP

* WIP

* Updated document to new style and added LDAP config

* Make website

* WIP

* Fixed formatting on SAML section

* Typo

* Update website/integrations/services/nextcloud/index.mdx

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

* Update website/integrations/services/nextcloud/index.mdx

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

* Update website/integrations/services/nextcloud/index.mdx

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

* Update website/integrations/services/nextcloud/index.mdx

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

* Applied suggestions from Dominic

* Applied more suggestions

* Typo

* Applied suggestions

---------

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-06-10 12:09:43 +01:00
88fa7e37dc outposts: Refactor session end signal and add LDAP support (#14539)
* outpost: promote session end signal to non-provider specific

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

* implement server-side logout in ldap

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

* fix previous import

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

* use better retry logic

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

* log

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

* make more generic if we switch from ws to something else

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

* make it possible to e2e test WS

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

* fix ldap session id

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

* ok I actually need to go to bed this took me an hour to fix

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

* format; add ldap test

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

* fix leftover state

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

* remove thread

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

* use ws base for radius

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

* separate test utils

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

* rename

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

* fix missing super calls

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

* websocket tests with browser 🎉

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

* add proxy test for sign out

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

* fix install_id issue with channels tests

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

* fix proxy basic auth test

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

* big code dedupe

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

* allow passing go build args

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

* improve waiting for outpost

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

* rewrite ldap tests

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

* ok actually fix the tests

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

* undo a couple things that need more time to cook

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

* remove unused lockfile-lint dependency since we use a shell script and SFE does not have a lockfile

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

* fix session id for ldap

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

* fix missing createTimestamp and modifyTimestamp ldap attributes

closes #10474

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-10 12:11:21 +02:00
8bfc9ab7c9 core: bump cryptography from 45.0.3 to 45.0.4 (#14989)
Bumps [cryptography](https://github.com/pyca/cryptography) from 45.0.3 to 45.0.4.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/45.0.3...45.0.4)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 45.0.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-06-10 11:25:52 +02:00
f145580dae core: bump goauthentik/fips-python from 3.13.3-slim-bookworm-fips to 3.13.4-slim-bookworm-fips (#14990)
core: bump goauthentik/fips-python

Bumps goauthentik/fips-python from 3.13.3-slim-bookworm-fips to 3.13.4-slim-bookworm-fips.

---
updated-dependencies:
- dependency-name: goauthentik/fips-python
  dependency-version: 3.13.4-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-06-10 11:25:33 +02:00
31eb4a6315 web: bump API Client version (#14985)
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-06-10 02:39:20 +02:00
48696e3d7d core, web: update translations (#14984)
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-06-10 02:36:27 +02:00
734db4dee6 events: rework metrics endpoint (#14934)
* rework event volume

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

* migrate more

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

* migrate more

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

* migrate more

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

* the rest of the owl

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

* client-side data padding

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

* I love deleting code

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

* fix

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

* fix clamping

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

* chunk it

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

* fix

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

* fix tests

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

* add event-to-color map

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

* sync colours

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

* switch colours

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

* heatmap?

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

* Revert "heatmap?"

This reverts commit c1f549a18b.

* Revert "Revert "heatmap?""

This reverts commit 6d6175b96b.

* Revert "Revert "Revert "heatmap?"""

This reverts commit 3717903f12.

* format

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-10 02:36:09 +02:00
856ac052e7 website/integrations: replaces all kbd and em tags (#14980)
Replaces all kbd and em tags
2025-06-09 21:06:37 +01:00
dea2d67ceb internal/outpost: fix incorrect usage of golang SHA API (#14981)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-09 20:57:36 +02:00
a844fb41d4 web/elements: fix dual select without sortBy (#14977)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-09 19:04:07 +02:00
f4da22aea8 website/docs: added a link in our Upgrade docs to the Outpost upgrade docs, slight reformatting (#14931)
* add link to outpost upgrade doc

* darn build breaks

* kens edits

* again

---------

Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-06-09 10:14:43 -05:00
1464852b92 website: fix search across multiple subdomains (#14976)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-09 17:13:04 +02:00
6aebf45aea core: bump goauthentik.io/api/v3 from 3.2025060.1 to 3.2025061.1 (#14972)
Bumps [goauthentik.io/api/v3](https://github.com/goauthentik/client-go) from 3.2025060.1 to 3.2025061.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.2025060.1...v3.2025061.1)

---
updated-dependencies:
- dependency-name: goauthentik.io/api/v3
  dependency-version: 3.2025061.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-06-09 14:52:58 +02:00
fad6ac76af web: bump API Client version (#14971) 2025-06-09 02:43:50 +00:00
c60a145f95 root: backport 2025.6.1 bump (#14970)
release: 2025.6.1

Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-06-09 04:15:33 +02:00
652a32d968 stages/email: Only attach logo to email if used (#14835)
* Only attach logo to email if used

* Fix MIME logo attachment to adhere to standard

* format, fix web

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

* not tuple

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-06-09 03:49:00 +02:00
bd5a66a3c7 web: bump @codemirror/lang-python from 6.1.6 to 6.2.1 in /web (#14713)
Bumps [@codemirror/lang-python](https://github.com/codemirror/lang-python) from 6.1.6 to 6.2.1.
- [Changelog](https://github.com/codemirror/lang-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/lang-python/compare/6.1.6...6.2.1)

---
updated-dependencies:
- dependency-name: "@codemirror/lang-python"
  dependency-version: 6.2.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-06-09 03:46:41 +02:00
a4c4b07614 website: bump prettier-plugin-packagejson from 2.5.14 to 2.5.15 in /website (#14829)
website: bump prettier-plugin-packagejson in /website

Bumps [prettier-plugin-packagejson](https://github.com/matzkoh/prettier-plugin-packagejson) from 2.5.14 to 2.5.15.
- [Release notes](https://github.com/matzkoh/prettier-plugin-packagejson/releases)
- [Commits](https://github.com/matzkoh/prettier-plugin-packagejson/compare/v2.5.14...v2.5.15)

---
updated-dependencies:
- dependency-name: prettier-plugin-packagejson
  dependency-version: 2.5.15
  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-06-09 03:39:00 +02:00
aaf76bab92 core: bump selenium/standalone-chrome from 136.0 to 137.0 in /tests/e2e (#14963)
Bumps selenium/standalone-chrome from 136.0 to 137.0.

---
updated-dependencies:
- dependency-name: selenium/standalone-chrome
  dependency-version: '137.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-06-09 03:32:59 +02:00
814f3fc43d core: bump axllent/mailpit from v1.25.1 to v1.26.0 in /tests/e2e (#14964)
Bumps axllent/mailpit from v1.25.1 to v1.26.0.

---
updated-dependencies:
- dependency-name: axllent/mailpit
  dependency-version: v1.26.0
  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-06-09 03:32:51 +02:00
d017af1347 core: bump astral-sh/uv from 0.7.11 to 0.7.12 (#14965)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.7.11 to 0.7.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.7.11...0.7.12)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.7.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-06-09 03:32:36 +02:00
6e11554f62 core: bump github.com/redis/go-redis/v9 from 9.9.0 to 9.10.0 (#14966)
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis) from 9.9.0 to 9.10.0.
- [Release notes](https://github.com/redis/go-redis/releases)
- [Changelog](https://github.com/redis/go-redis/blob/master/CHANGELOG.md)
- [Commits](https://github.com/redis/go-redis/compare/v9.9.0...v9.10.0)

---
updated-dependencies:
- dependency-name: github.com/redis/go-redis/v9
  dependency-version: 9.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-06-09 03:32:27 +02:00
14f2edc04b web: bump @types/mocha from 10.0.8 to 10.0.10 in /web (#14684)
Bumps [@types/mocha](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/mocha) from 10.0.8 to 10.0.10.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/mocha)

---
updated-dependencies:
- dependency-name: "@types/mocha"
  dependency-version: 10.0.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-06-09 03:30:46 +02:00
9f6173d8b2 web: bump ts-pattern from 5.4.0 to 5.7.1 in /web (#14686)
Bumps [ts-pattern](https://github.com/gvergnaud/ts-pattern) from 5.4.0 to 5.7.1.
- [Release notes](https://github.com/gvergnaud/ts-pattern/releases)
- [Commits](https://github.com/gvergnaud/ts-pattern/compare/v5.4.0...v5.7.1)

---
updated-dependencies:
- dependency-name: ts-pattern
  dependency-version: 5.7.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-06-09 03:30:29 +02:00
52c3ba551d website: bump @types/node from 22.15.29 to 22.15.30 in /website (#14968)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.15.29 to 22.15.30.
- [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: 22.15.30
  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-06-09 03:30:02 +02:00
633c6ff245 web: bump mermaid from 11.4.1 to 11.6.0 in /web (#14688)
Bumps [mermaid](https://github.com/mermaid-js/mermaid) from 11.4.1 to 11.6.0.
- [Release notes](https://github.com/mermaid-js/mermaid/releases)
- [Changelog](https://github.com/mermaid-js/mermaid/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/mermaid-js/mermaid/compare/mermaid@11.4.1...mermaid@11.6.0)

---
updated-dependencies:
- dependency-name: mermaid
  dependency-version: 11.6.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-06-09 03:28:44 +02:00
e5cb925f70 web: bump @fortawesome/fontawesome-free from 6.6.0 to 6.7.2 in /web (#14716)
Bumps [@fortawesome/fontawesome-free](https://github.com/FortAwesome/Font-Awesome) from 6.6.0 to 6.7.2.
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.6.0...6.7.2)

---
updated-dependencies:
- dependency-name: "@fortawesome/fontawesome-free"
  dependency-version: 6.7.2
  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-06-09 03:28:18 +02:00
a0b1327456 web: bump the eslint group across 2 directories with 3 updates (#14833)
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.33.0 to 8.33.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.33.1/packages/typescript-eslint)

Updates `@typescript-eslint/eslint-plugin` from 8.33.0 to 8.33.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.33.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.33.0 to 8.33.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.33.1/packages/parser)

Updates `typescript-eslint` from 8.33.0 to 8.33.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.33.1/packages/typescript-eslint)

Updates `@typescript-eslint/eslint-plugin` from 8.33.0 to 8.33.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.33.1/packages/eslint-plugin)

Updates `@typescript-eslint/parser` from 8.33.0 to 8.33.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.33.1/packages/parser)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.33.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.33.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.33.1
  dependency-type: indirect
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.33.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.33.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: eslint
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.33.1
  dependency-type: direct:development
  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-06-09 03:26:02 +02:00
891907390b website: bump the eslint group in /website with 4 updates (#14967)
Bumps the eslint group in /website with 4 updates: [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js), [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin), [eslint](https://github.com/eslint/eslint) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `@eslint/js` from 9.27.0 to 9.28.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/commits/v9.28.0/packages/js)

Updates `@typescript-eslint/eslint-plugin` from 8.32.1 to 8.33.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.33.1/packages/eslint-plugin)

Updates `eslint` from 9.27.0 to 9.28.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.27.0...v9.28.0)

Updates `typescript-eslint` from 8.32.1 to 8.33.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.33.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@eslint/js"
  dependency-version: 9.28.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.33.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: eslint
  dependency-version: 9.28.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: eslint
- dependency-name: typescript-eslint
  dependency-version: 8.33.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: eslint
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-09 03:14:20 +02:00
e1c47c0f00 website: bump @typescript-eslint/parser from 8.32.1 to 8.33.1 in /website (#14828)
* website: bump @typescript-eslint/parser in /website

Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.32.1 to 8.33.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.33.1/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.33.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* update dependabot groups for website

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-06-09 03:03:49 +02:00
0b71aa43d1 core, web: update translations (#14962)
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-06-09 03:01:25 +02:00
b4d26d5092 web: bump @sentry/browser from 9.24.0 to 9.25.1 in /web in the sentry group across 1 directory (#14865)
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 9.24.0 to 9.25.1
- [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/9.24.0...9.25.1)

---
updated-dependencies:
- dependency-name: "@sentry/browser"
  dependency-version: 9.25.1
  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-06-09 02:11:29 +02:00
8a9f6fb1ce core, web: update translations (#14954)
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-06-09 02:11:11 +02:00
355f302cb7 lifecycle/aws: bump aws-cdk from 2.1017.1 to 2.1018.0 in /lifecycle/aws (#14939)
Bumps [aws-cdk](https://github.com/aws/aws-cdk-cli/tree/HEAD/packages/aws-cdk) from 2.1017.1 to 2.1018.0.
- [Release notes](https://github.com/aws/aws-cdk-cli/releases)
- [Commits](https://github.com/aws/aws-cdk-cli/commits/aws-cdk@v2.1018.0/packages/aws-cdk)

---
updated-dependencies:
- dependency-name: aws-cdk
  dependency-version: 2.1018.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-06-09 02:10:16 +02:00
11666f5658 core: bump golang.org/x/sync from 0.14.0 to 0.15.0 (#14936)
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.14.0 to 0.15.0.
- [Commits](https://github.com/golang/sync/compare/v0.14.0...v0.15.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sync
  dependency-version: 0.15.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-06-09 02:09:41 +02:00
d54fe15511 website: bump the build group across 1 directory with 9 updates (#14937)
Bumps the build group with 9 updates in the /website directory:

| Package | From | To |
| --- | --- | --- |
| [@rspack/binding-darwin-arm64](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.11` | `1.3.15` |
| [@rspack/binding-linux-arm64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.11` | `1.3.15` |
| [@rspack/binding-linux-x64-gnu](https://github.com/web-infra-dev/rspack/tree/HEAD/packages/rspack) | `1.3.11` | `1.3.15` |
| [@swc/core-darwin-arm64](https://github.com/swc-project/swc) | `1.11.29` | `1.11.31` |
| [@swc/core-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.29` | `1.11.31` |
| [@swc/core-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.29` | `1.11.31` |
| [@swc/html-darwin-arm64](https://github.com/swc-project/swc) | `1.11.29` | `1.11.31` |
| [@swc/html-linux-arm64-gnu](https://github.com/swc-project/swc) | `1.11.29` | `1.11.31` |
| [@swc/html-linux-x64-gnu](https://github.com/swc-project/swc) | `1.11.29` | `1.11.31` |



Updates `@rspack/binding-darwin-arm64` from 1.3.11 to 1.3.15
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.15/packages/rspack)

Updates `@rspack/binding-linux-arm64-gnu` from 1.3.11 to 1.3.15
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.15/packages/rspack)

Updates `@rspack/binding-linux-x64-gnu` from 1.3.11 to 1.3.15
- [Release notes](https://github.com/web-infra-dev/rspack/releases)
- [Commits](https://github.com/web-infra-dev/rspack/commits/v1.3.15/packages/rspack)

Updates `@swc/core-darwin-arm64` from 1.11.29 to 1.11.31
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.29...v1.11.31)

Updates `@swc/core-linux-arm64-gnu` from 1.11.29 to 1.11.31
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.29...v1.11.31)

Updates `@swc/core-linux-x64-gnu` from 1.11.29 to 1.11.31
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.29...v1.11.31)

Updates `@swc/html-darwin-arm64` from 1.11.29 to 1.11.31
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.29...v1.11.31)

Updates `@swc/html-linux-arm64-gnu` from 1.11.29 to 1.11.31
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.29...v1.11.31)

Updates `@swc/html-linux-x64-gnu` from 1.11.29 to 1.11.31
- [Release notes](https://github.com/swc-project/swc/releases)
- [Changelog](https://github.com/swc-project/swc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/swc-project/swc/compare/v1.11.29...v1.11.31)

---
updated-dependencies:
- dependency-name: "@rspack/binding-darwin-arm64"
  dependency-version: 1.3.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-arm64-gnu"
  dependency-version: 1.3.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@rspack/binding-linux-x64-gnu"
  dependency-version: 1.3.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-darwin-arm64"
  dependency-version: 1.11.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-linux-arm64-gnu"
  dependency-version: 1.11.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/core-linux-x64-gnu"
  dependency-version: 1.11.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-darwin-arm64"
  dependency-version: 1.11.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-linux-arm64-gnu"
  dependency-version: 1.11.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
- dependency-name: "@swc/html-linux-x64-gnu"
  dependency-version: 1.11.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: build
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-09 02:06:18 +02:00
baa4deda99 tests/e2e: WebAuthn E2E tests (#14461)
* a start of webauthn testing

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

* separate file, just do it via localhost

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

* remove unneeded stuff

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

* add auth and sfe tests

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

* auto select device challenge if only 1

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

* revert a thing

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-07 09:31:16 +02:00
b7417e77c7 outposts: remove duplicate startup/setup code, add pyroscope, make sentry not reconfigure every time (#14724)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-07 03:01:00 +02:00
a01bb551d0 web/standards: fix boolean attribute abuse (#14662)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* web/maintenance: correct the usage of boolean (false) attributes

## What

Just cleaning up a bad habit; we have a lot of `?attribute=${true|false}` (or, more alarmingly,
`.attribute=${true|false}`.  These should just be `attribute` or be missing; anything else is
unnecessary.

Where the attribute is `true` by default, no changes have been made; there are only a few of them,
and they require re-working of the logic to assist with the changes. Booleans should never be `true` by
default, and if you absolutely cannot find an alternative phrasing that makes having them be `false`
by default a valid choice, they should be `reflect: true` to make their presence visible to screen
readers and debuggers.

## Why

Removing non-standard HTML uses from web components matches our programming standards and is an
important step toward the Authentik Elements NPM package, as well as the Schema-Driven Forms update.

## Boring excessive detail.

Because there are literally hundreds of changes, I've documented the boring ones here.

Changes that do *not* meet the basic criteria of "made the component comply with the standards" are
commented in the PR.

Here are all the Boolean property declarations in the system, delta the ones that declare `= true`;
those are documented at the bottom of this commit, and are not addressed in this PR.  This
information is included to guide your decision making.  The second block, below, documents the
actual changes made to component declarations throughout our code.  The third block, at the bottom,
documents changes not made due to logic and effort constraints.

```
components/ak-switch-input.ts:
    @property({ type: Boolean })
    checked: boolean = false;
--
components/ak-switch-input.ts:
    @property({ type: Boolean })
    required = false;
--
components/ak-file-input.ts:
    @property({ type: Boolean })
    required = false;
--
components/HorizontalLightComponent.ts:
    @property({ type: Boolean })
    required = false;
--
components/ak-multi-select.ts:
    @property({ type: Boolean })
    required = false;
--
elements/TreeView.ts:
    @property({ type: Boolean })
    open = false;
--
components/ak-status-label.ts:
    @property({ type: Boolean })
    good = false;
--
components/ak-status-label.ts:
    @property({ type: Boolean })
    compact = false;
--
elements/CodeMirror.ts:
    @property({ type: Boolean })
    readOnly = false;
--
elements/buttons/ModalButton.ts:
    @property({ type: Boolean })
    open = false;
--
elements/EmptyState.ts:
    @property({ type: Boolean })
    fullHeight = false;
--
elements/Tabs.ts:
    @property({ type: Boolean })
    vertical = false;
--
elements/ak-checkbox-group/ak-checkbox-group.ts:
    @property({ type: Boolean })
    required = false;
--
elements/Label.ts:
    @property({ type: Boolean })
    compact = false;
--
elements/forms/FormGroup.ts:
    @property({ type: Boolean, reflect: true })
    expanded = false;
--
elements/Expand.ts:
    @property({ type: Boolean })
    expanded = false;
--
elements/forms/HorizontalFormElement.ts:
    @property({ type: Boolean })
    required = false;
--
elements/forms/HorizontalFormElement.ts:
    @property({ type: Boolean })
    slugMode = false;
--
elements/forms/SearchSelect/ak-portal.ts:
    @property({ type: Boolean, reflect: true })
    open = false;
--
elements/Alert.ts:
    @property({ type: Boolean })
    inline = false;
--
elements/forms/SearchSelect/ak-search-select-view.ts:
    @property({ type: Boolean, reflect: true })
    open = false;
--
elements/forms/SearchSelect/ak-search-select-view.ts:
    @property({ type: Boolean })
    blankable = false;
--
elements/sidebar/SidebarItem.ts:
    @property({ type: Boolean })
    expanded = false;
--
admin/stages/StageWizard.ts:
    @property({ type: Boolean })
    showBindingPage = false;
--
elements/forms/FormElement.ts:
    @property({ type: Boolean })
    required = false;
--
admin/common/ak-flow-search/FlowSearch.ts:
    @property({ type: Boolean })
    required?: boolean = false;
--
admin/applications/ProviderSelectModal.ts:
    @property({ type: Boolean })
    backchannel = false;
--
elements/forms/SearchSelect/SearchSelect.ts:
    @property({ type: Boolean })
    blankable = false;
--
admin/applications/components/ak-provider-search-input.ts:
    @property({ type: Boolean })
    required = false;
--
admin/applications/components/ak-provider-search-input.ts:
    @property({ type: Boolean })
    blankable = false;
--
admin/applications/components/ak-backchannel-input.ts:
    @property({ type: Boolean })
    required = false;
--
admin/policies/PolicyWizard.ts:
    @property({ type: Boolean })
    showBindingPage = false;
```

The attribute 'required' is an HTML native, and is false by default.

Here are all the change pairs around HTML attrbutes:

```
$ git diff | rg -A 1 '\?(backchannel|blankable|checked|compact|expanded|fullHeight|good|inline|open|readOnly|required|showBindingPage|slugMode|vertical)\b'

-                ?required=${true}
+                required

-                    <ak-provider-select-table ?backchannel=${true} .confirm=${this.confirm}>
+                    <ak-provider-select-table backchannel .confirm=${this.confirm}>

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${false}

-                    ?required=${true}
+                    required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                                  ?blankable=${true}
+                                  blankable

-                        ?required=${true}
+                        required

-                ?blankable=${true}
+                blankable

-                ?blankable=${true}
+                blankable

-            ?required=${true}
+            required

-            ?required=${true}
+            required

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-        return html` <ak-form-element-horizontal label=${msg("Name")} name="name" ?required=${true}>
+        return html` <ak-form-element-horizontal label=${msg("Name")} name="name" required>

-                ?required=${true}
+                required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                    ?blankable=${true}
+                    blankable

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("Severity")} ?required=${true} name="severity">
+            <ak-form-element-horizontal label=${msg("Severity")} required name="severity">

-                        ?showBindingPage=${true}
+                        showBindingPage

-                ?showBindingPage=${true}
+                showBindingPage

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Title")} ?required=${true} name="title">
+            <ak-form-element-horizontal label=${msg("Title")} required name="title">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            ?required=${true}
+            required

-            <ak-form-element-horizontal label=${msg("Stage")} ?required=${true} name="stage">
+            <ak-form-element-horizontal label=${msg("Stage")} required name="stage">

-            <ak-form-element-horizontal label=${msg("Order")} ?required=${true} name="order">
+            <ak-form-element-horizontal label=${msg("Order")} required name="order">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                    ?blankable=${true}
+                    blankable

-                ?required=${true}
+                required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Type")} ?required=${true} name="type">
+            <ak-form-element-horizontal label=${msg("Type")} required name="type">

-                    ?blankable=${true}
+                    blankable

-                        <ak-label color=${PFColor.Green} ?compact=${true}>
+                        <ak-label color=${PFColor.Green} compact>

-                            ? html`<ak-label color=${PFColor.Red} ?compact=${true}
+                            ? html`<ak-label color=${PFColor.Red} compact

-                            : html`<ak-label color=${PFColor.Green} ?compact=${true}
+                            : html`<ak-label color=${PFColor.Green} compact

-                    ? html`<ak-label color=${PFColor.Orange} ?compact=${true}>
+                    ? html`<ak-label color=${PFColor.Orange} compact>

-                    : html`<ak-label color=${PFColor.Green} ?compact=${true}>
+                    : html`<ak-label color=${PFColor.Green} compact>

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Docker URL")} ?required=${true} name="url">
+            <ak-form-element-horizontal label=${msg("Docker URL")} required name="url">

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?showBindingPage=${true}
+                        showBindingPage

-                      ?showBindingPage=${true}
+                      showBindingPage

-                            ?blankable=${true}
+                            blankable

-                            ?blankable=${true}
+                            blankable

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Order")} ?required=${true} name="order">
+            <ak-form-element-horizontal label=${msg("Order")} required name="order">

-            <ak-form-element-horizontal label=${msg("Timeout")} ?required=${true} name="timeout">
+            <ak-form-element-horizontal label=${msg("Timeout")} required name="timeout">

-                    ? html`<ak-label color=${PFColor.Green} ?compact=${true}>
+                    ? html`<ak-label color=${PFColor.Green} compact>

-                    : html`<ak-label color=${PFColor.Orange} ?compact=${true}>
+                    : html`<ak-label color=${PFColor.Orange} compact>

-        return html`<ak-form-element-horizontal label=${msg("User")} ?required=${true} name="user">
+        return html`<ak-form-element-horizontal label=${msg("User")} required name="user">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                            ?blankable=${true}
+                            blankable

-                            ?blankable=${true}
+                            blankable

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                      ?readOnly=${true}
+                      readOnly

-            return html`<ak-empty-state loading ?fullHeight=${true}></ak-empty-state>`;
+            return html`<ak-empty-state loading fullHeight></ak-empty-state>`;

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                            ?blankable=${true}
+                            blankable

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                    ?required=${true}
+                    required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                            ?blankable=${true}
+                            blankable

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-            ?required=${true}
+            required

-                    ?required=${true}
+                    required

-                                        ?blankable=${true}
+                                        blankable

-            <ak-form-element-horizontal label=${msg("Name")} name="name" ?required=${true}>
+            <ak-form-element-horizontal label=${msg("Name")} name="name" required>

-            <ak-form-element-horizontal label=${msg("Protocol")} ?required=${true} name="protocol">
+            <ak-form-element-horizontal label=${msg("Protocol")} required name="protocol">

-            <ak-form-element-horizontal label=${msg("Host")} name="host" ?required=${true}>
+            <ak-form-element-horizontal label=${msg("Host")} name="host" required>

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                    ?required=${false}

-                        ?blankable=${true}
+                        blankable

-                        ?blankable=${true}
+                        blankable

-        return html`<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html`<ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                                      ?readOnly=${true}
+                                      readOnly

-                                    ?blankable=${true}
+                                    blankable

-        return html`<ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html`<ak-form-element-horizontal label=${msg("Name")} required name="name">

-                    : html`<ak-label color=${PFColor.Orange} ?compact=${true}>
+                    : html`<ak-label color=${PFColor.Orange} compact>

-                <ak-label color=${PFColor.Grey} ?compact=${true}> ${msg("Built-in")}</ak-label>
+                <ak-label color=${PFColor.Grey} compact> ${msg("Built-in")}</ak-label>

-            return html`<ak-empty-state loading ?fullHeight=${true}></ak-empty-state>`;
+            return html`<ak-empty-state loading fullHeight></ak-empty-state>`;

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${false}>
+            <ak-form-group>

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                            ?blankable=${true}
+                            blankable

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                ?required=${true}
+                required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-                        ?required=${true}
+                        required

-                                ?readOnly=${true}
+                                readOnly

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Slug")} ?required=${true} name="slug">
+            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">

-            <ak-form-group ?expanded=${true}>
+            <ak-form-group expanded>

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                <ak-form-element-horizontal label=${msg("SMTP Host")} ?required=${true} name="host">
+                <ak-form-element-horizontal label=${msg("SMTP Host")} required name="host">

-                <ak-form-element-horizontal label=${msg("SMTP Port")} ?required=${true} name="port">
+                <ak-form-element-horizontal label=${msg("SMTP Port")} required name="port">

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                ?required=${true}
+                required

-                    ?blankable=${true}
+                    blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        <ak-alert ?inline=${true}>
+                        <ak-alert inline>

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                    <ak-form-element-horizontal label=${msg("Mode")} ?required=${true} name="mode">
+                    <ak-form-element-horizontal label=${msg("Mode")} required name="mode">

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                <ak-form-element-horizontal label=${msg("SMTP Host")} ?required=${true} name="host">
+                <ak-form-element-horizontal label=${msg("SMTP Host")} required name="host">

-                <ak-form-element-horizontal label=${msg("SMTP Port")} ?required=${true} name="port">
+                <ak-form-element-horizontal label=${msg("SMTP Port")} required name="port">

-                    ?required=${true}
+                    required

-                    ?required=${true}
+                    required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                ?slugMode=${true}
+                slugMode

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("Expires")} ?required=${true} name="expires">
+            <ak-form-element-horizontal label=${msg("Expires")} required name="expires">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                            ?blankable=${true}
+                            blankable

-                        ?required=${true}
+                        required

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Field Key")} ?required=${true} name="fieldKey">
+            <ak-form-element-horizontal label=${msg("Field Key")} required name="fieldKey">

-            <ak-form-element-horizontal label=${msg("Label")} ?required=${true} name="label">
+            <ak-form-element-horizontal label=${msg("Label")} required name="label">

-            <ak-form-element-horizontal label=${msg("Type")} ?required=${true} name="type">
+            <ak-form-element-horizontal label=${msg("Type")} required name="type">

-            <ak-form-element-horizontal label=${msg("Order")} ?required=${true} name="order">
+            <ak-form-element-horizontal label=${msg("Order")} required name="order">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Source")} ?required=${true} name="source">
+            <ak-form-element-horizontal label=${msg("Source")} required name="source">

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                        ?required=${true}
+                        required

-                        <ak-alert ?inline=${true}>
+                        <ak-alert inline>

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-                        ?required=${true}
+                        required

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-            <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+            <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                            ?blankable=${true}
+                            blankable

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("User")} ?required=${true} name="user">
+            <ak-form-element-horizontal label=${msg("User")} required name="user">

-            <ak-form-element-horizontal label=${msg("Intent")} ?required=${true} name="intent">
+            <ak-form-element-horizontal label=${msg("Intent")} required name="intent">

-                ?required=${true}
+                required

-                    <input class="pf-c-switch__input" type="checkbox" ?checked=${true} />
+                    <input class="pf-c-switch__input" type="checkbox" checked />

-                    <input class="pf-c-switch__input" type="checkbox" ?checked=${true} />
+                    <input class="pf-c-switch__input" type="checkbox" checked />

-                ?required=${true}
+                required

-            <ak-form-element-horizontal label=${msg("User type")} ?required=${true} name="type">
+            <ak-form-element-horizontal label=${msg("User type")} required name="type">

-            <ak-form-element-horizontal label=${msg("Path")} ?required=${true} name="path">
+            <ak-form-element-horizontal label=${msg("Path")} required name="path">

-            ?required=${true}
+            required

-            ?required=${true}
+            required

-            <ak-tabs pageIdentifier="userCredentialsTokens" ?vertical=${true}>
+            <ak-tabs pageIdentifier="userCredentialsTokens" vertical>

-                <ak-status-label ?good=${true}></ak-status-label>
+                <ak-status-label good></ak-status-label>

-                    ?open=${true}
+                    open

-                ?blankable=${true}
+                blankable

-                <ak-tabs ?vertical="${true}">
+                <ak-tabs vertical>

-        return html` <ak-form-element-horizontal label=${msg("Name")} ?required=${true} name="name">
+        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">

-                ?required=${true}
+                required

```

The following issues are the `true` by default Booleans.  As mentioned, these are **not addressed** by this PR.

```
elements/table/Table.ts::
    @property({ type: Boolean })
    paginated = true;

elements/forms/ModalForm.ts::
    @property({ type: Boolean })
    closeAfterSuccessfulSubmit = true;

elements/forms/ModalForm.ts::
    @property({ type: Boolean })
    showSubmitButton = true;

elements/CodeMirror.ts::
    @property({ type: Boolean })
    parseValue = true;

elements/LoadingOverlay.ts::
    @property({ type: Boolean })
    loading = true;

admin/stages/authenticator_validate/AuthenticatorValidateStageForm.ts::
    @property({ type: Boolean })
    showConfigurationStages = true;

elements/user/sources/SourceSettings.ts::
    @property({ type: Boolean })
    canConnect = true;

admin/outposts/OutpostHealthSimple.ts::
    @property({ attribute: false })
    showVersion = true;

elements/wizard/Wizard.ts::
    @property({ type: Boolean })
    canCancel = true;

elements/wizard/Wizard.ts::
    @property({ type: Boolean })
    canBack = true;
```

* Prettier had opinions.

* Caught during code review.

* Merged incorrectly; not sure what went wrong, but this re-applies the removal of the  syntax from the current LDAPSourceForm.ts from  to this branch.
2025-06-06 23:06:25 +00:00
9a03bdeaf1 web/maintenance: remove writeOnly hacks from Form and HorizontalFormElement (#14649)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* web/standards: use attribute naming scheme for attributes

## What

Renamed the 'inputHint' attribute to 'input-hint', because it is an attribute, not a property.
Properties are camelCased, but attributes are kebab-cased.

Updated all instances where this appears with the usual magic:

```
$ perl -pi.bak -e 's/inputHint="code"/input-hint="code"/' $(rg -l 'inputHint="code"')
```

This fix is in preparation for both the Patternfly 5 project and the Schema-Driven Forms project.

* web/maintenance: remove `writeOnly` hacks from Form and HorizontalFormElement

## What

The `writeOnly` hack substituted an obscuring, read-only field for secret keys and passwords that an
admin should never be able to see/read, only *write*, but allowed the user to click on and replace
the key or password. The hack performed this substitution within `HorizontalFormElement` and
dispersed a flag throughout the code to enforce it. Another hack within `Form` directed the API to
not update / write changes to that field if the field had never been activated.

This commit replaces the `writeOnly` hack with a pair of purpose-built components,
`ak-private-text-input` and `ak-private-textarea-input`, that perform the exact same functionality
but without having to involve the HorizontalFormElement, which really should just be layout and
generic functionality.  It also replaces all the `writeOnly` hackery in Form with a simple
`doNotProcess` flag, which extends and genericizes this capability to any and all input fields.

The only major protocol change is that `?writeOnly` was a *positive* flag; you controlled it by
saying `this.instance !== undefined`; `?revealed` is a *positive* flog; you reveal the working input
field when `this.instance === undefined`.

It is not necessary to specify the monospace, autocomplete, and spell-check features; those are
enabled or disabled automatically when the `input-hint="code"` flag is passed.

## Why

Removing special cases from processing code is an important step toward the Authentik Elements NPM
package, as well as the Schema-Driven Forms update.

## Note

This is actually a very significant change; this is important functionality that I have hand-tested
quite a bit, but could wish for automated testing that also checks the database back-end to ensure
the fixes made write the keys and passwords as required. Checking the back-end directly is important
since these fields are never re-sent to the front-end after being saved!

Things like `placeholder`, `required`, and getting the `name`, `label` or `help` are all issues very
subject to Last-Line Effect, so give this the hairiest eyeball you've got, please.

* Found a few small things, like a missing import that might have broken something.

* web/admin: Update `private-text` field to pass new linting requirement.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes
2025-06-06 15:11:49 -07:00
6b530ff764 web/admin: use attribute naming scheme for attributes (#14644)
web/standards: use attribute naming scheme for attributes

## What

Renamed the 'inputHint' attribute to 'input-hint', because it is an attribute, not a property.
Properties are camelCased, but attributes are kebab-cased.

Updated all instances where this appears with the usual magic:

```
$ perl -pi.bak -e 's/inputHint="code"/input-hint="code"/' $(rg -l 'inputHint="code"')
```

This fix is in preparation for both the Patternfly 5 project and the Schema-Driven Forms project.

* Revision: You almost certainly do NOT want every field to be reflected.  Booleans are okay, especially for fields that may be changed internally but need to be read by screen-readers, sunch as 'hidden' or 'invalid'.  But if a field is a string or a number and has a default value, you do not want it to be reflected.
2025-06-06 14:49:47 -07:00
e77a3241f0 core: bump django from 5.1.9 to 5.1.10 (#14951)
bump django to 5.1.10
2025-06-06 20:42:15 +02:00
a718ff2617 website/docs: add 2025.6.1 release notes (#14948) 2025-06-06 15:28:10 +00:00
969fa82b7f root: remove /if/help (#14929)
Co-authored-by: Teffen Ellis <teffen@sister.software>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-06-06 17:21:07 +02:00
bb47a70310 core, web: update translations (#14933)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-06-06 14:58:30 +02:00
a306cecb73 providers/proxy: add option to override host header with property mappings (#14927) 2025-06-06 14:54:59 +02:00
760879c3db website/integrations: fix webfinger link in tailscale doc (#14942)
* Update index.md

Modify the link in webfinger

Signed-off-by: Bisn <b@bisn.cn>

* Update website/integrations/services/tailscale/index.md

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

---------

Signed-off-by: Bisn <b@bisn.cn>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-06-06 11:27:45 +00:00
ef5d3580e8 web/admin: make message container bottom aligned for admin interface (#14816)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-06 01:09:46 +02:00
d14b480926 web/user: fix user settings flow not loading (#14911)
* web/user: fix user settings flow not loading

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

* fix

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

* unrelated fix: fix select caret color in dark theme

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
2025-06-05 23:26:06 +02:00
d9c79558b1 website/docs: fix outdated and incorrect example kubernetes deployment (#14928)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-06-05 21:09:56 +02:00
ed20d1b6aa docusaurus-config: Update deps, colors. (#14796) 2025-06-05 14:00:06 -04:00
f03ee47bb3 admin: only run update checks in the default tenant (#14874) 2025-06-05 13:51:27 +00:00
396366a99a translate: Updates for file locale/en/LC_MESSAGES/django.po in fr (#14923)
Translate locale/en/LC_MESSAGES/django.po in fr

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'fr'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-05 13:42:38 +00:00
13d2df3bf6 core: bump astral-sh/uv from 0.7.10 to 0.7.11 (#14918)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-05 12:33:17 +00:00
d65b8ae029 providers/proxy: set_oauth_defaults in reconcile instead of task (#14875) 2025-06-05 14:28:18 +02:00
296031c5df *: use ManagedAppConfig everywhere (#14839) 2025-06-05 14:28:11 +02:00
452639d6d2 tenants: fix tenant aware celery scheduler (#14921) 2025-06-05 12:20:01 +00:00
465ccb7ab9 core, web: update translations (#14910)
Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com>
2025-06-05 14:11:00 +02:00
fdce812ddc core: bump goauthentik.io/api/v3 from 3.2025041.4 to 3.2025060.1 (#14919)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-05 14:05:29 +02:00
005da84dbe translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#14915)
Translate locale/en/LC_MESSAGES/django.po in zh_CN

100% translated source file: 'locale/en/LC_MESSAGES/django.po'
on 'zh_CN'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-05 14:04:46 +02:00
b098971718 translate: Updates for file web/xliff/en.xlf in zh_CN (#14916)
Translate web/xliff/en.xlf in zh_CN

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

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-05 14:04:27 +02:00
147bfa3f97 translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#14914)
Translate django.po in zh-Hans

100% translated source file: 'django.po'
on 'zh-Hans'.

Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2025-06-05 14:04:22 +02:00
fc5f91ea29 website/integrations: improve komodo config verification (#14849)
### What

Some wording improvements to the Komodo configuration verification. Not sure I like it, but I found parts of the old wording a little strange

Signed-off-by: Dominic R <dominic@sdko.org>
2025-06-05 10:32:51 +01:00
e29961b088 website/integrations: fix komodo provider url (#14912)
* fix KOMODO_OIDC_PROVIDER uri docs

* Update website/integrations/services/komodo/index.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Dylan Gottlieb <dylangottlieb@users.noreply.github.com>

---------

Signed-off-by: Dylan Gottlieb <dylangottlieb@users.noreply.github.com>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-06-05 09:30:47 +00:00
52ca70d6bb website/docs: fix note at end of rac credentials prompt (#14909)
* Fixes note section at end of document

* tweak to bump build

---------

Co-authored-by: Tana M Berry <tana@goauthentik.io>
2025-06-04 17:12:40 -05:00
42cb9cb531 website/docs: add credentials prompt for rac doc (#14840)
* Adds document

* Typo

* Clarified RAC endpoint sentence based on Tana's suggestion.

* Update website/docs/add-secure-apps/providers/rac/rac_credentials_prompt.md

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

* Small wording improvements

* Added connection security type information

* A word

* Added to sidebar

* Update website/docs/add-secure-apps/providers/rac/rac_credentials_prompt.md

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

* Applied suggestions from Tana

* Update website/docs/add-secure-apps/providers/rac/rac_credentials_prompt.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-06-04 20:40:43 +00:00
837cd3bcb0 core: bump redis from 6.0.0 to v6.2.0 (#14895) 2025-06-04 20:17:09 +02:00
53a9c147cd core: bump protobuf from 6.30.2 to v6.31.1 (#14894) 2025-06-04 20:16:54 +02:00
d7f166f260 core: bump click from 8.2.0 to v8.2.1 (#14881) 2025-06-04 20:16:45 +02:00
8ce9343457 core: bump uritemplate from 4.1.1 to v4.2.0 (#14902) 2025-06-04 15:11:21 -03:00
6af27d0c90 core: bump azure-identity from 1.22.0 to v1.23.0 (#14879) 2025-06-04 19:36:46 +02:00
6fd48ccf9b core: bump durationpy from 0.9 to v0.10 (#14883) 2025-06-04 19:36:27 +02:00
5567967848 core: bump prometheus-client from 0.21.1 to v0.22.1 (#14893) 2025-06-04 19:36:14 +02:00
090a377c78 core: bump jsonschema from 4.23.0 to v4.24.0 (#14887) 2025-06-04 19:35:59 +02:00
3e7bda87ea core: bump std-uritemplate from 2.0.3 to v2.0.5 (#14898) 2025-06-04 19:35:47 +02:00
f22a539b50 core: bump aiohttp from 3.11.18 to v3.12.8 (#14878) 2025-06-04 19:35:33 +02:00
54811b2b05 core: bump pluggy from 1.5.0 to v1.6.0 (#14892) 2025-06-04 19:35:19 +02:00
35263f71ee core: bump msgraph-core from 1.3.3 to v1.3.4 (#14889) 2025-06-04 19:35:03 +02:00
f0bc809389 core: bump daphne from 4.1.2 to v4.2.0 (#14882) 2025-06-04 19:34:47 +02:00
75b45312ee core: bump typing-extensions from 4.13.2 to v4.14.0 (#14900) 2025-06-04 19:34:34 +02:00
e4eeb43f8a core: bump google-api-core from 2.24.2 to v2.25.0 (#14885) 2025-06-04 19:34:19 +02:00
04850e5c84 core: bump rpds-py from 0.24.0 to v0.25.1 (#14896) 2025-06-04 19:34:07 +02:00
fbae9f2f34 core: bump google-auth from 2.40.1 to v2.40.2 (#14886) 2025-06-04 19:33:54 +02:00
3c966d9252 core: bump setuptools from 80.4.0 to v80.9.0 (#14897) 2025-06-04 19:33:38 +02:00
9f1cef18b2 core: bump frozenlist from 1.6.0 to v1.6.2 (#14884) 2025-06-04 19:33:23 +02:00
aae20dc399 core: bump multidict from 6.4.3 to v6.4.4 (#14890) 2025-06-04 19:33:12 +02:00
4dc43b788a core: bump boto3 from 1.38.13 to v1.38.29 (#14880) 2025-06-04 19:32:57 +02:00
a3b40a97ef core: bump opentelemetry-api from 1.33.0 to v1.34.0 (#14891) 2025-06-04 19:32:43 +02:00
852106f02f core: bump typing-inspection from 0.4.0 to v0.4.1 (#14901) 2025-06-04 19:32:32 +02:00
7a34428aff core: bump zipp from 3.21.0 to v3.22.0 (#14903) 2025-06-04 19:32:18 +02:00
c1b6a681a0 web: bump API Client version (#14907)
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-06-04 16:57:58 +00:00
472 changed files with 14684 additions and 13934 deletions

View File

@ -1,16 +1,16 @@
[bumpversion]
current_version = 2025.6.0
current_version = 2025.6.2
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
serialize =
serialize =
{major}.{minor}.{patch}-{rc_t}{rc_n}
{major}.{minor}.{patch}
message = release: {new_version}
tag_name = version/{new_version}
[bumpversion:part:rc_t]
values =
values =
rc
final
optional_value = final

View File

@ -5,8 +5,10 @@ dist/**
build/**
build_docs/**
*Dockerfile
**/*Dockerfile
blueprints/local
.git
!gen-ts-api/node_modules
!gen-ts-api/dist/**
!gen-go-api/
.venv

View File

@ -100,6 +100,13 @@ updates:
goauthentik:
patterns:
- "@goauthentik/*"
eslint:
patterns:
- "@eslint/*"
- "@typescript-eslint/*"
- "eslint-*"
- "eslint"
- "typescript-eslint"
- package-ecosystem: npm
directory: "/lifecycle/aws"
schedule:

View File

@ -202,7 +202,7 @@ jobs:
uses: actions/cache@v4
with:
path: web/dist
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
key: ${{ runner.os }}-web-${{ hashFiles('web/package-lock.json', 'package-lock.json', 'web/src/**', 'web/packages/sfe/src/**') }}-b
- name: prepare web ui
if: steps.cache-web.outputs.cache-hit != 'true'
working-directory: web

View File

@ -41,32 +41,60 @@ jobs:
- name: test
working-directory: website/
run: npm test
build:
build-container:
runs-on: ubuntu-latest
name: ${{ matrix.job }}
strategy:
fail-fast: false
matrix:
job:
- build
permissions:
# Needed to upload container images to ghcr.io
packages: write
# Needed for attestation
id-token: write
attestations: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: website/package.json
cache: "npm"
cache-dependency-path: website/package-lock.json
- working-directory: website/
run: npm ci
- name: build
working-directory: website/
run: npm run ${{ matrix.job }}
ref: ${{ github.event.pull_request.head.sha }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.6.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
with:
image-name: ghcr.io/goauthentik/dev-docs
- name: Login to Container Registry
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker Image
id: push
uses: docker/build-push-action@v6
with:
tags: ${{ steps.ev.outputs.imageTags }}
file: website/Dockerfile
push: ${{ steps.ev.outputs.shouldPush == 'true' }}
platforms: linux/amd64,linux/arm64
context: .
cache-from: type=registry,ref=ghcr.io/goauthentik/dev-docs:buildcache
cache-to: ${{ steps.ev.outputs.shouldPush == 'true' && 'type=registry,ref=ghcr.io/goauthentik/dev-docs:buildcache,mode=max' || '' }}
- uses: actions/attest-build-provenance@v2
id: attest
if: ${{ steps.ev.outputs.shouldPush == 'true' }}
with:
subject-name: ${{ steps.ev.outputs.attestImageNames }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
ci-website-mark:
if: always()
needs:
- lint
- test
- build
- build-container
runs-on: ubuntu-latest
steps:
- uses: re-actors/alls-green@release/v1

View File

@ -20,6 +20,49 @@ jobs:
release: true
registry_dockerhub: true
registry_ghcr: true
build-docs:
runs-on: ubuntu-latest
permissions:
# Needed to upload container images to ghcr.io
packages: write
# Needed for attestation
id-token: write
attestations: write
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.6.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: prepare variables
uses: ./.github/actions/docker-push-variables
id: ev
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
with:
image-name: ghcr.io/goauthentik/docs
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Docker Image
id: push
uses: docker/build-push-action@v6
with:
tags: ${{ steps.ev.outputs.imageTags }}
file: website/Dockerfile
push: true
platforms: linux/amd64,linux/arm64
context: .
- uses: actions/attest-build-provenance@v2
id: attest
if: true
with:
subject-name: ${{ steps.ev.outputs.attestImageNames }}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
build-outpost:
runs-on: ubuntu-latest
permissions:
@ -193,6 +236,6 @@ jobs:
SENTRY_ORG: authentik-security-inc
SENTRY_PROJECT: authentik
with:
version: authentik@${{ steps.ev.outputs.version }}
release: authentik@${{ steps.ev.outputs.version }}
sourcemaps: "./web/dist"
url_prefix: "~/static/dist"

View File

@ -1,26 +1,7 @@
# syntax=docker/dockerfile:1
# Stage 1: Build website
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24 AS website-builder
ENV NODE_ENV=production
WORKDIR /work/website
RUN --mount=type=bind,target=/work/website/package.json,src=./website/package.json \
--mount=type=bind,target=/work/website/package-lock.json,src=./website/package-lock.json \
--mount=type=cache,id=npm-website,sharing=shared,target=/root/.npm \
npm ci --include=dev
COPY ./website /work/website/
COPY ./blueprints /work/blueprints/
COPY ./schema.yml /work/
COPY ./SECURITY.md /work/
RUN npm run build-bundled
# Stage 2: Build webui
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24 AS web-builder
# Stage 1: Build webui
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24-slim AS node-builder
ARG GIT_BUILD_HASH
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
@ -32,7 +13,7 @@ RUN --mount=type=bind,target=/work/web/package.json,src=./web/package.json \
--mount=type=bind,target=/work/web/package-lock.json,src=./web/package-lock.json \
--mount=type=bind,target=/work/web/packages/sfe/package.json,src=./web/packages/sfe/package.json \
--mount=type=bind,target=/work/web/scripts,src=./web/scripts \
--mount=type=cache,id=npm-web,sharing=shared,target=/root/.npm \
--mount=type=cache,id=npm-ak,sharing=shared,target=/root/.npm \
npm ci --include=dev
COPY ./package.json /work
@ -43,7 +24,7 @@ COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
RUN npm run build && \
npm run build:sfe
# Stage 3: Build go proxy
# Stage 2: Build go proxy
FROM --platform=${BUILDPLATFORM} docker.io/library/golang:1.24-bookworm AS go-builder
ARG TARGETOS
@ -68,8 +49,8 @@ RUN --mount=type=bind,target=/go/src/goauthentik.io/go.mod,src=./go.mod \
COPY ./cmd /go/src/goauthentik.io/cmd
COPY ./authentik/lib /go/src/goauthentik.io/authentik/lib
COPY ./web/static.go /go/src/goauthentik.io/web/static.go
COPY --from=web-builder /work/web/robots.txt /go/src/goauthentik.io/web/robots.txt
COPY --from=web-builder /work/web/security.txt /go/src/goauthentik.io/web/security.txt
COPY --from=node-builder /work/web/robots.txt /go/src/goauthentik.io/web/robots.txt
COPY --from=node-builder /work/web/security.txt /go/src/goauthentik.io/web/security.txt
COPY ./internal /go/src/goauthentik.io/internal
COPY ./go.mod /go/src/goauthentik.io/go.mod
COPY ./go.sum /go/src/goauthentik.io/go.sum
@ -80,7 +61,7 @@ RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \
CGO_ENABLED=1 GOFIPS140=latest GOARM="${TARGETVARIANT#v}" \
go build -o /go/authentik ./cmd/server
# Stage 4: MaxMind GeoIP
# Stage 3: MaxMind GeoIP
FROM --platform=${BUILDPLATFORM} ghcr.io/maxmind/geoipupdate:v7.1.0 AS geoip
ENV GEOIPUPDATE_EDITION_IDS="GeoLite2-City GeoLite2-ASN"
@ -93,10 +74,10 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
mkdir -p /usr/share/GeoIP && \
/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 5: Download uv
FROM ghcr.io/astral-sh/uv:0.7.10 AS uv
# Stage 6: Base python image
FROM ghcr.io/goauthentik/fips-python:3.13.3-slim-bookworm-fips AS python-base
# Stage 4: Download uv
FROM ghcr.io/astral-sh/uv:0.7.13 AS uv
# Stage 5: Base python image
FROM ghcr.io/goauthentik/fips-python:3.13.5-slim-bookworm-fips AS python-base
ENV VENV_PATH="/ak-root/.venv" \
PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \
@ -109,7 +90,7 @@ WORKDIR /ak-root/
COPY --from=uv /uv /uvx /bin/
# Stage 7: Python dependencies
# Stage 6: Python dependencies
FROM python-base AS python-deps
ARG TARGETARCH
@ -144,7 +125,7 @@ RUN --mount=type=bind,target=pyproject.toml,src=pyproject.toml \
--mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-install-project --no-dev
# Stage 8: Run
# Stage 7: Run
FROM python-base AS final-image
ARG VERSION
@ -187,9 +168,8 @@ COPY ./lifecycle/ /lifecycle
COPY ./authentik/sources/kerberos/krb5.conf /etc/krb5.conf
COPY --from=go-builder /go/authentik /bin/authentik
COPY --from=python-deps /ak-root/.venv /ak-root/.venv
COPY --from=web-builder /work/web/dist/ /web/dist/
COPY --from=web-builder /work/web/authentik/ /web/authentik/
COPY --from=website-builder /work/website/build/ /website/help/
COPY --from=node-builder /work/web/dist/ /web/dist/
COPY --from=node-builder /work/web/authentik/ /web/authentik/
COPY --from=geoip /usr/share/GeoIP /geoip
USER 1000

View File

@ -94,7 +94,7 @@ gen-build: ## Extract the schema from the database
AUTHENTIK_DEBUG=true \
AUTHENTIK_TENANTS__ENABLED=true \
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \
uv run ak make_blueprint_schema > blueprints/schema.json
uv run ak make_blueprint_schema --file blueprints/schema.json
AUTHENTIK_DEBUG=true \
AUTHENTIK_TENANTS__ENABLED=true \
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST=true \

View File

@ -2,7 +2,7 @@
from os import environ
__version__ = "2025.6.0"
__version__ = "2025.6.2"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -1,79 +0,0 @@
"""authentik administration metrics"""
from datetime import timedelta
from django.db.models.functions import ExtractHour
from drf_spectacular.utils import extend_schema, extend_schema_field
from guardian.shortcuts import get_objects_for_user
from rest_framework.fields import IntegerField, SerializerMethodField
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView
from authentik.core.api.utils import PassiveSerializer
from authentik.events.models import EventAction
class CoordinateSerializer(PassiveSerializer):
"""Coordinates for diagrams"""
x_cord = IntegerField(read_only=True)
y_cord = IntegerField(read_only=True)
class LoginMetricsSerializer(PassiveSerializer):
"""Login Metrics per 1h"""
logins = SerializerMethodField()
logins_failed = SerializerMethodField()
authorizations = SerializerMethodField()
@extend_schema_field(CoordinateSerializer(many=True))
def get_logins(self, _):
"""Get successful logins per 8 hours for the last 7 days"""
user = self.context["user"]
return (
get_objects_for_user(user, "authentik_events.view_event").filter(
action=EventAction.LOGIN
)
# 3 data points per day, so 8 hour spans
.get_events_per(timedelta(days=7), ExtractHour, 7 * 3)
)
@extend_schema_field(CoordinateSerializer(many=True))
def get_logins_failed(self, _):
"""Get failed logins per 8 hours for the last 7 days"""
user = self.context["user"]
return (
get_objects_for_user(user, "authentik_events.view_event").filter(
action=EventAction.LOGIN_FAILED
)
# 3 data points per day, so 8 hour spans
.get_events_per(timedelta(days=7), ExtractHour, 7 * 3)
)
@extend_schema_field(CoordinateSerializer(many=True))
def get_authorizations(self, _):
"""Get successful authorizations per 8 hours for the last 7 days"""
user = self.context["user"]
return (
get_objects_for_user(user, "authentik_events.view_event").filter(
action=EventAction.AUTHORIZE_APPLICATION
)
# 3 data points per day, so 8 hour spans
.get_events_per(timedelta(days=7), ExtractHour, 7 * 3)
)
class AdministrationMetricsViewSet(APIView):
"""Login Metrics per 1h"""
permission_classes = [IsAuthenticated]
@extend_schema(responses={200: LoginMetricsSerializer(many=False)})
def get(self, request: Request) -> Response:
"""Login Metrics per 1h"""
serializer = LoginMetricsSerializer(True)
serializer.context["user"] = request.user
return Response(serializer.data)

View File

@ -1,6 +1,7 @@
"""authentik administration overview"""
from django.core.cache import cache
from django_tenants.utils import get_public_schema_name
from drf_spectacular.utils import extend_schema
from packaging.version import parse
from rest_framework.fields import SerializerMethodField
@ -13,6 +14,7 @@ from authentik import __version__, get_build_hash
from authentik.admin.tasks import VERSION_CACHE_KEY, VERSION_NULL, update_latest_version
from authentik.core.api.utils import PassiveSerializer
from authentik.outposts.models import Outpost
from authentik.tenants.utils import get_current_tenant
class VersionSerializer(PassiveSerializer):
@ -35,6 +37,8 @@ class VersionSerializer(PassiveSerializer):
def get_version_latest(self, _) -> str:
"""Get latest version from cache"""
if get_current_tenant().schema_name == get_public_schema_name():
return __version__
version_in_cache = cache.get(VERSION_CACHE_KEY)
if not version_in_cache: # pragma: no cover
update_latest_version.delay()

View File

@ -14,3 +14,19 @@ class AuthentikAdminConfig(ManagedAppConfig):
label = "authentik_admin"
verbose_name = "authentik Admin"
default = True
@ManagedAppConfig.reconcile_global
def clear_update_notifications(self):
"""Clear update notifications on startup if the notification was for the version
we're running now."""
from packaging.version import parse
from authentik.admin.tasks import LOCAL_VERSION
from authentik.events.models import EventAction, Notification
for notification in Notification.objects.filter(event__action=EventAction.UPDATE_AVAILABLE):
if "new_version" not in notification.event.context:
continue
notification_version = notification.event.context["new_version"]
if LOCAL_VERSION >= parse(notification_version):
notification.delete()

View File

@ -1,6 +1,7 @@
"""authentik admin settings"""
from celery.schedules import crontab
from django_tenants.utils import get_public_schema_name
from authentik.lib.utils.time import fqdn_rand
@ -8,6 +9,7 @@ CELERY_BEAT_SCHEDULE = {
"admin_latest_version": {
"task": "authentik.admin.tasks.update_latest_version",
"schedule": crontab(minute=fqdn_rand("admin_latest_version"), hour="*"),
"tenant_schemas": [get_public_schema_name()],
"options": {"queue": "authentik_scheduled"},
}
}

View File

@ -1,7 +1,6 @@
"""authentik admin tasks"""
from django.core.cache import cache
from django.db import DatabaseError, InternalError, ProgrammingError
from django.utils.translation import gettext_lazy as _
from packaging.version import parse
from requests import RequestException
@ -9,7 +8,7 @@ from structlog.stdlib import get_logger
from authentik import __version__, get_build_hash
from authentik.admin.apps import PROM_INFO
from authentik.events.models import Event, EventAction, Notification
from authentik.events.models import Event, EventAction
from authentik.events.system_tasks import SystemTask, TaskStatus, prefill_task
from authentik.lib.config import CONFIG
from authentik.lib.utils.http import get_http_session
@ -33,20 +32,6 @@ def _set_prom_info():
)
@CELERY_APP.task(
throws=(DatabaseError, ProgrammingError, InternalError),
)
def clear_update_notifications():
"""Clear update notifications on startup if the notification was for the version
we're running now."""
for notification in Notification.objects.filter(event__action=EventAction.UPDATE_AVAILABLE):
if "new_version" not in notification.event.context:
continue
notification_version = notification.event.context["new_version"]
if LOCAL_VERSION >= parse(notification_version):
notification.delete()
@CELERY_APP.task(bind=True, base=SystemTask)
@prefill_task
def update_latest_version(self: SystemTask):

View File

@ -36,11 +36,6 @@ class TestAdminAPI(TestCase):
body = loads(response.content)
self.assertEqual(len(body), 0)
def test_metrics(self):
"""Test metrics API"""
response = self.client.get(reverse("authentik_api:admin_metrics"))
self.assertEqual(response.status_code, 200)
def test_apps(self):
"""Test apps API"""
response = self.client.get(reverse("authentik_api:apps-list"))

View File

@ -1,12 +1,12 @@
"""test admin tasks"""
from django.apps import apps
from django.core.cache import cache
from django.test import TestCase
from requests_mock import Mocker
from authentik.admin.tasks import (
VERSION_CACHE_KEY,
clear_update_notifications,
update_latest_version,
)
from authentik.events.models import Event, EventAction
@ -72,12 +72,13 @@ class TestAdminTasks(TestCase):
def test_clear_update_notifications(self):
"""Test clear of previous notification"""
admin_config = apps.get_app_config("authentik_admin")
Event.objects.create(
action=EventAction.UPDATE_AVAILABLE, context={"new_version": "99999999.9999999.9999999"}
)
Event.objects.create(action=EventAction.UPDATE_AVAILABLE, context={"new_version": "1.1.1"})
Event.objects.create(action=EventAction.UPDATE_AVAILABLE, context={})
clear_update_notifications()
admin_config.clear_update_notifications()
self.assertFalse(
Event.objects.filter(
action=EventAction.UPDATE_AVAILABLE, context__new_version="1.1"

View File

@ -3,7 +3,6 @@
from django.urls import path
from authentik.admin.api.meta import AppsViewSet, ModelViewSet
from authentik.admin.api.metrics import AdministrationMetricsViewSet
from authentik.admin.api.system import SystemView
from authentik.admin.api.version import VersionView
from authentik.admin.api.version_history import VersionHistoryViewSet
@ -12,11 +11,6 @@ from authentik.admin.api.workers import WorkerView
api_urlpatterns = [
("admin/apps", AppsViewSet, "apps"),
("admin/models", ModelViewSet, "models"),
path(
"admin/metrics/",
AdministrationMetricsViewSet.as_view(),
name="admin_metrics",
),
path("admin/version/", VersionView.as_view(), name="admin_version"),
("admin/version/history", VersionHistoryViewSet, "version_history"),
path("admin/workers/", WorkerView.as_view(), name="admin_workers"),

View File

@ -1,12 +1,13 @@
"""authentik API AppConfig"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikAPIConfig(AppConfig):
class AuthentikAPIConfig(ManagedAppConfig):
"""authentik API Config"""
name = "authentik.api"
label = "authentik_api"
mountpoint = "api/"
verbose_name = "authentik API"
default = True

View File

@ -72,20 +72,33 @@ class Command(BaseCommand):
"additionalProperties": True,
},
"entries": {
"type": "array",
"items": {
"oneOf": [],
},
"anyOf": [
{
"type": "array",
"items": {"$ref": "#/$defs/blueprint_entry"},
},
{
"type": "object",
"additionalProperties": {
"type": "array",
"items": {"$ref": "#/$defs/blueprint_entry"},
},
},
],
},
},
"$defs": {},
"$defs": {"blueprint_entry": {"oneOf": []}},
}
def add_arguments(self, parser):
parser.add_argument("--file", type=str)
@no_translations
def handle(self, *args, **options):
def handle(self, *args, file: str, **options):
"""Generate JSON Schema for blueprints"""
self.build()
self.stdout.write(dumps(self.schema, indent=4, default=Command.json_default))
with open(file, "w") as _schema:
_schema.write(dumps(self.schema, indent=4, default=Command.json_default))
@staticmethod
def json_default(value: Any) -> Any:
@ -112,7 +125,7 @@ class Command(BaseCommand):
}
)
model_path = f"{model._meta.app_label}.{model._meta.model_name}"
self.schema["properties"]["entries"]["items"]["oneOf"].append(
self.schema["$defs"]["blueprint_entry"]["oneOf"].append(
self.template_entry(model_path, model, serializer)
)
@ -134,7 +147,7 @@ class Command(BaseCommand):
"id": {"type": "string"},
"state": {
"type": "string",
"enum": [s.value for s in BlueprintEntryDesiredState],
"enum": sorted([s.value for s in BlueprintEntryDesiredState]),
"default": "present",
},
"conditions": {"type": "array", "items": {"type": "boolean"}},
@ -205,7 +218,7 @@ class Command(BaseCommand):
"type": "object",
"required": ["permission"],
"properties": {
"permission": {"type": "string", "enum": perms},
"permission": {"type": "string", "enum": sorted(perms)},
"user": {"type": "integer"},
"role": {"type": "string"},
},

View File

@ -1,10 +1,11 @@
version: 1
entries:
- identifiers:
name: "%(id)s"
slug: "%(id)s"
model: authentik_flows.flow
state: present
attrs:
designation: stage_configuration
title: foo
foo:
- identifiers:
name: "%(id)s"
slug: "%(id)s"
model: authentik_flows.flow
state: present
attrs:
designation: stage_configuration
title: foo

View File

@ -0,0 +1,14 @@
from django.test import TestCase
from authentik.blueprints.apps import ManagedAppConfig
from authentik.enterprise.apps import EnterpriseConfig
from authentik.lib.utils.reflection import get_apps
class TestManagedAppConfig(TestCase):
def test_apps_use_managed_app_config(self):
for app in get_apps():
if app.name.startswith("authentik.enterprise"):
self.assertIn(EnterpriseConfig, app.__class__.__bases__)
else:
self.assertIn(ManagedAppConfig, app.__class__.__bases__)

View File

@ -191,11 +191,18 @@ class Blueprint:
"""Dataclass used for a full export"""
version: int = field(default=1)
entries: list[BlueprintEntry] = field(default_factory=list)
entries: list[BlueprintEntry] | dict[str, list[BlueprintEntry]] = field(default_factory=list)
context: dict = field(default_factory=dict)
metadata: BlueprintMetadata | None = field(default=None)
def iter_entries(self) -> Iterable[BlueprintEntry]:
if isinstance(self.entries, dict):
for _section, entries in self.entries.items():
yield from entries
else:
yield from self.entries
class YAMLTag:
"""Base class for all YAML Tags"""
@ -226,7 +233,7 @@ class KeyOf(YAMLTag):
self.id_from = node.value
def resolve(self, entry: BlueprintEntry, blueprint: Blueprint) -> Any:
for _entry in blueprint.entries:
for _entry in blueprint.iter_entries():
if _entry.id == self.id_from and _entry._state.instance:
# Special handling for PolicyBindingModels, as they'll have a different PK
# which is used when creating policy bindings

View File

@ -384,7 +384,7 @@ class Importer:
def _apply_models(self, raise_errors=False) -> bool:
"""Apply (create/update) models yaml"""
self.__pk_map = {}
for entry in self._import.entries:
for entry in self._import.iter_entries():
model_app_label, model_name = entry.get_model(self._import).split(".")
try:
model: type[SerializerModel] = registry.get_model(model_app_label, model_name)

View File

@ -47,7 +47,7 @@ class MetaModelRegistry:
models = apps.get_models()
for _, value in self.models.items():
models.append(value)
return models
return sorted(models, key=str)
def get_model(self, app_label: str, model_id: str) -> type[Model]:
"""Get model checks if any virtual models are registered, and falls back

View File

@ -1,9 +1,9 @@
"""authentik brands app"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikBrandsConfig(AppConfig):
class AuthentikBrandsConfig(ManagedAppConfig):
"""authentik Brand app"""
name = "authentik.brands"
@ -12,3 +12,4 @@ class AuthentikBrandsConfig(AppConfig):
mountpoints = {
"authentik.brands.urls_root": "",
}
default = True

View File

@ -148,3 +148,14 @@ class TestBrands(APITestCase):
"default_locale": "",
},
)
def test_custom_css(self):
"""Test custom_css"""
brand = create_test_brand()
brand.branding_custom_css = """* {
font-family: "Foo bar";
}"""
brand.save()
res = self.client.get(reverse("authentik_core:if-user"))
self.assertEqual(res.status_code, 200)
self.assertIn(brand.branding_custom_css, res.content.decode())

View File

@ -5,6 +5,8 @@ from typing import Any
from django.db.models import F, Q
from django.db.models import Value as V
from django.http.request import HttpRequest
from django.utils.html import _json_script_escapes
from django.utils.safestring import mark_safe
from authentik import get_full_version
from authentik.brands.models import Brand
@ -32,8 +34,13 @@ def context_processor(request: HttpRequest) -> dict[str, Any]:
"""Context Processor that injects brand object into every template"""
brand = getattr(request, "brand", DEFAULT_BRAND)
tenant = getattr(request, "tenant", Tenant())
# similarly to `json_script` we escape everything HTML-related, however django
# only directly exposes this as a function that also wraps it in a <script> tag
# which we dont want for CSS
brand_css = mark_safe(str(brand.branding_custom_css).translate(_json_script_escapes)) # nosec
return {
"brand": brand,
"brand_css": brand_css,
"footer_links": tenant.footer_links,
"html_meta": {**get_http_meta()},
"version": get_full_version(),

View File

@ -2,11 +2,9 @@
from collections.abc import Iterator
from copy import copy
from datetime import timedelta
from django.core.cache import cache
from django.db.models import QuerySet
from django.db.models.functions import ExtractHour
from django.shortcuts import get_object_or_404
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
@ -20,7 +18,6 @@ from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from structlog.stdlib import get_logger
from authentik.admin.api.metrics import CoordinateSerializer
from authentik.api.pagination import Pagination
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
from authentik.core.api.providers import ProviderSerializer
@ -28,7 +25,6 @@ from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer
from authentik.core.models import Application, User
from authentik.events.logs import LogEventSerializer, capture_logs
from authentik.events.models import EventAction
from authentik.lib.utils.file import (
FilePathSerializer,
FileUploadSerializer,
@ -321,18 +317,3 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
"""Set application icon (as URL)"""
app: Application = self.get_object()
return set_file_url(request, app, "meta_icon")
@permission_required("authentik_core.view_application", ["authentik_events.view_event"])
@extend_schema(responses={200: CoordinateSerializer(many=True)})
@action(detail=True, pagination_class=None, filter_backends=[])
def metrics(self, request: Request, slug: str):
"""Metrics for application logins"""
app = self.get_object()
return Response(
get_objects_for_user(request.user, "authentik_events.view_event").filter(
action=EventAction.AUTHORIZE_APPLICATION,
context__authorized_application__pk=app.pk.hex,
)
# 3 data points per day, so 8 hour spans
.get_events_per(timedelta(days=7), ExtractHour, 7 * 3)
)

View File

@ -6,7 +6,6 @@ from typing import Any
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.models import Permission
from django.db.models.functions import ExtractHour
from django.db.transaction import atomic
from django.db.utils import IntegrityError
from django.urls import reverse_lazy
@ -52,7 +51,6 @@ from rest_framework.validators import UniqueValidator
from rest_framework.viewsets import ModelViewSet
from structlog.stdlib import get_logger
from authentik.admin.api.metrics import CoordinateSerializer
from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT
from authentik.brands.models import Brand
from authentik.core.api.used_by import UsedByMixin
@ -317,53 +315,6 @@ class SessionUserSerializer(PassiveSerializer):
original = UserSelfSerializer(required=False)
class UserMetricsSerializer(PassiveSerializer):
"""User Metrics"""
logins = SerializerMethodField()
logins_failed = SerializerMethodField()
authorizations = SerializerMethodField()
@extend_schema_field(CoordinateSerializer(many=True))
def get_logins(self, _):
"""Get successful logins per 8 hours for the last 7 days"""
user = self.context["user"]
request = self.context["request"]
return (
get_objects_for_user(request.user, "authentik_events.view_event").filter(
action=EventAction.LOGIN, user__pk=user.pk
)
# 3 data points per day, so 8 hour spans
.get_events_per(timedelta(days=7), ExtractHour, 7 * 3)
)
@extend_schema_field(CoordinateSerializer(many=True))
def get_logins_failed(self, _):
"""Get failed logins per 8 hours for the last 7 days"""
user = self.context["user"]
request = self.context["request"]
return (
get_objects_for_user(request.user, "authentik_events.view_event").filter(
action=EventAction.LOGIN_FAILED, context__username=user.username
)
# 3 data points per day, so 8 hour spans
.get_events_per(timedelta(days=7), ExtractHour, 7 * 3)
)
@extend_schema_field(CoordinateSerializer(many=True))
def get_authorizations(self, _):
"""Get failed logins per 8 hours for the last 7 days"""
user = self.context["user"]
request = self.context["request"]
return (
get_objects_for_user(request.user, "authentik_events.view_event").filter(
action=EventAction.AUTHORIZE_APPLICATION, user__pk=user.pk
)
# 3 data points per day, so 8 hour spans
.get_events_per(timedelta(days=7), ExtractHour, 7 * 3)
)
class UsersFilter(FilterSet):
"""Filter for users"""
@ -607,17 +558,6 @@ class UserViewSet(UsedByMixin, ModelViewSet):
update_session_auth_hash(self.request, user)
return Response(status=204)
@permission_required("authentik_core.view_user", ["authentik_events.view_event"])
@extend_schema(responses={200: UserMetricsSerializer(many=False)})
@action(detail=True, pagination_class=None, filter_backends=[])
def metrics(self, request: Request, pk: int) -> Response:
"""User metrics per 1h"""
user: User = self.get_object()
serializer = UserMetricsSerializer(instance={})
serializer.context["user"] = user
serializer.context["request"] = request
return Response(serializer.data)
@permission_required("authentik_core.reset_user_password")
@extend_schema(
responses={

View File

@ -16,7 +16,7 @@
{% block head_before %}
{% endblock %}
<link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}">
<style>{{ brand.branding_custom_css }}</style>
<style>{{ brand_css }}</style>
<script src="{% versioned_script 'dist/poly-%v.js' %}" type="module"></script>
<script src="{% versioned_script 'dist/standalone/loading/index-%v.js' %}" type="module"></script>
{% block head %}

View File

@ -10,7 +10,7 @@
{% endblock %}
{% block body %}
<ak-message-container></ak-message-container>
<ak-message-container alignment="bottom"></ak-message-container>
<ak-interface-admin>
<ak-loading></ak-loading>
</ak-interface-admin>

View File

@ -81,22 +81,6 @@ class TestUsersAPI(APITestCase):
response = self.client.get(reverse("authentik_api:user-list"), {"include_groups": "true"})
self.assertEqual(response.status_code, 200)
def test_metrics(self):
"""Test user's metrics"""
self.client.force_login(self.admin)
response = self.client.get(
reverse("authentik_api:user-metrics", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 200)
def test_metrics_denied(self):
"""Test user's metrics (non-superuser)"""
self.client.force_login(self.user)
response = self.client.get(
reverse("authentik_api:user-metrics", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 403)
def test_recovery_no_flow(self):
"""Test user recovery link (no recovery flow set)"""
self.client.force_login(self.admin)

View File

@ -1,28 +1,36 @@
"""Events API Views"""
from datetime import timedelta
from json import loads
import django_filters
from django.db.models.aggregates import Count
from django.db.models import Count, ExpressionWrapper, F, QuerySet
from django.db.models import DateTimeField as DjangoDateTimeField
from django.db.models.fields.json import KeyTextTransform, KeyTransform
from django.db.models.functions import ExtractDay, ExtractHour
from django.db.models.functions import TruncHour
from django.db.models.query_utils import Q
from django.utils.timezone import now
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from guardian.shortcuts import get_objects_for_user
from rest_framework.decorators import action
from rest_framework.fields import DictField, IntegerField
from rest_framework.fields import ChoiceField, DateTimeField, DictField, IntegerField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from authentik.admin.api.metrics import CoordinateSerializer
from authentik.core.api.object_types import TypeCreateSerializer
from authentik.core.api.utils import ModelSerializer, PassiveSerializer
from authentik.events.models import Event, EventAction
class EventVolumeSerializer(PassiveSerializer):
"""Count of events of action created on day"""
action = ChoiceField(choices=EventAction.choices)
time = DateTimeField()
count = IntegerField()
class EventSerializer(ModelSerializer):
"""Event Serializer"""
@ -53,7 +61,7 @@ class EventsFilter(django_filters.FilterSet):
"""Filter for events"""
username = django_filters.CharFilter(
field_name="user", lookup_expr="username", label="Username"
field_name="user", label="Username", method="filter_username"
)
context_model_pk = django_filters.CharFilter(
field_name="context",
@ -78,12 +86,19 @@ class EventsFilter(django_filters.FilterSet):
field_name="action",
lookup_expr="icontains",
)
actions = django_filters.MultipleChoiceFilter(
field_name="action",
choices=EventAction.choices,
)
brand_name = django_filters.CharFilter(
field_name="brand",
lookup_expr="name",
label="Brand name",
)
def filter_username(self, queryset, name, value):
return queryset.filter(Q(user__username=value) | Q(context__username=value))
def filter_context_model_pk(self, queryset, name, value):
"""Because we store the PK as UUID.hex,
we need to remove the dashes that a client may send. We can't use a
@ -156,45 +171,37 @@ class EventViewSet(ModelViewSet):
return Response(EventTopPerUserSerializer(instance=events, many=True).data)
@extend_schema(
responses={200: CoordinateSerializer(many=True)},
)
@action(detail=False, methods=["GET"], pagination_class=None)
def volume(self, request: Request) -> Response:
"""Get event volume for specified filters and timeframe"""
queryset = self.filter_queryset(self.get_queryset())
return Response(queryset.get_events_per(timedelta(days=7), ExtractHour, 7 * 3))
@extend_schema(
responses={200: CoordinateSerializer(many=True)},
filters=[],
responses={200: EventVolumeSerializer(many=True)},
parameters=[
OpenApiParameter(
"action",
type=OpenApiTypes.STR,
location=OpenApiParameter.QUERY,
required=False,
),
OpenApiParameter(
"query",
type=OpenApiTypes.STR,
"history_days",
type=OpenApiTypes.NUMBER,
location=OpenApiParameter.QUERY,
required=False,
default=7,
),
],
)
@action(detail=False, methods=["GET"], pagination_class=None)
def per_month(self, request: Request):
"""Get the count of events per month"""
filtered_action = request.query_params.get("action", EventAction.LOGIN)
try:
query = loads(request.query_params.get("query", "{}"))
except ValueError:
return Response(status=400)
def volume(self, request: Request) -> Response:
"""Get event volume for specified filters and timeframe"""
queryset: QuerySet[Event] = self.filter_queryset(self.get_queryset())
delta = timedelta(days=7)
time_delta = request.query_params.get("history_days", 7)
if time_delta:
delta = timedelta(days=min(int(time_delta), 60))
return Response(
get_objects_for_user(request.user, "authentik_events.view_event")
.filter(action=filtered_action)
.filter(**query)
.get_events_per(timedelta(weeks=4), ExtractDay, 30)
queryset.filter(created__gte=now() - delta)
.annotate(hour=TruncHour("created"))
.annotate(
time=ExpressionWrapper(
F("hour") - (F("hour__hour") % 6) * timedelta(hours=1),
output_field=DjangoDateTimeField(),
)
)
.values("time", "action")
.annotate(count=Count("pk"))
.order_by("time", "action")
)
@extend_schema(responses={200: TypeCreateSerializer(many=True)})

View File

@ -1,7 +1,5 @@
"""authentik events models"""
import time
from collections import Counter
from datetime import timedelta
from difflib import get_close_matches
from functools import lru_cache
@ -11,11 +9,6 @@ from uuid import uuid4
from django.apps import apps
from django.db import connection, models
from django.db.models import Count, ExpressionWrapper, F
from django.db.models.fields import DurationField
from django.db.models.functions import Extract
from django.db.models.manager import Manager
from django.db.models.query import QuerySet
from django.http import HttpRequest
from django.http.request import QueryDict
from django.utils.timezone import now
@ -124,60 +117,6 @@ class EventAction(models.TextChoices):
CUSTOM_PREFIX = "custom_"
class EventQuerySet(QuerySet):
"""Custom events query set with helper functions"""
def get_events_per(
self,
time_since: timedelta,
extract: Extract,
data_points: int,
) -> list[dict[str, int]]:
"""Get event count by hour in the last day, fill with zeros"""
_now = now()
max_since = timedelta(days=60)
# Allow maximum of 60 days to limit load
if time_since.total_seconds() > max_since.total_seconds():
time_since = max_since
date_from = _now - time_since
result = (
self.filter(created__gte=date_from)
.annotate(age=ExpressionWrapper(_now - F("created"), output_field=DurationField()))
.annotate(age_interval=extract("age"))
.values("age_interval")
.annotate(count=Count("pk"))
.order_by("age_interval")
)
data = Counter({int(d["age_interval"]): d["count"] for d in result})
results = []
interval_delta = time_since / data_points
for interval in range(1, -data_points, -1):
results.append(
{
"x_cord": time.mktime((_now + (interval_delta * interval)).timetuple()) * 1000,
"y_cord": data[interval * -1],
}
)
return results
class EventManager(Manager):
"""Custom helper methods for Events"""
def get_queryset(self) -> QuerySet:
"""use custom queryset"""
return EventQuerySet(self.model, using=self._db)
def get_events_per(
self,
time_since: timedelta,
extract: Extract,
data_points: int,
) -> list[dict[str, int]]:
"""Wrap method from queryset"""
return self.get_queryset().get_events_per(time_since, extract, data_points)
class Event(SerializerModel, ExpiringModel):
"""An individual Audit/Metrics/Notification/Error Event"""
@ -193,8 +132,6 @@ class Event(SerializerModel, ExpiringModel):
# Shadow the expires attribute from ExpiringModel to override the default duration
expires = models.DateTimeField(default=default_event_duration)
objects = EventManager()
@staticmethod
def _get_app_from_request(request: HttpRequest) -> str:
if not isinstance(request, HttpRequest):

View File

@ -37,6 +37,9 @@ class WebsocketMessageInstruction(IntEnum):
# Provider specific message
PROVIDER_SPECIFIC = 3
# Session ended
SESSION_END = 4
@dataclass(slots=True)
class WebsocketMessage:
@ -145,6 +148,14 @@ class OutpostConsumer(JsonWebsocketConsumer):
asdict(WebsocketMessage(instruction=WebsocketMessageInstruction.TRIGGER_UPDATE))
)
def event_session_end(self, event):
"""Event handler which is called when a session is ended"""
self.send_json(
asdict(
WebsocketMessage(instruction=WebsocketMessageInstruction.SESSION_END, args=event)
)
)
def event_provider_specific(self, event):
"""Event handler which can be called by provider-specific
implementations to send specific messages to the outpost"""

View File

@ -1,17 +1,24 @@
"""authentik outpost signals"""
from django.contrib.auth.signals import user_logged_out
from django.core.cache import cache
from django.db.models import Model
from django.db.models.signals import m2m_changed, post_save, pre_delete, pre_save
from django.dispatch import receiver
from django.http import HttpRequest
from structlog.stdlib import get_logger
from authentik.brands.models import Brand
from authentik.core.models import Provider
from authentik.core.models import AuthenticatedSession, Provider, User
from authentik.crypto.models import CertificateKeyPair
from authentik.lib.utils.reflection import class_to_path
from authentik.outposts.models import Outpost, OutpostServiceConnection
from authentik.outposts.tasks import CACHE_KEY_OUTPOST_DOWN, outpost_controller, outpost_post_save
from authentik.outposts.tasks import (
CACHE_KEY_OUTPOST_DOWN,
outpost_controller,
outpost_post_save,
outpost_session_end,
)
LOGGER = get_logger()
UPDATE_TRIGGERING_MODELS = (
@ -73,3 +80,17 @@ def pre_delete_cleanup(sender, instance: Outpost, **_):
instance.user.delete()
cache.set(CACHE_KEY_OUTPOST_DOWN % instance.pk.hex, instance)
outpost_controller.delay(instance.pk.hex, action="down", from_cache=True)
@receiver(user_logged_out)
def logout_revoke_direct(sender: type[User], request: HttpRequest, **_):
"""Catch logout by direct logout and forward to providers"""
if not request.session or not request.session.session_key:
return
outpost_session_end.delay(request.session.session_key)
@receiver(pre_delete, sender=AuthenticatedSession)
def logout_revoke(sender: type[AuthenticatedSession], instance: AuthenticatedSession, **_):
"""Catch logout by expiring sessions being deleted"""
outpost_session_end.delay(instance.session.session_key)

View File

@ -1,5 +1,6 @@
"""outpost tasks"""
from hashlib import sha256
from os import R_OK, access
from pathlib import Path
from socket import gethostname
@ -49,6 +50,11 @@ LOGGER = get_logger()
CACHE_KEY_OUTPOST_DOWN = "goauthentik.io/outposts/teardown/%s"
def hash_session_key(session_key: str) -> str:
"""Hash the session key for sending session end signals"""
return sha256(session_key.encode("ascii")).hexdigest()
def controller_for_outpost(outpost: Outpost) -> type[BaseController] | None:
"""Get a controller for the outpost, when a service connection is defined"""
if not outpost.service_connection:
@ -289,3 +295,20 @@ def outpost_connection_discovery(self: SystemTask):
url=unix_socket_path,
)
self.set_status(TaskStatus.SUCCESSFUL, *messages)
@CELERY_APP.task()
def outpost_session_end(session_id: str):
"""Update outpost instances connected to a single outpost"""
layer = get_channel_layer()
hashed_session_id = hash_session_key(session_id)
for outpost in Outpost.objects.all():
LOGGER.info("Sending session end signal to outpost", outpost=outpost)
group = OUTPOST_GROUP % {"outpost_pk": str(outpost.pk)}
async_to_sync(layer.group_send)(
group,
{
"type": "event.session.end",
"session_id": hashed_session_id,
},
)

View File

@ -1,11 +1,9 @@
"""Websocket tests"""
from dataclasses import asdict
from unittest.mock import patch
from channels.routing import URLRouter
from channels.testing import WebsocketCommunicator
from django.contrib.contenttypes.models import ContentType
from django.test import TransactionTestCase
from authentik import __version__
@ -16,12 +14,6 @@ from authentik.providers.proxy.models import ProxyProvider
from authentik.root import websocket
def patched__get_ct_cached(app_label, codename):
"""Caches `ContentType` instances like its `QuerySet` does."""
return ContentType.objects.get(app_label=app_label, permission__codename=codename)
@patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached)
class TestOutpostWS(TransactionTestCase):
"""Websocket tests"""

View File

@ -1,11 +1,12 @@
"""Authentik policy dummy app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikPolicyDummyConfig(AppConfig):
class AuthentikPolicyDummyConfig(ManagedAppConfig):
"""Authentik policy_dummy app config"""
name = "authentik.policies.dummy"
label = "authentik_policies_dummy"
verbose_name = "authentik Policies.Dummy"
default = True

View File

@ -1,11 +1,12 @@
"""authentik Event Matcher policy app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikPoliciesEventMatcherConfig(AppConfig):
class AuthentikPoliciesEventMatcherConfig(ManagedAppConfig):
"""authentik Event Matcher policy app config"""
name = "authentik.policies.event_matcher"
label = "authentik_policies_event_matcher"
verbose_name = "authentik Policies.Event Matcher"
default = True

View File

@ -1,11 +1,12 @@
"""Authentik policy_expiry app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikPolicyExpiryConfig(AppConfig):
class AuthentikPolicyExpiryConfig(ManagedAppConfig):
"""Authentik policy_expiry app config"""
name = "authentik.policies.expiry"
label = "authentik_policies_expiry"
verbose_name = "authentik Policies.Expiry"
default = True

View File

@ -1,11 +1,12 @@
"""Authentik policy_expression app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikPolicyExpressionConfig(AppConfig):
class AuthentikPolicyExpressionConfig(ManagedAppConfig):
"""Authentik policy_expression app config"""
name = "authentik.policies.expression"
label = "authentik_policies_expression"
verbose_name = "authentik Policies.Expression"
default = True

View File

@ -1,11 +1,12 @@
"""Authentik policy geoip app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikPolicyGeoIPConfig(AppConfig):
class AuthentikPolicyGeoIPConfig(ManagedAppConfig):
"""Authentik policy_geoip app config"""
name = "authentik.policies.geoip"
label = "authentik_policies_geoip"
verbose_name = "authentik Policies.GeoIP"
default = True

View File

@ -1,11 +1,12 @@
"""authentik Password policy app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikPoliciesPasswordConfig(AppConfig):
class AuthentikPoliciesPasswordConfig(ManagedAppConfig):
"""authentik Password policy app config"""
name = "authentik.policies.password"
label = "authentik_policies_password"
verbose_name = "authentik Policies.Password"
default = True

View File

@ -1,11 +1,12 @@
"""authentik ldap provider app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikProviderLDAPConfig(AppConfig):
class AuthentikProviderLDAPConfig(ManagedAppConfig):
"""authentik ldap provider app config"""
name = "authentik.providers.ldap"
label = "authentik_providers_ldap"
verbose_name = "authentik Providers.LDAP"
default = True

View File

@ -387,8 +387,7 @@ class TestAuthorize(OAuthTestCase):
self.assertEqual(
response.url,
(
f"http://localhost#access_token={token.token}"
f"&id_token={provider.encode(token.id_token.to_dict())}"
f"http://localhost#id_token={provider.encode(token.id_token.to_dict())}"
f"&token_type={TOKEN_TYPE}"
f"&expires_in={int(expires)}&state={state}"
),
@ -563,7 +562,6 @@ class TestAuthorize(OAuthTestCase):
"url": "http://localhost",
"title": f"Redirecting to {app.name}...",
"attrs": {
"access_token": token.token,
"id_token": provider.encode(token.id_token.to_dict()),
"token_type": TOKEN_TYPE,
"expires_in": "3600",

View File

@ -150,12 +150,12 @@ class OAuthAuthorizationParams:
self.check_redirect_uri()
self.check_grant()
self.check_scope(github_compat)
self.check_nonce()
self.check_code_challenge()
if self.request:
raise AuthorizeError(
self.redirect_uri, "request_not_supported", self.grant_type, self.state
)
self.check_nonce()
self.check_code_challenge()
def check_grant(self):
"""Check grant"""
@ -630,7 +630,6 @@ class OAuthFulfillmentStage(StageView):
if self.params.response_type in [
ResponseTypes.ID_TOKEN_TOKEN,
ResponseTypes.CODE_ID_TOKEN_TOKEN,
ResponseTypes.ID_TOKEN,
ResponseTypes.CODE_TOKEN,
]:
query_fragment["access_token"] = token.token

View File

@ -10,3 +10,11 @@ class AuthentikProviderProxyConfig(ManagedAppConfig):
label = "authentik_providers_proxy"
verbose_name = "authentik Providers.Proxy"
default = True
@ManagedAppConfig.reconcile_tenant
def proxy_set_defaults(self):
from authentik.providers.proxy.models import ProxyProvider
for provider in ProxyProvider.objects.all():
provider.set_oauth_defaults()
provider.save()

View File

@ -1,23 +0,0 @@
"""Proxy provider signals"""
from django.contrib.auth.signals import user_logged_out
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.http import HttpRequest
from authentik.core.models import AuthenticatedSession, User
from authentik.providers.proxy.tasks import proxy_on_logout
@receiver(user_logged_out)
def logout_proxy_revoke_direct(sender: type[User], request: HttpRequest, **_):
"""Catch logout by direct logout and forward to proxy providers"""
if not request.session or not request.session.session_key:
return
proxy_on_logout.delay(request.session.session_key)
@receiver(pre_delete, sender=AuthenticatedSession)
def logout_proxy_revoke(sender: type[AuthenticatedSession], instance: AuthenticatedSession, **_):
"""Catch logout by expiring sessions being deleted"""
proxy_on_logout.delay(instance.session.session_key)

View File

@ -1,38 +0,0 @@
"""proxy provider tasks"""
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from django.db import DatabaseError, InternalError, ProgrammingError
from authentik.outposts.consumer import OUTPOST_GROUP
from authentik.outposts.models import Outpost, OutpostType
from authentik.providers.oauth2.id_token import hash_session_key
from authentik.providers.proxy.models import ProxyProvider
from authentik.root.celery import CELERY_APP
@CELERY_APP.task(
throws=(DatabaseError, ProgrammingError, InternalError),
)
def proxy_set_defaults():
"""Ensure correct defaults are set for all providers"""
for provider in ProxyProvider.objects.all():
provider.set_oauth_defaults()
provider.save()
@CELERY_APP.task()
def proxy_on_logout(session_id: str):
"""Update outpost instances connected to a single outpost"""
layer = get_channel_layer()
hashed_session_id = hash_session_key(session_id)
for outpost in Outpost.objects.filter(type=OutpostType.PROXY):
group = OUTPOST_GROUP % {"outpost_pk": str(outpost.pk)}
async_to_sync(layer.group_send)(
group,
{
"type": "event.provider.specific",
"sub_type": "logout",
"session_id": hashed_session_id,
},
)

View File

@ -20,6 +20,9 @@ from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.engine import PolicyEngine
from authentik.policies.views import PolicyAccessView
from authentik.providers.rac.models import ConnectionToken, Endpoint, RACProvider
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
PLAN_CONNECTION_SETTINGS = "connection_settings"
class RACStartView(PolicyAccessView):
@ -109,10 +112,15 @@ class RACFinalStage(RedirectStage):
return super().dispatch(request, *args, **kwargs)
def get_challenge(self, *args, **kwargs) -> RedirectChallenge:
settings = self.executor.plan.context.get(PLAN_CONNECTION_SETTINGS)
if not settings:
settings = self.executor.plan.context.get(PLAN_CONTEXT_PROMPT, {}).get(
PLAN_CONNECTION_SETTINGS
)
token = ConnectionToken.objects.create(
provider=self.provider,
endpoint=self.endpoint,
settings=self.executor.plan.context.get("connection_settings", {}),
settings=settings or {},
session=self.request.session["authenticatedsession"],
expires=now() + timedelta_from_string(self.provider.connection_expiry),
expiring=True,

View File

@ -1,11 +1,12 @@
"""authentik radius provider app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikProviderRadiusConfig(AppConfig):
class AuthentikProviderRadiusConfig(ManagedAppConfig):
"""authentik radius provider app config"""
name = "authentik.providers.radius"
label = "authentik_providers_radius"
verbose_name = "authentik Providers.Radius"
default = True

View File

@ -190,6 +190,7 @@ class SAMLProviderSerializer(ProviderSerializer):
"sign_response",
"sp_binding",
"default_relay_state",
"default_name_id_policy",
"url_download_metadata",
"url_sso_post",
"url_sso_redirect",

View File

@ -1,12 +1,13 @@
"""authentik SAML IdP app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikProviderSAMLConfig(AppConfig):
class AuthentikProviderSAMLConfig(ManagedAppConfig):
"""authentik SAML IdP app config"""
name = "authentik.providers.saml"
label = "authentik_providers_saml"
verbose_name = "authentik Providers.SAML"
mountpoint = "application/saml/"
default = True

View File

@ -0,0 +1,31 @@
# Generated by Django 5.1.11 on 2025-06-18 09:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_providers_saml", "0018_alter_samlprovider_acs_url"),
]
operations = [
migrations.AddField(
model_name="samlprovider",
name="default_name_id_policy",
field=models.TextField(
choices=[
("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "Email"),
("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", "Persistent"),
("urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName", "X509"),
(
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
"Windows",
),
("urn:oasis:names:tc:SAML:2.0:nameid-format:transient", "Transient"),
("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", "Unspecified"),
],
default="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
),
),
]

View File

@ -12,6 +12,7 @@ from authentik.core.models import PropertyMapping, Provider
from authentik.crypto.models import CertificateKeyPair
from authentik.lib.models import DomainlessURLValidator
from authentik.lib.utils.time import timedelta_string_validator
from authentik.sources.saml.models import SAMLNameIDPolicy
from authentik.sources.saml.processors.constants import (
DSA_SHA1,
ECDSA_SHA1,
@ -179,6 +180,9 @@ class SAMLProvider(Provider):
default_relay_state = models.TextField(
default="", blank=True, help_text=_("Default relay_state value for IDP-initiated logins")
)
default_name_id_policy = models.TextField(
choices=SAMLNameIDPolicy.choices, default=SAMLNameIDPolicy.UNSPECIFIED
)
sign_assertion = models.BooleanField(default=True)
sign_response = models.BooleanField(default=False)

View File

@ -205,6 +205,13 @@ class AssertionProcessor:
def get_name_id(self) -> Element:
"""Get NameID Element"""
name_id = Element(f"{{{NS_SAML_ASSERTION}}}NameID")
# For requests that don't specify a NameIDPolicy, check if we
# can fall back to the provider default
if (
self.auth_n_request.name_id_policy == SAML_NAME_ID_FORMAT_UNSPECIFIED
and self.provider.default_name_id_policy != SAML_NAME_ID_FORMAT_UNSPECIFIED
):
self.auth_n_request.name_id_policy = self.provider.default_name_id_policy
name_id.attrib["Format"] = self.auth_n_request.name_id_policy
# persistent is used as a fallback, so always generate it
persistent = self.http_request.user.uid

View File

@ -13,6 +13,7 @@ from authentik.lib.xml import lxml_from_string
from authentik.providers.saml.exceptions import CannotHandleAssertion
from authentik.providers.saml.models import SAMLProvider
from authentik.providers.saml.utils.encoding import decode_base64_and_inflate
from authentik.sources.saml.models import SAMLNameIDPolicy
from authentik.sources.saml.processors.constants import (
DSA_SHA1,
NS_MAP,
@ -175,7 +176,9 @@ class AuthNRequestParser:
def idp_initiated(self) -> AuthNRequest:
"""Create IdP Initiated AuthNRequest"""
relay_state = None
request = AuthNRequest(relay_state=None)
if self.provider.default_relay_state != "":
relay_state = self.provider.default_relay_state
return AuthNRequest(relay_state=relay_state)
request.relay_state = self.provider.default_relay_state
if self.provider.default_name_id_policy != SAMLNameIDPolicy.UNSPECIFIED:
request.name_id_policy = self.provider.default_name_id_policy
return request

View File

@ -13,6 +13,7 @@ from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Flow
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.utils.encoding import PEM_FOOTER, PEM_HEADER
from authentik.sources.saml.models import SAMLNameIDPolicy
from authentik.sources.saml.processors.constants import (
NS_MAP,
NS_SAML_METADATA,
@ -46,6 +47,7 @@ class ServiceProviderMetadata:
auth_n_request_signed: bool
assertion_signed: bool
name_id_policy: SAMLNameIDPolicy
signing_keypair: CertificateKeyPair | None = None
@ -60,6 +62,7 @@ class ServiceProviderMetadata:
provider.issuer = self.entity_id
provider.sp_binding = self.acs_binding
provider.acs_url = self.acs_location
provider.default_name_id_policy = self.name_id_policy
if self.signing_keypair and self.auth_n_request_signed:
self.signing_keypair.name = f"Provider {name} - SAML Signing Certificate"
self.signing_keypair.save()
@ -148,6 +151,11 @@ class ServiceProviderMetadataParser:
if signing_keypair:
self.check_signature(root, signing_keypair)
name_id_format = descriptor.findall(f"{{{NS_SAML_METADATA}}}NameIDFormat")
name_id_policy = SAMLNameIDPolicy.UNSPECIFIED
if len(name_id_format) > 0:
name_id_policy = SAMLNameIDPolicy(name_id_format[0].text)
return ServiceProviderMetadata(
entity_id=entity_id,
acs_binding=acs_binding,
@ -155,4 +163,5 @@ class ServiceProviderMetadataParser:
auth_n_request_signed=auth_n_request_signed,
assertion_signed=assertion_signed,
signing_keypair=signing_keypair,
name_id_policy=name_id_policy,
)

View File

@ -4,7 +4,7 @@
cacheDuration="PT604800S"
entityID="http://localhost:8080/saml/metadata">
<md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://localhost:8080/saml/acs"
index="1" />

View File

@ -14,6 +14,7 @@ from authentik.lib.xml import lxml_from_string
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.processors.metadata import MetadataProcessor
from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser
from authentik.sources.saml.models import SAMLNameIDPolicy
from authentik.sources.saml.processors.constants import ECDSA_SHA256, NS_MAP, NS_SAML_METADATA
@ -86,6 +87,7 @@ class TestServiceProviderMetadataParser(TestCase):
self.assertEqual(provider.acs_url, "http://localhost:8080/saml/acs")
self.assertEqual(provider.issuer, "http://localhost:8080/saml/metadata")
self.assertEqual(provider.sp_binding, SAMLBindings.POST)
self.assertEqual(provider.default_name_id_policy, SAMLNameIDPolicy.EMAIL)
self.assertEqual(
len(provider.property_mappings.all()),
len(SAMLPropertyMapping.objects.exclude(managed__isnull=True)),

View File

@ -1,12 +1,29 @@
"""test decorators api"""
from django.urls import reverse
from guardian.shortcuts import assign_perm
from rest_framework.decorators import action
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.test import APITestCase
from rest_framework.viewsets import ModelViewSet
from authentik.core.models import Application
from authentik.core.tests.utils import create_test_user
from authentik.lib.generators import generate_id
from authentik.lib.tests.utils import get_request
from authentik.rbac.decorators import permission_required
class MVS(ModelViewSet):
queryset = Application.objects.all()
lookup_field = "slug"
@permission_required("authentik_core.view_application", ["authentik_events.view_event"])
@action(detail=True, pagination_class=None, filter_backends=[])
def test(self, request: Request, slug: str):
self.get_object()
return Response(status=200)
class TestAPIDecorators(APITestCase):
@ -18,41 +35,33 @@ class TestAPIDecorators(APITestCase):
def test_obj_perm_denied(self):
"""Test object perm denied"""
self.client.force_login(self.user)
request = get_request("", user=self.user)
app = Application.objects.create(name=generate_id(), slug=generate_id())
response = self.client.get(
reverse("authentik_api:application-metrics", kwargs={"slug": app.slug})
)
response = MVS.as_view({"get": "test"})(request, slug=app.slug)
self.assertEqual(response.status_code, 403)
def test_obj_perm_global(self):
"""Test object perm successful (global)"""
assign_perm("authentik_core.view_application", self.user)
assign_perm("authentik_events.view_event", self.user)
self.client.force_login(self.user)
app = Application.objects.create(name=generate_id(), slug=generate_id())
response = self.client.get(
reverse("authentik_api:application-metrics", kwargs={"slug": app.slug})
)
self.assertEqual(response.status_code, 200)
request = get_request("", user=self.user)
response = MVS.as_view({"get": "test"})(request, slug=app.slug)
self.assertEqual(response.status_code, 200, response.data)
def test_obj_perm_scoped(self):
"""Test object perm successful (scoped)"""
assign_perm("authentik_events.view_event", self.user)
app = Application.objects.create(name=generate_id(), slug=generate_id())
assign_perm("authentik_core.view_application", self.user, app)
self.client.force_login(self.user)
response = self.client.get(
reverse("authentik_api:application-metrics", kwargs={"slug": app.slug})
)
request = get_request("", user=self.user)
response = MVS.as_view({"get": "test"})(request, slug=app.slug)
self.assertEqual(response.status_code, 200)
def test_other_perm_denied(self):
"""Test other perm denied"""
self.client.force_login(self.user)
app = Application.objects.create(name=generate_id(), slug=generate_id())
assign_perm("authentik_core.view_application", self.user, app)
response = self.client.get(
reverse("authentik_api:application-metrics", kwargs={"slug": app.slug})
)
request = get_request("", user=self.user)
response = MVS.as_view({"get": "test"})(request, slug=app.slug)
self.assertEqual(response.status_code, 403)

View File

@ -1,12 +1,13 @@
"""authentik Recovery app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikRecoveryConfig(AppConfig):
class AuthentikRecoveryConfig(ManagedAppConfig):
"""authentik Recovery app config"""
name = "authentik.recovery"
label = "authentik_recovery"
verbose_name = "authentik Recovery"
mountpoint = "recovery/"
default = True

View File

@ -98,13 +98,7 @@ def _get_startup_tasks_default_tenant() -> list[Callable]:
def _get_startup_tasks_all_tenants() -> list[Callable]:
"""Get all tasks to be run on startup for all tenants"""
from authentik.admin.tasks import clear_update_notifications
from authentik.providers.proxy.tasks import proxy_set_defaults
return [
clear_update_notifications,
proxy_set_defaults,
]
return []
@worker_ready.connect

View File

@ -166,6 +166,7 @@ SPECTACULAR_SETTINGS = {
"UserVerificationEnum": "authentik.stages.authenticator_webauthn.models.UserVerification",
"UserTypeEnum": "authentik.core.models.UserTypes",
"OutgoingSyncDeleteAction": "authentik.lib.sync.outgoing.models.OutgoingSyncDeleteAction",
"SAMLNameIDPolicyEnum": "authentik.sources.saml.models.SAMLNameIDPolicy",
},
"ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE": False,
"ENUM_GENERATE_CHOICE_DESCRIPTION": False,

View File

@ -3,25 +3,44 @@
import os
from argparse import ArgumentParser
from unittest import TestCase
from unittest.mock import patch
import pytest
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.test.runner import DiscoverRunner
from structlog.stdlib import get_logger
from authentik.lib.config import CONFIG
from authentik.lib.sentry import sentry_init
from authentik.root.signals import post_startup, pre_startup, startup
from tests.e2e.utils import get_docker_tag
# globally set maxDiff to none to show full assert error
TestCase.maxDiff = None
def get_docker_tag() -> str:
"""Get docker-tag based off of CI variables"""
env_pr_branch = "GITHUB_HEAD_REF"
default_branch = "GITHUB_REF"
branch_name = os.environ.get(default_branch, "main")
if os.environ.get(env_pr_branch, "") != "":
branch_name = os.environ[env_pr_branch]
branch_name = branch_name.replace("refs/heads/", "").replace("/", "-")
return f"gh-{branch_name}"
def patched__get_ct_cached(app_label, codename):
"""Caches `ContentType` instances like its `QuerySet` does."""
return ContentType.objects.get(app_label=app_label, permission__codename=codename)
class PytestTestRunner(DiscoverRunner): # pragma: no cover
"""Runs pytest to discover and run tests."""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.logger = get_logger().bind(runner="pytest")
self.args = []
if self.failfast:
@ -34,22 +53,33 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
if kwargs.get("no_capture", False):
self.args.append("--capture=no")
self._setup_test_environment()
def _setup_test_environment(self):
"""Configure test environment settings"""
settings.TEST = True
settings.CELERY["task_always_eager"] = True
CONFIG.set("events.context_processors.geoip", "tests/GeoLite2-City-Test.mmdb")
CONFIG.set("events.context_processors.asn", "tests/GeoLite2-ASN-Test.mmdb")
CONFIG.set("blueprints_dir", "./blueprints")
CONFIG.set(
"outposts.container_image_base",
f"ghcr.io/goauthentik/dev-%(type)s:{get_docker_tag()}",
)
CONFIG.set("tenants.enabled", False)
CONFIG.set("outposts.disable_embedded_outpost", False)
CONFIG.set("error_reporting.sample_rate", 0)
CONFIG.set("error_reporting.environment", "testing")
CONFIG.set("error_reporting.send_pii", True)
sentry_init()
# Test-specific configuration
test_config = {
"events.context_processors.geoip": "tests/GeoLite2-City-Test.mmdb",
"events.context_processors.asn": "tests/GeoLite2-ASN-Test.mmdb",
"blueprints_dir": "./blueprints",
"outposts.container_image_base": f"ghcr.io/goauthentik/dev-%(type)s:{get_docker_tag()}",
"tenants.enabled": False,
"outposts.disable_embedded_outpost": False,
"error_reporting.sample_rate": 0,
"error_reporting.environment": "testing",
"error_reporting.send_pii": True,
}
for key, value in test_config.items():
CONFIG.set(key, value)
sentry_init()
self.logger.debug("Test environment configured")
# Send startup signals
pre_startup.send(sender=self, mode="test")
startup.send(sender=self, mode="test")
post_startup.send(sender=self, mode="test")
@ -72,7 +102,21 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
help="Disable any capturing of stdout/stderr during tests.",
)
def run_tests(self, test_labels, extra_tests=None, **kwargs):
def _validate_test_label(self, label: str) -> bool:
"""Validate test label format"""
if not label:
return False
# Check for invalid characters, but allow forward slashes and colons
# for paths and pytest markers
invalid_chars = set('\\*?"<>|')
if any(c in label for c in invalid_chars):
self.logger.error("Invalid characters in test label", label=label)
return False
return True
def run_tests(self, test_labels: list[str], extra_tests=None, **kwargs):
"""Run pytest and return the exitcode.
It translates some of Django's test command option to pytest's.
@ -82,10 +126,17 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
The extra_tests argument has been deprecated since Django 5.x
It is kept for compatibility with PyCharm's Django test runner.
"""
if not test_labels:
self.logger.error("No test files specified")
return 1
for label in test_labels:
if not self._validate_test_label(label):
return 1
valid_label_found = False
label_as_path = os.path.abspath(label)
# File path has been specified
if os.path.exists(label_as_path):
self.args.append(label_as_path)
@ -93,24 +144,31 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover
elif "::" in label:
self.args.append(label)
valid_label_found = True
# Convert dotted module path to file_path::class::method
else:
# Check if the label is a dotted module path
path_pieces = label.split(".")
# Check whether only class or class and method are specified
for i in range(-1, -3, -1):
path = os.path.join(*path_pieces[:i]) + ".py"
label_as_path = os.path.abspath(path)
if os.path.exists(label_as_path):
path_method = label_as_path + "::" + "::".join(path_pieces[i:])
self.args.append(path_method)
valid_label_found = True
break
try:
path = os.path.join(*path_pieces[:i]) + ".py"
if os.path.exists(path):
if i < -1:
path_method = path + "::" + "::".join(path_pieces[i:])
self.args.append(path_method)
else:
self.args.append(path)
valid_label_found = True
break
except (TypeError, IndexError):
continue
if not valid_label_found:
raise RuntimeError(
f"One of the test labels: {label!r}, "
f"is not supported. Use a dotted module name or "
f"path instead."
)
self.logger.error("Test file not found", label=label)
return 1
return pytest.main(self.args)
self.logger.info("Running tests", test_files=self.args)
with patch("guardian.shortcuts._get_ct_cached", patched__get_ct_cached):
try:
return pytest.main(self.args)
except Exception as e:
self.logger.error("Error running tests", error=str(e), test_files=self.args)
return 1

View File

@ -1,11 +1,12 @@
"""authentik plex config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikSourcePlexConfig(AppConfig):
class AuthentikSourcePlexConfig(ManagedAppConfig):
"""authentik source plex config"""
name = "authentik.sources.plex"
label = "authentik_sources_plex"
verbose_name = "authentik Sources.Plex"
default = True

View File

@ -0,0 +1,32 @@
# Generated by Django 5.1.11 on 2025-06-18 09:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_sources_saml", "0019_migrate_usersamlsourceconnection_identifier"),
]
operations = [
migrations.AlterField(
model_name="samlsource",
name="name_id_policy",
field=models.TextField(
choices=[
("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "Email"),
("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent", "Persistent"),
("urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName", "X509"),
(
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
"Windows",
),
("urn:oasis:names:tc:SAML:2.0:nameid-format:transient", "Transient"),
("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", "Unspecified"),
],
default="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
help_text="NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent.",
),
),
]

View File

@ -39,6 +39,7 @@ from authentik.sources.saml.processors.constants import (
SAML_NAME_ID_FORMAT_EMAIL,
SAML_NAME_ID_FORMAT_PERSISTENT,
SAML_NAME_ID_FORMAT_TRANSIENT,
SAML_NAME_ID_FORMAT_UNSPECIFIED,
SAML_NAME_ID_FORMAT_WINDOWS,
SAML_NAME_ID_FORMAT_X509,
SHA1,
@ -73,6 +74,7 @@ class SAMLNameIDPolicy(models.TextChoices):
X509 = SAML_NAME_ID_FORMAT_X509
WINDOWS = SAML_NAME_ID_FORMAT_WINDOWS
TRANSIENT = SAML_NAME_ID_FORMAT_TRANSIENT
UNSPECIFIED = SAML_NAME_ID_FORMAT_UNSPECIFIED
class SAMLSource(Source):

View File

@ -1,11 +1,12 @@
"""Authenticator"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageAuthenticatorConfig(AppConfig):
class AuthentikStageAuthenticatorConfig(ManagedAppConfig):
"""Authenticator App config"""
name = "authentik.stages.authenticator"
label = "authentik_stages_authenticator"
verbose_name = "authentik Stages.Authenticator"
default = True

View File

@ -1,11 +1,12 @@
"""SMS"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageAuthenticatorSMSConfig(AppConfig):
class AuthentikStageAuthenticatorSMSConfig(ManagedAppConfig):
"""SMS App config"""
name = "authentik.stages.authenticator_sms"
label = "authentik_stages_authenticator_sms"
verbose_name = "authentik Stages.Authenticator.SMS"
default = True

View File

@ -1,11 +1,12 @@
"""TOTP"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageAuthenticatorTOTPConfig(AppConfig):
class AuthentikStageAuthenticatorTOTPConfig(ManagedAppConfig):
"""TOTP App config"""
name = "authentik.stages.authenticator_totp"
label = "authentik_stages_authenticator_totp"
verbose_name = "authentik Stages.Authenticator.TOTP"
default = True

View File

@ -1,11 +1,12 @@
"""Authenticator Validation Stage"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageAuthenticatorValidateConfig(AppConfig):
class AuthentikStageAuthenticatorValidateConfig(ManagedAppConfig):
"""Authenticator Validation Stage"""
name = "authentik.stages.authenticator_validate"
label = "authentik_stages_authenticator_validate"
verbose_name = "authentik Stages.Authenticator.Validate"
default = True

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,12 @@
"""authentik captcha app"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageCaptchaConfig(AppConfig):
class AuthentikStageCaptchaConfig(ManagedAppConfig):
"""authentik captcha app"""
name = "authentik.stages.captcha"
label = "authentik_stages_captcha"
verbose_name = "authentik Stages.Captcha"
default = True

View File

@ -1,11 +1,12 @@
"""authentik consent app"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageConsentConfig(AppConfig):
class AuthentikStageConsentConfig(ManagedAppConfig):
"""authentik consent app"""
name = "authentik.stages.consent"
label = "authentik_stages_consent"
verbose_name = "authentik Stages.Consent"
default = True

View File

@ -1,11 +1,12 @@
"""authentik deny stage app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageDenyConfig(AppConfig):
class AuthentikStageDenyConfig(ManagedAppConfig):
"""authentik deny stage config"""
name = "authentik.stages.deny"
label = "authentik_stages_deny"
verbose_name = "authentik Stages.Deny"
default = True

View File

@ -1,11 +1,12 @@
"""authentik dummy stage config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageDummyConfig(AppConfig):
class AuthentikStageDummyConfig(ManagedAppConfig):
"""authentik dummy stage config"""
name = "authentik.stages.dummy"
label = "authentik_stages_dummy"
verbose_name = "authentik Stages.Dummy"
default = True

View File

@ -100,9 +100,11 @@ def send_mail(
# Because we use the Message-ID as UID for the task, manually assign it
message_object.extra_headers["Message-ID"] = message_id
# Add the logo (we can't add it in the previous message since MIMEImage
# can't be converted to json)
message_object.attach(logo_data())
# Add the logo if it is used in the email body (we can't add it in the
# previous message since MIMEImage can't be converted to json)
body = get_email_body(message_object)
if "cid:logo" in body:
message_object.attach(logo_data())
if (
message_object.to

View File

@ -96,7 +96,7 @@
<table width="100%" style="background-color: #FFFFFF; border-spacing: 0; margin-top: 15px;">
<tr height="80">
<td align="center" style="padding: 20px 0;">
<img src="{% block logo_url %}cid:logo.png{% endblock %}" border="0=" alt="authentik logo" class="flexibleImage logo">
<img src="{% block logo_url %}cid:logo{% endblock %}" border="0=" alt="authentik logo" class="flexibleImage logo">
</td>
</tr>
{% block content %}

View File

@ -19,7 +19,8 @@ def logo_data() -> MIMEImage:
path = Path("web/dist/assets/icons/icon_left_brand.png")
with open(path, "rb") as _logo_file:
logo = MIMEImage(_logo_file.read())
logo.add_header("Content-ID", "logo.png")
logo.add_header("Content-ID", "<logo>")
logo.add_header("Content-Disposition", "inline", filename="logo.png")
return logo

View File

@ -1,11 +1,12 @@
"""authentik identification stage app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageIdentificationConfig(AppConfig):
class AuthentikStageIdentificationConfig(ManagedAppConfig):
"""authentik identification stage config"""
name = "authentik.stages.identification"
label = "authentik_stages_identification"
verbose_name = "authentik Stages.Identification"
default = True

View File

@ -1,11 +1,12 @@
"""authentik invitation stage app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageInvitationConfig(AppConfig):
class AuthentikStageInvitationConfig(ManagedAppConfig):
"""authentik invitation stage config"""
name = "authentik.stages.invitation"
label = "authentik_stages_invitation"
verbose_name = "authentik Stages.Invitation"
default = True

View File

@ -1,11 +1,12 @@
"""authentik core app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStagePasswordConfig(AppConfig):
class AuthentikStagePasswordConfig(ManagedAppConfig):
"""authentik password stage config"""
name = "authentik.stages.password"
label = "authentik_stages_password"
verbose_name = "authentik Stages.Password"
default = True

View File

@ -1,11 +1,12 @@
"""authentik prompt stage app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStagePromptConfig(AppConfig):
class AuthentikStagePromptConfig(ManagedAppConfig):
"""authentik prompt stage config"""
name = "authentik.stages.prompt"
label = "authentik_stages_prompt"
verbose_name = "authentik Stages.Prompt"
default = True

View File

@ -1,11 +1,12 @@
"""authentik redirect app"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageRedirectConfig(AppConfig):
class AuthentikStageRedirectConfig(ManagedAppConfig):
"""authentik redirect app"""
name = "authentik.stages.redirect"
label = "authentik_stages_redirect"
verbose_name = "authentik Stages.Redirect"
default = True

View File

@ -1,11 +1,12 @@
"""authentik delete stage app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageUserDeleteConfig(AppConfig):
class AuthentikStageUserDeleteConfig(ManagedAppConfig):
"""authentik delete stage config"""
name = "authentik.stages.user_delete"
label = "authentik_stages_user_delete"
verbose_name = "authentik Stages.User Delete"
default = True

View File

@ -1,11 +1,12 @@
"""authentik login stage app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageUserLoginConfig(AppConfig):
class AuthentikStageUserLoginConfig(ManagedAppConfig):
"""authentik login stage config"""
name = "authentik.stages.user_login"
label = "authentik_stages_user_login"
verbose_name = "authentik Stages.User Login"
default = True

View File

@ -1,11 +1,12 @@
"""authentik logout stage app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageUserLogoutConfig(AppConfig):
class AuthentikStageUserLogoutConfig(ManagedAppConfig):
"""authentik logout stage config"""
name = "authentik.stages.user_logout"
label = "authentik_stages_user_logout"
verbose_name = "authentik Stages.User Logout"
default = True

View File

@ -1,11 +1,12 @@
"""authentik write stage app config"""
from django.apps import AppConfig
from authentik.blueprints.apps import ManagedAppConfig
class AuthentikStageUserWriteConfig(AppConfig):
class AuthentikStageUserWriteConfig(ManagedAppConfig):
"""authentik write stage config"""
name = "authentik.stages.user_write"
label = "authentik_stages_user_write"
verbose_name = "authentik Stages.User Write"
default = True

File diff suppressed because it is too large Load Diff

View File

@ -2,17 +2,13 @@ package main
import (
"fmt"
"net/url"
"os"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"goauthentik.io/internal/common"
"goauthentik.io/internal/config"
"goauthentik.io/internal/constants"
"goauthentik.io/internal/debug"
"goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/ak/entrypoint"
"goauthentik.io/internal/outpost/ak/healthcheck"
"goauthentik.io/internal/outpost/ldap"
)
@ -25,65 +21,15 @@ Required environment variables:
- AUTHENTIK_INSECURE: Skip SSL Certificate verification`
var rootCmd = &cobra.Command{
Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.JSONFormatter{
FieldMap: log.FieldMap{
log.FieldKeyMsg: "event",
log.FieldKeyTime: "timestamp",
},
DisableHTMLEscape: true,
})
},
Run: func(cmd *cobra.Command, args []string) {
debug.EnableDebugServer()
akURL := config.Get().AuthentikHost
if akURL == "" {
fmt.Println("env AUTHENTIK_HOST not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
akToken := config.Get().AuthentikToken
if akToken == "" {
fmt.Println("env AUTHENTIK_TOKEN not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
akURLActual, err := url.Parse(akURL)
Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: common.PreRun,
RunE: func(cmd *cobra.Command, args []string) error {
err := entrypoint.OutpostMain("authentik.outpost.ldap", ldap.NewServer)
if err != nil {
fmt.Println(err)
fmt.Println(helpMessage)
os.Exit(1)
}
ex := common.Init()
defer common.Defer()
go func() {
for {
<-ex
os.Exit(0)
}
}()
ac := ak.NewAPIController(*akURLActual, akToken)
if ac == nil {
os.Exit(1)
}
defer ac.Shutdown()
ac.Server = ldap.NewServer(ac)
err = ac.Start()
if err != nil {
log.WithError(err).Panic("Failed to run server")
}
for {
<-ex
}
return err
},
}

View File

@ -2,17 +2,13 @@ package main
import (
"fmt"
"net/url"
"os"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"goauthentik.io/internal/common"
"goauthentik.io/internal/config"
"goauthentik.io/internal/constants"
"goauthentik.io/internal/debug"
"goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/ak/entrypoint"
"goauthentik.io/internal/outpost/ak/healthcheck"
"goauthentik.io/internal/outpost/proxyv2"
)
@ -28,65 +24,15 @@ Optionally, you can set these:
- AUTHENTIK_HOST_BROWSER: URL to use in the browser, when it differs from AUTHENTIK_HOST`
var rootCmd = &cobra.Command{
Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.JSONFormatter{
FieldMap: log.FieldMap{
log.FieldKeyMsg: "event",
log.FieldKeyTime: "timestamp",
},
DisableHTMLEscape: true,
})
},
Run: func(cmd *cobra.Command, args []string) {
debug.EnableDebugServer()
akURL := config.Get().AuthentikHost
if akURL == "" {
fmt.Println("env AUTHENTIK_HOST not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
akToken := config.Get().AuthentikToken
if akToken == "" {
fmt.Println("env AUTHENTIK_TOKEN not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
akURLActual, err := url.Parse(akURL)
Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: common.PreRun,
RunE: func(cmd *cobra.Command, args []string) error {
err := entrypoint.OutpostMain("authentik.outpost.proxy", proxyv2.NewProxyServer)
if err != nil {
fmt.Println(err)
fmt.Println(helpMessage)
os.Exit(1)
}
ex := common.Init()
defer common.Defer()
go func() {
for {
<-ex
os.Exit(0)
}
}()
ac := ak.NewAPIController(*akURLActual, akToken)
if ac == nil {
os.Exit(1)
}
defer ac.Shutdown()
ac.Server = proxyv2.NewProxyServer(ac)
err = ac.Start()
if err != nil {
log.WithError(err).Panic("Failed to run server")
}
for {
<-ex
}
return err
},
}

View File

@ -2,16 +2,13 @@ package main
import (
"fmt"
"net/url"
"os"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"goauthentik.io/internal/common"
"goauthentik.io/internal/constants"
"goauthentik.io/internal/debug"
"goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/ak/entrypoint"
"goauthentik.io/internal/outpost/ak/healthcheck"
"goauthentik.io/internal/outpost/rac"
)
@ -24,65 +21,15 @@ Required environment variables:
- AUTHENTIK_INSECURE: Skip SSL Certificate verification`
var rootCmd = &cobra.Command{
Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.JSONFormatter{
FieldMap: log.FieldMap{
log.FieldKeyMsg: "event",
log.FieldKeyTime: "timestamp",
},
DisableHTMLEscape: true,
})
},
Run: func(cmd *cobra.Command, args []string) {
debug.EnableDebugServer()
akURL, found := os.LookupEnv("AUTHENTIK_HOST")
if !found {
fmt.Println("env AUTHENTIK_HOST not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
akToken, found := os.LookupEnv("AUTHENTIK_TOKEN")
if !found {
fmt.Println("env AUTHENTIK_TOKEN not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
akURLActual, err := url.Parse(akURL)
Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: common.PreRun,
RunE: func(cmd *cobra.Command, args []string) error {
err := entrypoint.OutpostMain("authentik.outpost.rac", rac.NewServer)
if err != nil {
fmt.Println(err)
fmt.Println(helpMessage)
os.Exit(1)
}
ex := common.Init()
defer common.Defer()
go func() {
for {
<-ex
os.Exit(0)
}
}()
ac := ak.NewAPIController(*akURLActual, akToken)
if ac == nil {
os.Exit(1)
}
defer ac.Shutdown()
ac.Server = rac.NewServer(ac)
err = ac.Start()
if err != nil {
log.WithError(err).Panic("Failed to run server")
}
for {
<-ex
}
return err
},
}

View File

@ -2,16 +2,13 @@ package main
import (
"fmt"
"net/url"
"os"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"goauthentik.io/internal/common"
"goauthentik.io/internal/constants"
"goauthentik.io/internal/debug"
"goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/ak/entrypoint"
"goauthentik.io/internal/outpost/ak/healthcheck"
"goauthentik.io/internal/outpost/radius"
)
@ -24,65 +21,15 @@ Required environment variables:
- AUTHENTIK_INSECURE: Skip SSL Certificate verification`
var rootCmd = &cobra.Command{
Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.JSONFormatter{
FieldMap: log.FieldMap{
log.FieldKeyMsg: "event",
log.FieldKeyTime: "timestamp",
},
DisableHTMLEscape: true,
})
},
Run: func(cmd *cobra.Command, args []string) {
debug.EnableDebugServer()
akURL, found := os.LookupEnv("AUTHENTIK_HOST")
if !found {
fmt.Println("env AUTHENTIK_HOST not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
akToken, found := os.LookupEnv("AUTHENTIK_TOKEN")
if !found {
fmt.Println("env AUTHENTIK_TOKEN not set!")
fmt.Println(helpMessage)
os.Exit(1)
}
akURLActual, err := url.Parse(akURL)
Long: helpMessage,
Version: constants.FullVersion(),
PersistentPreRun: common.PreRun,
RunE: func(cmd *cobra.Command, args []string) error {
err := entrypoint.OutpostMain("authentik.outpost.radius", radius.NewServer)
if err != nil {
fmt.Println(err)
fmt.Println(helpMessage)
os.Exit(1)
}
ex := common.Init()
defer common.Defer()
go func() {
for {
<-ex
os.Exit(0)
}
}()
ac := ak.NewAPIController(*akURLActual, akToken)
if ac == nil {
os.Exit(1)
}
defer ac.Shutdown()
ac.Server = radius.NewServer(ac)
err = ac.Start()
if err != nil {
log.WithError(err).Panic("Failed to run server")
}
for {
<-ex
}
return err
},
}

View File

@ -22,21 +22,12 @@ import (
)
var rootCmd = &cobra.Command{
Use: "authentik",
Short: "Start authentik instance",
Version: constants.FullVersion(),
PersistentPreRun: func(cmd *cobra.Command, args []string) {
log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.JSONFormatter{
FieldMap: log.FieldMap{
log.FieldKeyMsg: "event",
log.FieldKeyTime: "timestamp",
},
DisableHTMLEscape: true,
})
},
Use: "authentik",
Short: "Start authentik instance",
Version: constants.FullVersion(),
PersistentPreRun: common.PreRun,
Run: func(cmd *cobra.Command, args []string) {
debug.EnableDebugServer()
debug.EnableDebugServer("authentik.core")
l := log.WithField("logger", "authentik.root")
if config.Get().ErrorReporting.Enabled {
@ -99,7 +90,7 @@ func attemptProxyStart(ws *web.WebServer, u *url.URL) {
})
srv := proxyv2.NewProxyServer(ac)
ws.ProxyServer = srv
ws.ProxyServer = srv.(*proxyv2.ProxyServer)
ac.Server = srv
l.Debug("attempting to start outpost")
err := ac.StartBackgroundTasks()

View File

@ -31,7 +31,7 @@ services:
volumes:
- redis:/data
server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.0}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
restart: unless-stopped
command: server
environment:
@ -55,7 +55,7 @@ services:
redis:
condition: service_healthy
worker:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.0}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
restart: unless-stopped
command: worker
environment:

12
go.mod
View File

@ -4,6 +4,7 @@ go 1.24.0
require (
beryju.io/ldap v0.1.0
github.com/avast/retry-go/v4 v4.6.1
github.com/coreos/go-oidc/v3 v3.14.1
github.com/getsentry/sentry-go v0.33.0
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
@ -16,21 +17,22 @@ require (
github.com/gorilla/securecookie v1.1.2
github.com/gorilla/sessions v1.4.0
github.com/gorilla/websocket v1.5.3
github.com/jellydator/ttlcache/v3 v3.3.0
github.com/grafana/pyroscope-go v1.2.2
github.com/jellydator/ttlcache/v3 v3.4.0
github.com/mitchellh/mapstructure v1.5.0
github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
github.com/pires/go-proxyproto v0.8.1
github.com/prometheus/client_golang v1.22.0
github.com/redis/go-redis/v9 v9.9.0
github.com/redis/go-redis/v9 v9.10.0
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/wwt/guac v1.3.2
goauthentik.io/api/v3 v3.2025041.4
goauthentik.io/api/v3 v3.2025062.1
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
golang.org/x/oauth2 v0.30.0
golang.org/x/sync v0.14.0
golang.org/x/sync v0.15.0
gopkg.in/yaml.v2 v2.4.0
layeh.com/radius v0.0.0-20210819152912-ad72663a72ab
)
@ -58,8 +60,10 @@ require (
github.com/go-openapi/strfmt v0.23.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/validate v0.24.0 // indirect
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/oklog/ulid v1.3.1 // indirect

24
go.sum
View File

@ -41,6 +41,8 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk=
github.com/avast/retry-go/v4 v4.6.1/go.mod h1:V6oF8njAwxJ5gRo1Q7Cxab24xs5NCWZBeaHHBklR8mA=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
@ -178,6 +180,10 @@ github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2e
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grafana/pyroscope-go v1.2.2 h1:uvKCyZMD724RkaCEMrSTC38Yn7AnFe8S2wiAIYdDPCE=
github.com/grafana/pyroscope-go v1.2.2/go.mod h1:zzT9QXQAp2Iz2ZdS216UiV8y9uXJYQiGE1q8v1FyhqU=
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 h1:iwOtYXeeVSAeYefJNaxDytgjKtUuKQbJqgAIjlnicKg=
github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -197,8 +203,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc=
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
@ -245,8 +251,8 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/redis/go-redis/v9 v9.9.0 h1:URbPQ4xVQSQhZ27WMQVmZSo3uT3pL+4IdHVcYq2nVfM=
github.com/redis/go-redis/v9 v9.9.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/redis/go-redis/v9 v9.10.0 h1:FxwK3eV8p/CQa0Ch276C7u2d0eNC9kCmAYQ7mCXCzVs=
github.com/redis/go-redis/v9 v9.10.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
@ -262,6 +268,8 @@ github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -290,8 +298,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.2025041.4 h1:cGqzWYnUHrWDoaXWDpIL/kWnX9sFrIhkYDye0P0OEAo=
goauthentik.io/api/v3 v3.2025041.4/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
goauthentik.io/api/v3 v3.2025062.1 h1:spvILDpDDWJNO3pM6QGqmryx6NvSchr1E8H60J/XUCA=
goauthentik.io/api/v3 v3.2025062.1/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -376,8 +384,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

17
internal/common/prerun.go Normal file
View File

@ -0,0 +1,17 @@
package common
import (
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
func PreRun(cmd *cobra.Command, args []string) {
log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.JSONFormatter{
FieldMap: log.FieldMap{
log.FieldKeyMsg: "event",
log.FieldKeyTime: "timestamp",
},
DisableHTMLEscape: true,
})
}

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