* ## What
window.authentik.flow = {
"layout": "{{ flow.layout }}",
+ "background": "{{ flow.background }}",
+ "title": "{{ flow.title }}",
};
Amends the `flow.html` template and `GlobalAuthentik` parser to include new parameters, `background` and `title`, in the flow-specific part of the configuration written to the HTML `<head>` object, and to provide those parameters to client code.
## Why
The `layout` is start-up critical: it tells the Flow interface how the admin wants the Flow page to look, and allows the HTML and CSS to be pre-aligned to that condition. `layout` is determined on a per-Flow bases, not a per-Stage basis; Flows are derived from a tuple of `(Brand, Application?)`, where the opening policy *may* direct a user to a different flow if the user reached authentik via a redirect from a specific application, but will otherwise fall back to the default Flow for the Brand.
The `background` is a field that is required if the `Flow`’s layout is of type `frame_background`; in this case, the part of the viewport not dedicated to the FlowExecutor is reserved for an `<iframe>` that will be filled in with whatever the administrator specifies. Although this gives it the same priority as `layout` (whether it’s provided or undefined) for describing the [chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome) around a challenge, it is currently not provided to the application in the start-up config; it is provided in the `challenge` and renders the IFrame as part of the initial challenge.
This patch fixes that; if `layout` is provided, `background` ought to be as well, even if it’s empty. The execution of a Challenge ought not have any influence over the look and feel of the Flow-defined appearance *around* that Challenge.
I have added `title` as well; with that, all of the current theme-and-appearance related configuration details are placed into `<head>` and can be removed from the FlowExecutor.
Server-side, `background` is currently specified: `background = FileField(blank=True, default="")` which is … interesting since we also appear to store URLs in it. I don’t see anything in the FlowSerializer that would change that from a client’s point of view.
This patch furthers the effort to separate flow execution from flow presentation.
- \[🐰\] The code has been formatted (`make web`)
* web/bugfix: Device user/group/policy bindings not being recorded correctly
## [Issue 22387](https://github.com/goauthentik/authentik/issues/22387)
> When manually binding a user to a device via Admin → Endpoints → Devices → \[Device\] → Users/Groups tab → Create or bind, the binding is incorrectly created as a PolicyBinding (authentik_policies) instead of a DeviceUserBinding (authentik_endpoints).
>
> As a result, the Users/Groups tabs on the Device detail page remain empty even after the binding is created.
## What has been changed:
A new flag, `no-wizard`, has been added to the attributes taken by `ak-bound-policies-list`; when set, this flag overrides the default behavior of offering `ak-policy-wizard`, and instead falls back to `ak-policy-binding-form`, which has the correct behavior. This limits the capability to create new policies for devices, but most of the time admins want to bind an existing User or Group, so this is probably not a large takeaway at the moment.
## Why
This is an annoying bug. As I understand the problem, `DeviceUserBindingForm` is the *only* feature that inherits from `PolicyBindingForm`. It is the `DeviceUserBindingForm`, not the wizard, that supports calling the `endpointsDeviceBindings(Update/Create)` method correctly. In the long term, we could do some sort of inheritance / endpoint override thing with the wizard, but for the moment that’s a bigger lift.
The simplest fix was to add a flag to *force* `BoundPoliciesList` to pick the (overridable) `*BindingForm` over the (not so overridable) wizard; this passes through the inheritance chain from `BoundDeviceUsersList` to trigger the correct behavior.
## Other fixes
We duplicate both the “validate policy type” and “clean binding to be sent” code in multiple places; I have de-duplicated them.
What is authentik?
authentik is an open-source Identity Provider (IdP) for modern SSO. It supports SAML, OAuth2/OIDC, LDAP, RADIUS, and more, designed for self-hosting from small labs to large production clusters.
Our enterprise offering is available for organizations to securely replace existing IdPs such as Okta, Auth0, Entra ID, and Ping Identity for robust, large-scale identity management.
Installation
- Docker Compose: recommended for small/test setups. See the documentation.
- Kubernetes (Helm Chart): recommended for larger setups. See the documentation and the Helm chart repository.
- AWS CloudFormation: deploy on AWS using our official templates. See the documentation.
- DigitalOcean Marketplace: one-click deployment via the official Marketplace app. See the app listing.
Screenshots
| Light | Dark |
|---|---|
![]() |
![]() |
![]() |
![]() |
Development and contributions
See the Developer Documentation for information about setting up local build environments, testing your contributions, and our contribution process.
When you contribute documentation, either to accompany a code change or as a standalone contribution, please be sure to follow our documentation Style Guide.
Security
Please see SECURITY.md.
Adoption
Using authentik? We'd love to hear your story and feature your logo. Email us at hello@goauthentik.io or open a GitHub Issue/PR!



