diff --git a/authentik/brands/utils.py b/authentik/brands/utils.py
index e5c8380198..db6309c7ff 100644
--- a/authentik/brands/utils.py
+++ b/authentik/brands/utils.py
@@ -43,6 +43,6 @@ def context_processor(request: HttpRequest) -> dict[str, Any]:
"brand": brand,
"brand_css": brand_css,
"footer_links": tenant.footer_links,
- "html_meta": get_http_meta(),
+ "html_meta": {**get_http_meta()},
"version": get_full_version(),
}
diff --git a/authentik/core/templates/base/skeleton.html b/authentik/core/templates/base/skeleton.html
index fc5eda491c..a9df91fdb0 100644
--- a/authentik/core/templates/base/skeleton.html
+++ b/authentik/core/templates/base/skeleton.html
@@ -10,7 +10,6 @@
{# Darkreader breaks the site regardless of theme as its not compatible with webcomponents, and we default to a dark theme based on preferred colour-scheme #}
-
{% block title %}{% trans title|default:brand.branding_title %}{% endblock %}
diff --git a/internal/web/static.go b/internal/web/static.go
index 4e6bdd7455..25cdcaaed5 100644
--- a/internal/web/static.go
+++ b/internal/web/static.go
@@ -1,9 +1,11 @@
package web
import (
+ "fmt"
"net/http"
"github.com/go-http-utils/etag"
+ "github.com/gorilla/mux"
"goauthentik.io/internal/config"
"goauthentik.io/internal/constants"
@@ -40,6 +42,27 @@ func (ws *WebServer) configureStatic() {
config.Get().Web.Path,
))
+ indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/flow/{flow_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+
+ pathStripper(
+ distFs,
+ "if/flow/"+vars["flow_slug"],
+ config.Get().Web.Path,
+ ).ServeHTTP(rw, r)
+ })
+ indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/admin/assets").Handler(http.StripPrefix(fmt.Sprintf("%sif/admin", config.Get().Web.Path), distFs))
+ indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/user/assets").Handler(http.StripPrefix(fmt.Sprintf("%sif/user", config.Get().Web.Path), distFs))
+ indexLessRouter.PathPrefix(config.Get().Web.Path).PathPrefix("/if/rac/{app_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+
+ pathStripper(
+ distFs,
+ "if/rac/"+vars["app_slug"],
+ config.Get().Web.Path,
+ ).ServeHTTP(rw, r)
+ })
+
// Media files, if backend is file
if config.Get().Storage.Media.Backend == "file" {
fsMedia := http.FileServer(http.Dir(config.Get().Storage.Media.File.Path))
diff --git a/web/bundler/css-assets-plugin/node.js b/web/bundler/css-assets-plugin/node.js
deleted file mode 100644
index cafaa92a1e..0000000000
--- a/web/bundler/css-assets-plugin/node.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * @file CSS asset rewrite plugin for ESBuild.
- *
- * @import { Plugin } from "esbuild"
- */
-
-import * as fs from "node:fs/promises";
-
-/**
- * Rewrite `url()` calls in CSS files to point to the static directory.
- *
- * @returns {Plugin}
- */
-export function cssAssetPlugin() {
- return {
- name: "css-text-loader",
- setup: (build) => {
- const URLPattern = /url\(\s*['"]?(?:[./]*)(assets\/[^)'"']*)['"]?\s*\)/g;
-
- build.onLoad({ filter: /\.css$/ }, async (args) => {
- const contents = await fs.readFile(args.path, "utf8");
-
- return {
- loader: "text",
- contents: contents.replaceAll(URLPattern, "url(./static/dist/$1)"),
- };
- });
- },
- };
-}
diff --git a/web/bundler/mdx-plugin/node.js b/web/bundler/mdx-plugin/node.js
index 0a0c619a94..fe33b8f63e 100644
--- a/web/bundler/mdx-plugin/node.js
+++ b/web/bundler/mdx-plugin/node.js
@@ -1,3 +1,6 @@
+import * as fs from "node:fs/promises";
+import * as path from "node:path";
+
/**
* @file MDX plugin for ESBuild.
*
@@ -10,10 +13,6 @@
* PluginBuild
* } from "esbuild"
*/
-
-import * as fs from "node:fs/promises";
-import * as path from "node:path";
-
import { MonoRepoRoot } from "@goauthentik/core/paths/node";
/**
diff --git a/web/scripts/build-web.mjs b/web/scripts/build-web.mjs
index a0c1130792..6cc153094f 100644
--- a/web/scripts/build-web.mjs
+++ b/web/scripts/build-web.mjs
@@ -1,13 +1,11 @@
+import * as fs from "node:fs/promises";
+import * as path from "node:path";
+
/**
* @file ESBuild script for building the authentik web UI.
*
* @import { BuildOptions } from "esbuild";
*/
-
-import * as fs from "node:fs/promises";
-import * as path from "node:path";
-
-import { cssAssetPlugin } from "#bundler/css-assets-plugin/node";
import { mdxPlugin } from "#bundler/mdx-plugin/node";
import { createBundleDefinitions } from "#bundler/utils/node";
import { DistDirectory, EntryPoint, PackageRoot } from "#paths/node";
@@ -42,8 +40,11 @@ const BASE_ESBUILD_OPTIONS = {
legalComments: "external",
splitting: true,
treeShaking: true,
-
+ external: ["*.woff", "*.woff2"],
tsconfig: path.resolve(PackageRoot, "tsconfig.build.json"),
+ loader: {
+ ".css": "text",
+ },
plugins: [
copy({
assets: [
@@ -74,7 +75,6 @@ const BASE_ESBUILD_OPTIONS = {
path: true,
},
}),
- cssAssetPlugin(),
mdxPlugin({
root: MonoRepoRoot,
}),
diff --git a/web/src/common/styles/authentik.css b/web/src/common/styles/authentik.css
index 61f734bd12..a1ef240095 100644
--- a/web/src/common/styles/authentik.css
+++ b/web/src/common/styles/authentik.css
@@ -35,31 +35,6 @@
--ak-navbar--height: 7rem;
}
-/* #region Fonts */
-
-body {
- --pf-global--FontFamily--sans-serif:
- RedHatVF, "RedHatText", "Overpass", overpass, helvetica, arial, sans-serif;
-
- --pf-global--FontFamily--heading--sans-serif:
- RedHatDisplayVF, "RedHatDisplay", "Overpass", overpass, helvetica, arial, sans-serif;
-
- --pf-global--FontFamily--monospace:
- RedHatMonoVF, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
- monospace;
-}
-
-code,
-pre {
- /*
- The variable weight is a bit too thin compared to the fixed weight.
- So we'll use a slightly larger value here to compensate.
- */
- font-weight: 500;
-}
-
-/* #endregion */
-
.pf-c-form__group {
--pf-c-form--m-horizontal__group-label--md--GridColumnWidth: minmax(max-content, 9.375rem);
column-gap: var(--pf-global--spacer--md);
diff --git a/web/src/elements/router/RouteMatch.ts b/web/src/elements/router/RouteMatch.ts
index 9a81bfc0a2..07c20d4a56 100644
--- a/web/src/elements/router/RouteMatch.ts
+++ b/web/src/elements/router/RouteMatch.ts
@@ -41,14 +41,6 @@ export class RouteMatch {
}
}
-export function createPathnameHash(
- hashRoute?: string | null,
- basePath = location.pathname,
-): string {
- if (!hashRoute) return basePath;
- return `${basePath}#${hashRoute}`;
-}
-
export function getURLParam(key: string, fallback: T): T {
const params = getURLParams();
if (key in params) {
@@ -72,18 +64,13 @@ export function getURLParams(): { [key: string]: unknown } {
}
export function setURLParams(params: { [key: string]: unknown }, replace = true): void {
- const serializedParams = JSON.stringify(params);
-
- const [currentRoute] = window.location.hash.slice(1).split(ROUTE_SEPARATOR);
-
- const nextPathname = createPathnameHash(
- `${currentRoute};${encodeURIComponent(serializedParams)}`,
- );
-
+ const paramsString = JSON.stringify(params);
+ const currentUrl = window.location.hash.slice(1, Infinity).split(ROUTE_SEPARATOR)[0];
+ const newUrl = `#${currentUrl};${encodeURIComponent(paramsString)}`;
if (replace) {
- history.replaceState(undefined, "", nextPathname);
+ history.replaceState(undefined, "", newUrl);
} else {
- history.pushState(undefined, "", nextPathname);
+ history.pushState(undefined, "", newUrl);
}
}
@@ -92,6 +79,5 @@ export function updateURLParams(params: { [key: string]: unknown }, replace = tr
for (const key in params) {
currentParams[key] = params[key] as string;
}
-
setURLParams(currentParams, replace);
}
diff --git a/web/src/elements/sidebar/SidebarItem.ts b/web/src/elements/sidebar/SidebarItem.ts
index 0138786be5..4ff9e1dd20 100644
--- a/web/src/elements/sidebar/SidebarItem.ts
+++ b/web/src/elements/sidebar/SidebarItem.ts
@@ -1,7 +1,6 @@
import { ROUTE_SEPARATOR } from "#common/constants";
import { AKElement } from "#elements/Base";
-import { createPathnameHash } from "#elements/router/RouteMatch";
import { msg, str } from "@lit/localize";
import { css, CSSResult, html, nothing, TemplateResult } from "lit";
@@ -90,7 +89,10 @@ export class SidebarItem extends AKElement {
public current?: boolean;
@property({ type: Boolean })
- public highlight = false;
+ public isAbsoluteLink = false;
+
+ @property({ type: Boolean })
+ public highlight?: boolean;
public parent?: SidebarItem;
@@ -215,8 +217,8 @@ export class SidebarItem extends AKElement {
renderWithPath() {
return html`