* web: fix Brand CSS not applied to nested Shadow DOM components
After PR #17444, Brand CSS was only applied when ThemeChangeEvent fired.
Components created after the initial event never received the custom styles.
This fix immediately applies Brand CSS when a style root is set, ensuring
all nested Shadow DOM components (like flow stages) receive brand styling
regardless of when they are created.
* Update web/src/elements/Base.ts
Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
* Clarify.
---------
Signed-off-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
* Move inline styles into separate file.
* Fix preferred order of captcha vendor discovery.
* Clean up mutation and resize observer lifecycle.
* Flesh out controllers.
* Tidy refresh.
* Fix incompatibilities with Storybook.
* Flesh out captcha stories.
* Bump package.
* Flesh out stories.
* Move inline styles into separate file.
* Fix preferred order of captcha vendor discovery.
* Clean up mutation and resize observer lifecycle.
* Flesh out controllers.
* Tidy refresh.
* Remove unused.
* Bump package.
* clean up roles and permissions
This was purposefully not included in `2025.12` to split the changes up.
The main content of this patch is in the migrations. Everything else
follows more or less automatically.
* add breaking change warning to release notes
* add `ak_groups` --> `groups` deprecated proxy
* fixup! add `ak_groups` --> `groups` deprecated proxy
* fixup! add `ak_groups` --> `groups` deprecated proxy
* fixup! add `ak_groups` --> `groups` deprecated proxy
* add configuration warning to default notifications blueprint
* add rudimentary tests for User.ak_groups
* remove no longer used permissions
* clarify deprecation
Co-authored-by: Jens L. <jens@goauthentik.io>
Signed-off-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com>
* remove integration changes
These will be included in a separate PR once this is released.
---------
Signed-off-by: Simonyi Gergő <28359278+gergosimonyi@users.noreply.github.com>
Co-authored-by: Jens L. <jens@goauthentik.io>
* providers/scim: modify user- and group syncing behavior
rename filtergroup to groupfilters and allow multiple values
only sync groups which are in the scimprovider's attribute \"group_filters\"
only sync users which are entitled to view the scimprovider's application
* Update authentik/providers/scim/api/providers.py
Signed-off-by: Immanuel von Neumann <45020096+ImmanuelVonNeumann@users.noreply.github.com>
* fix(authentik/scim): update schema.yml and test name
* merge migrations
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* providers/scim: fix linting
* format
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
* filter eagerly
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
---------
Signed-off-by: Immanuel von Neumann <45020096+ImmanuelVonNeumann@users.noreply.github.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
* web: display custom attributes on admin view pages
Overview:
Add a reusable ak-object-attributes-card component that displays custom attributes on User, Group, and Device admin view pages.
This allows admins to see custom attributes directly on the overview tab without needing to open the edit form.
The component:
- Filters out system attributes (goauthentik.io/* prefixed keys)
- Optionally excludes the notes attribute
- Renders values based on type: booleans as status labels, arrays as comma-separated lists, objects as formatted JSON
Testing:
1. Navigate to Admin > Identity > Users > [any user]
2. Verify "Custom Attributes" card appears below Changelog
3. Add custom attributes via Edit form:
```
{
"department": "Engineering",
"employee_id": 12345,
"is_contractor": false,
"is_manager": true,
"skills": ["Python", "TypeScript", "Go"],
"office_location": {
"building": "HQ",
"floor": 3,
"desk": "A-42"
},
"notes": "This should NOT appear in Custom Attributes card",
"goauthentik.io/user/sources": ["should-be-filtered"]
}
```
4. Confirm they appear in the card, system attributes are hidden
5. Repeat for Groups and Devices
Screenshot:
<!-- todo -->
Motivation:
Admins frequently need to view custom attributes on users, groups, and devices. Currently this requires clicking Edit and scrolling to the attributes field.
Closes: https://github.com/goauthentik/authentik/issues/18625
* web: Ken's suggestion
* Revert "admin/files: support %(theme)s variable in media file paths (#19108)"
This reverts commit 1a963d27c8.
* admin/files: add centralized theme variable support for file URLs
Overview:
Adds support for `%(theme)s` placeholder in file paths, which allows theme-specific assets (like logos, backgrounds, icons) to be served based on the user's current theme (light/dark).
This replaces the previous implementation (reverted in this PR) which only handled theme substitution in the Go file backend and instead uses the new approach which centralizes theme logic and works across both backends.
Testing:
Try out the following for the file and s3 backend:
* Ensure themed images load
* Ensure non-themed images load
Motivation:
Internal
* brands: fix tests
* admin/files: s3 backend: fix tests
.xyz is a known MIME type for chemical/molecular structure files
* admin/files: api: fix tests
* core: fix tests
* admin/files: manager: fix tests
* admin/files: Support themed urls for passthrough backend
* admin/files: Create and use ThemedUrlsSerializer
* root: Regenerate
* core: Add read_only=True since it's a computed field from the model
* root: Regenerate
* web: Use the ThemedUrlsSerializer
* web, core: Fix frontend build
* core: Lint
* admin/files: Fix tests following CodeQL
* flows, providers: fix tests
* web/elements: stabilize dual-select status height
Overview:
Reserve a stable two-line height for the selected-status row to minimize layout shifts on small screens, and use proper singular/plural wording for status messages.
Testing:
Behavior shown in linked issue
Motivation:
Avoid accidental removals caused by status text reflow/jumping on narrow
viewports.
Closes: https://github.com/goauthentik/authentik/issues/19732
* web: Comment to explain first suggestion
Ref: https://authentiksecurity.slack.com/archives/C08C0SCU2JV/p1769471926609429
Overview:
Normalize row-action icon padding and inherit icon color through
tooltips to avoid misalignment and false "active" styling on the Tokens
page.
Testing:
Replicate linked issue
Motivation:
Fix minor visual inconsistencies in action icons.
Closes https://github.com/goauthentik/authentik/issues/19315
* Flesh out proxy form clean up.
* Flesh out StrictUnsafe helper, slotted labels.
* Clean up usage of proxy form.
* Allow forms to render outside of modals.
* Fix linter.
* web/admin: fix file upload not preserving extension for custom names with dots
Overview:
The `hasBasenameExtension()` function in `FileUploadForm.ts` incorrectly determined whether a custom filename already had an extension by checking if it contained any dot at position > 0.
This caused filenames like "e._.e" to be treated as having an extension, so the original file's extension was not appended. The file would be saved as "e._.e" instead of "e._.e.jpg", which caused `mimetypes.guess_type()` to return `None` (since ".e" is not a recognized extension) and the backend to fall back to "application/octet-stream".
Removed `hasBasenameExtension()` entirely. Since the UI explicitly states "Optionally rename the file (without extension)", we now always append the original file's extension when a custom name is provided.
Testing:
1. Upload a JPG file with custom name "e" --> saves as "e.jpg", and is detected as "image/jpeg"
2. Upload a JPG file with custom name "e._.e" --> now saves as "e._.e.jpg",and is detected as "image/jpeg"
Motivation:
Fixes incorrect MIME type detection for uploaded files when users provide custom filenames containing dots.
* web: lint
* web: Ken's suggestion
Overview:
When the default application field was left blank, the form was sending the string "undefined" instead of null, and that caused a UUID validation error on the backend.
The `.value` callback was using optional chaining which returns `undefined` when the item is null, and this was being converted to the string "undefined" during form serialization. Changed to return `null` explicitly when no application is selected.
Testing:
On main, attempt to set no default application. Then, try again on the
PR branch.
Motitation:
Fixes bug
* web/admin: fix captcha stage provider selector not showing saved value
Overview:
When editing an existing captcha stage, the Provider Type dropdown always showed "Google reCAPTCHA v2" (the first option) instead of the actual configured provider (e.g. Cloudflare Turnstile).
The root cause was using `.value=${this.selectedProvider}` on the `<select>` element, which doesn't work reliably in Lit templates. the browser selects the first `<option>` by default before the property binding takes effect.
Fixed by adding the `selected` attribute directly to each `<option>` element.
Testing:
1. Create a new captcha stage with Cloudflare Turnstile
2. Save and close the form
3. Edit the stage again
4. Verify the Provider Type dropdown shows "Cloudflare Turnstile" instead of "Google reCAPTCHA v2"
Motivation:
Closes https://github.com/goauthentik/authentik/issues/19550
* web/admin: default captcha provider selector to first option
Matches previous behavior and makes it slightly friendlier than a blank page without any help.
* 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.
* website: fix bad escaping of URLs in release notes
## What
Fixes bad escaping of URLs in the release notes that resulted in mangled output.
v2024.6.4 had entries that looked like this:
```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```
v2025.4.md had entries that looked like this:
```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```
A couple of straightforward search-and-replaces has fixed the issue.
## Notes
Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.
@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.
The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.
* web: Remove PFBase.
* Remove stub.
* Just keeping this around.
* web/maintenance: deprecate PFBase in favor of an adopted stylesheet
# What !?!?!?
Removes `PFBase` from all components.
# Why !?!?!?
In `AkElement`, there was this code:
protected static override finalizeStyles(styles?: CSSResultGroup): CSSResultOrNative[] {
if (!styles) return [$PFBase, $AKBase];
if (!Array.isArray(styles)) return [$PFBase, createCSSResult(styles), $PFBase, $AKBase];
return [
$PFBase,
// ---
...(styles.flat() as CSSResultOrNative[]).map(createCSSResult),
$AKBase,
];
}
I’ve refined this:
protected static override finalizeStyles(styles: CSSResultGroup = []): CSSResultOrNative[] {
const elementStyles = [
$PFBase,
// Route around TSC`s known-to-fail typechecking of `.flat(Infinity)`. Removes types.
...([styles] as Array<unknown>).flat(Infinity),
$AKBase,
// Restore types. Safe: we control AKBase and PFBase in this file, and `styles` are
// typed on function signature.
] as CSSResultOrNative[];
// Remove duplicates in reverse order to preserve last-insert-wins semantics of CSS.
const elementSet = new Set(elementStyles.reverse());
// Reverse again because the return type is an array, and process as a CSSResult
return Array.from(elementSet).reverse().map(createCSSResult);
}
… with the duplication removal documented in Lit 3.0. `styles` defaults to an array, is cast to an array, then automatically flattented before the deduplication is run.
With this, both PFBase and AKBase are automatically included with each and every component that inherits from `AKElement`. At that point, the inclusion of `PFBase` interface-wide made no sense.
So they had to be removed:
$ for i in $(rg -t typescript -l PFBase | rg -v 'elements/Base\.ts') ; do \
perl -pi.bak -e 's{import PFBase from ".patternfly/patternfly/patternfly-base.css";}{}' "$i" ; \
done
$ for i in $(rg -t typescript -l PFBase | rg -v 'elements/Base\.ts') ; do \
perl -pi.bak -e 's/PFBase,//' "$i" ; \
done
This commit removes 131 `import` statements from the source code. As a result, the bundle is about 27K smaller… which admittedly is about 0.2% smaller than before. Ah, well. “Every little bit helps,” right?
* Update comment to point to semantic rules for `finalizeStyles` in Lit reactive-element
* Yeah, didn't need the analysis files lying around.
* Merge confirmed
---------
Co-authored-by: Teffen Ellis <teffen@goauthentik.io>
Overview:
Reduce vertical padding on ak-form-group sections to create tighter spacing between collapsible form sections.
- Reduce summary padding-block from 1rem to 0.5rem when open
- Reduce summary padding-block to 0.25rem when closed
- Reduce content bottom padding from 1rem to 0.5rem
- Remove debug red outline on marker hover
Testing:
Visiting the UI
Screenshots:
Before:
<!-- TODO -->
After:
<!-- TODO -->
Motivation:
Tooooo muchhhh spaceeeeee wasssstedddd
* web/forms: fix forms not resetting state when modal closes
Overview:
Forms were not properly resetting their state when closing modals, which caused stale values to persist when reopening forms. This affected all forms with @state() decorated properties.
Testing:
1. Create any item (user, token, application, etc.), close modal
2. Click Create again, form should show default/empty values
3. Edit an item, cancel, click Create - form should be empty
4. Edit an item, cancel, edit same item - should show correct data
Motivation:
Form inputs retained values from previous create/edit operations.
* Fix linter errors, types.
* Add property accessors, types.
---------
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
* web/forms: fix invalid date error for empty datetime-local inputs
Overview:
When a datetime-local input is empty, `valueAsNumber` returns `NaN` and `new Date("")` creates an Invalid Date. Previously, form serialization passed these invalid dates to the API, which caused "RangeError: Invalid time value" when `toISOString()` was called. Now empty datetime inputs correctly serialize to `null`.
Testing:
1. Go to Directory > Tokens and App passwords
2. Create or edit a token
3. Uncheck the "Expiring" checkbox
4. Save the token
5. Verify no error occurs and token is saved without expiry
Motivation:
Closes: https://github.com/goauthentik/authentik/issues/19558
* web: lint
* Add fallback weights to accept language header.
* Fix context cache lifecycle, compatibility.
* Fix stale locale on API provided values.
* Update locale after changing user settings.
* Remove legacy XLF files.
* Apply suggestion from @BeryJu
Signed-off-by: Jens L. <jens@beryju.org>
---------
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Jens L. <jens@goauthentik.io>
* 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.
* website: fix bad escaping of URLs in release notes
## What
Fixes bad escaping of URLs in the release notes that resulted in mangled output.
v2024.6.4 had entries that looked like this:
```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```
v2025.4.md had entries that looked like this:
```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```
A couple of straightforward search-and-replaces has fixed the issue.
## Notes
Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.
@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.
The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.
* web/bug/hidden-secrets-not-propagating
# What
This commit updates ak-secret-text-input, adding the `name` attribute to all valid input fields and updating the value writer to match those of known-working components, to ensure that either variety of the display is fully and correctly updated with the content of the hidden secret.
# Why
The hidden input field is the one that HorizontalFormElement was expecting to read its value from, but that field never received a `name` because it wasn’t present when the field was first updated.
HorizontalFormElement writes the `name` field to the first `<input>` it finds. That was the “dummy” input field, which has no working value.
Form ignored the input element because the value it read came with an undefined name.
Object-oriented state management sometimes bites.
---------
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
* 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.
* website: fix bad escaping of URLs in release notes
## What
Fixes bad escaping of URLs in the release notes that resulted in mangled output.
v2024.6.4 had entries that looked like this:
```
##### `GET` /providers/google_workspace/{#123;id}#125;/
```
v2025.4.md had entries that looked like this:
```
##### `GET` /policies/unique_password/{#125;#123;policy_uuid}/
```
A couple of straightforward search-and-replaces has fixed the issue.
## Notes
Two of the release notes had bad escaping of URLs. I'm not sure how the error was made or got past,
but it was obvious when visiting the page.
@Beryju suggested that the bug is due to our using `{...}` to symbolize parameters in a URL while
Docusaurus wants to interpret `{...}` as an internal template instruction, resulting in odd
behavior. In either case, docusarus interpreted the hashtagged entries as links to unrelated issues
in Github (the same two issues, which were "bump version of pylint" and "bump version of sentry"),
which could be very confusing.
The inconsistencies between the two releases, and the working releases, suggests that the error was
introduced manually.
* web/admin: always retrieve selected provider when editing the application
# What
Re-writes the `fetch` function for ak-provider-search-input so that, if there’s an assigned value and it does not appear in the currently retrieved list of providers, prepend it to the list so that it is always present and always selectable.
# Why
Our pagination windows can restrict the list of objects retrieved from the server, and when we’re chasing composite objects we have to retrieve the displayable elements of that object from their respective tables. This combination means that a paginated retrieval may not have the object indicated by the parent object’s PK for that object collection. We have to retrieve it separately if it’s not in the current collection.
This problem is probably endemic to some of our design decisions.