Compare commits
	
		
			36 Commits
		
	
	
		
			providers/
			...
			providers/
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| faf8bf591f | |||
| 52115f9345 | |||
| b476551f13 | |||
| f9563c25cd | |||
| 0067e6e155 | |||
| ce183929d4 | |||
| 2fdf345271 | |||
| bbcf8418b4 | |||
| dc57be46f4 | |||
| d68b3ba516 | |||
| a9c46cfcbd | |||
| c50353ebf6 | |||
| db6be9e1b6 | |||
| a74892886d | |||
| 74cd4c2236 | |||
| ef3bd7e77b | |||
| 3f5ad2baa4 | |||
| 24805f087b | |||
| 9464b422a3 | |||
| da6d4ede51 | |||
| cecad5bfd3 | |||
| bc4b07d57b | |||
| e85d2d0096 | |||
| be1dd3103b | |||
| 5dfde5e1d3 | |||
| 7cb1e6d81e | |||
| d7c3129b1c | |||
| 2a1d33021b | |||
| f273e49ae6 | |||
| cc31957900 | |||
| b1ccdecc8e | |||
| 34031003a4 | |||
| 055e1d1025 | |||
| 59a804273e | |||
| bce70a1796 | |||
| e86c40a00c | 
@ -1,5 +1,5 @@
 | 
				
			|||||||
[bumpversion]
 | 
					[bumpversion]
 | 
				
			||||||
current_version = 2025.6.1
 | 
					current_version = 2025.6.2
 | 
				
			||||||
tag = True
 | 
					tag = True
 | 
				
			||||||
commit = 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*))?
 | 
					parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/ci-main.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ci-main.yml
									
									
									
									
										vendored
									
									
								
							@ -202,7 +202,7 @@ jobs:
 | 
				
			|||||||
        uses: actions/cache@v4
 | 
					        uses: actions/cache@v4
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          path: web/dist
 | 
					          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
 | 
					      - name: prepare web ui
 | 
				
			||||||
        if: steps.cache-web.outputs.cache-hit != 'true'
 | 
					        if: steps.cache-web.outputs.cache-hit != 'true'
 | 
				
			||||||
        working-directory: web
 | 
					        working-directory: web
 | 
				
			||||||
 | 
				
			|||||||
@ -77,7 +77,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
 | 
				
			|||||||
# Stage 4: Download uv
 | 
					# Stage 4: Download uv
 | 
				
			||||||
FROM ghcr.io/astral-sh/uv:0.7.13 AS uv
 | 
					FROM ghcr.io/astral-sh/uv:0.7.13 AS uv
 | 
				
			||||||
# Stage 5: Base python image
 | 
					# Stage 5: Base python image
 | 
				
			||||||
FROM ghcr.io/goauthentik/fips-python:3.13.4-slim-bookworm-fips AS python-base
 | 
					FROM ghcr.io/goauthentik/fips-python:3.13.5-slim-bookworm-fips AS python-base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ENV VENV_PATH="/ak-root/.venv" \
 | 
					ENV VENV_PATH="/ak-root/.venv" \
 | 
				
			||||||
    PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \
 | 
					    PATH="/lifecycle:/ak-root/.venv/bin:$PATH" \
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from os import environ
 | 
					from os import environ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__version__ = "2025.6.1"
 | 
					__version__ = "2025.6.2"
 | 
				
			||||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
 | 
					ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,6 @@ class OAuth2Error(SentryIgnoredException):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    error: str
 | 
					    error: str
 | 
				
			||||||
    description: str
 | 
					    description: str
 | 
				
			||||||
    cause: str | None = None
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_dict(self):
 | 
					    def create_dict(self):
 | 
				
			||||||
        """Return error as dict for JSON Rendering"""
 | 
					        """Return error as dict for JSON Rendering"""
 | 
				
			||||||
@ -35,10 +34,6 @@ class OAuth2Error(SentryIgnoredException):
 | 
				
			|||||||
            **kwargs,
 | 
					            **kwargs,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def with_cause(self, cause: str):
 | 
					 | 
				
			||||||
        self.cause = cause
 | 
					 | 
				
			||||||
        return self
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RedirectUriError(OAuth2Error):
 | 
					class RedirectUriError(OAuth2Error):
 | 
				
			||||||
    """The request fails due to a missing, invalid, or mismatching
 | 
					    """The request fails due to a missing, invalid, or mismatching
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,7 @@ from authentik.core.tests.utils import create_test_admin_user, create_test_flow
 | 
				
			|||||||
from authentik.events.models import Event, EventAction
 | 
					from authentik.events.models import Event, EventAction
 | 
				
			||||||
from authentik.lib.generators import generate_id
 | 
					from authentik.lib.generators import generate_id
 | 
				
			||||||
from authentik.lib.utils.time import timedelta_from_string
 | 
					from authentik.lib.utils.time import timedelta_from_string
 | 
				
			||||||
from authentik.providers.oauth2.constants import SCOPE_OFFLINE_ACCESS, SCOPE_OPENID, TOKEN_TYPE
 | 
					from authentik.providers.oauth2.constants import TOKEN_TYPE
 | 
				
			||||||
from authentik.providers.oauth2.errors import AuthorizeError, ClientIdError, RedirectUriError
 | 
					from authentik.providers.oauth2.errors import AuthorizeError, ClientIdError, RedirectUriError
 | 
				
			||||||
from authentik.providers.oauth2.models import (
 | 
					from authentik.providers.oauth2.models import (
 | 
				
			||||||
    AccessToken,
 | 
					    AccessToken,
 | 
				
			||||||
@ -43,7 +43,7 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
            authorization_flow=create_test_flow(),
 | 
					            authorization_flow=create_test_flow(),
 | 
				
			||||||
            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid/Foo")],
 | 
					            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid/Foo")],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        with self.assertRaises(AuthorizeError) as cm:
 | 
					        with self.assertRaises(AuthorizeError):
 | 
				
			||||||
            request = self.factory.get(
 | 
					            request = self.factory.get(
 | 
				
			||||||
                "/",
 | 
					                "/",
 | 
				
			||||||
                data={
 | 
					                data={
 | 
				
			||||||
@ -53,7 +53,6 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            OAuthAuthorizationParams.from_request(request)
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
        self.assertEqual(cm.exception.error, "unsupported_response_type")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_invalid_client_id(self):
 | 
					    def test_invalid_client_id(self):
 | 
				
			||||||
        """Test invalid client ID"""
 | 
					        """Test invalid client ID"""
 | 
				
			||||||
@ -69,7 +68,7 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
            authorization_flow=create_test_flow(),
 | 
					            authorization_flow=create_test_flow(),
 | 
				
			||||||
            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid/Foo")],
 | 
					            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid/Foo")],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        with self.assertRaises(AuthorizeError) as cm:
 | 
					        with self.assertRaises(AuthorizeError):
 | 
				
			||||||
            request = self.factory.get(
 | 
					            request = self.factory.get(
 | 
				
			||||||
                "/",
 | 
					                "/",
 | 
				
			||||||
                data={
 | 
					                data={
 | 
				
			||||||
@ -80,30 +79,19 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            OAuthAuthorizationParams.from_request(request)
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
        self.assertEqual(cm.exception.error, "request_not_supported")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_invalid_redirect_uri_missing(self):
 | 
					 | 
				
			||||||
        """test missing redirect URI"""
 | 
					 | 
				
			||||||
        OAuth2Provider.objects.create(
 | 
					 | 
				
			||||||
            name=generate_id(),
 | 
					 | 
				
			||||||
            client_id="test",
 | 
					 | 
				
			||||||
            authorization_flow=create_test_flow(),
 | 
					 | 
				
			||||||
            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        with self.assertRaises(RedirectUriError) as cm:
 | 
					 | 
				
			||||||
            request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
 | 
					 | 
				
			||||||
            OAuthAuthorizationParams.from_request(request)
 | 
					 | 
				
			||||||
        self.assertEqual(cm.exception.cause, "redirect_uri_missing")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_invalid_redirect_uri(self):
 | 
					    def test_invalid_redirect_uri(self):
 | 
				
			||||||
        """test invalid redirect URI"""
 | 
					        """test missing/invalid redirect URI"""
 | 
				
			||||||
        OAuth2Provider.objects.create(
 | 
					        OAuth2Provider.objects.create(
 | 
				
			||||||
            name=generate_id(),
 | 
					            name=generate_id(),
 | 
				
			||||||
            client_id="test",
 | 
					            client_id="test",
 | 
				
			||||||
            authorization_flow=create_test_flow(),
 | 
					            authorization_flow=create_test_flow(),
 | 
				
			||||||
            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
 | 
					            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        with self.assertRaises(RedirectUriError) as cm:
 | 
					        with self.assertRaises(RedirectUriError):
 | 
				
			||||||
 | 
					            request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
 | 
				
			||||||
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
 | 
					        with self.assertRaises(RedirectUriError):
 | 
				
			||||||
            request = self.factory.get(
 | 
					            request = self.factory.get(
 | 
				
			||||||
                "/",
 | 
					                "/",
 | 
				
			||||||
                data={
 | 
					                data={
 | 
				
			||||||
@ -113,7 +101,6 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            OAuthAuthorizationParams.from_request(request)
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
        self.assertEqual(cm.exception.cause, "redirect_uri_no_match")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_blocked_redirect_uri(self):
 | 
					    def test_blocked_redirect_uri(self):
 | 
				
			||||||
        """test missing/invalid redirect URI"""
 | 
					        """test missing/invalid redirect URI"""
 | 
				
			||||||
@ -121,9 +108,9 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
            name=generate_id(),
 | 
					            name=generate_id(),
 | 
				
			||||||
            client_id="test",
 | 
					            client_id="test",
 | 
				
			||||||
            authorization_flow=create_test_flow(),
 | 
					            authorization_flow=create_test_flow(),
 | 
				
			||||||
            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "data:localhost")],
 | 
					            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "data:local.invalid")],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        with self.assertRaises(RedirectUriError) as cm:
 | 
					        with self.assertRaises(RedirectUriError):
 | 
				
			||||||
            request = self.factory.get(
 | 
					            request = self.factory.get(
 | 
				
			||||||
                "/",
 | 
					                "/",
 | 
				
			||||||
                data={
 | 
					                data={
 | 
				
			||||||
@ -133,7 +120,6 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            OAuthAuthorizationParams.from_request(request)
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
        self.assertEqual(cm.exception.cause, "redirect_uri_forbidden_scheme")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_invalid_redirect_uri_empty(self):
 | 
					    def test_invalid_redirect_uri_empty(self):
 | 
				
			||||||
        """test missing/invalid redirect URI"""
 | 
					        """test missing/invalid redirect URI"""
 | 
				
			||||||
@ -143,6 +129,9 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
            authorization_flow=create_test_flow(),
 | 
					            authorization_flow=create_test_flow(),
 | 
				
			||||||
            redirect_uris=[],
 | 
					            redirect_uris=[],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        with self.assertRaises(RedirectUriError):
 | 
				
			||||||
 | 
					            request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
 | 
				
			||||||
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
        request = self.factory.get(
 | 
					        request = self.factory.get(
 | 
				
			||||||
            "/",
 | 
					            "/",
 | 
				
			||||||
            data={
 | 
					            data={
 | 
				
			||||||
@ -161,9 +150,12 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
            name=generate_id(),
 | 
					            name=generate_id(),
 | 
				
			||||||
            client_id="test",
 | 
					            client_id="test",
 | 
				
			||||||
            authorization_flow=create_test_flow(),
 | 
					            authorization_flow=create_test_flow(),
 | 
				
			||||||
            redirect_uris=[RedirectURI(RedirectURIMatchingMode.REGEX, "http://local.invalid?")],
 | 
					            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid?")],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        with self.assertRaises(RedirectUriError) as cm:
 | 
					        with self.assertRaises(RedirectUriError):
 | 
				
			||||||
 | 
					            request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
 | 
				
			||||||
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
 | 
					        with self.assertRaises(RedirectUriError):
 | 
				
			||||||
            request = self.factory.get(
 | 
					            request = self.factory.get(
 | 
				
			||||||
                "/",
 | 
					                "/",
 | 
				
			||||||
                data={
 | 
					                data={
 | 
				
			||||||
@ -173,7 +165,6 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            OAuthAuthorizationParams.from_request(request)
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
        self.assertEqual(cm.exception.cause, "redirect_uri_no_match")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_redirect_uri_invalid_regex(self):
 | 
					    def test_redirect_uri_invalid_regex(self):
 | 
				
			||||||
        """test missing/invalid redirect URI (invalid regex)"""
 | 
					        """test missing/invalid redirect URI (invalid regex)"""
 | 
				
			||||||
@ -181,9 +172,12 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
            name=generate_id(),
 | 
					            name=generate_id(),
 | 
				
			||||||
            client_id="test",
 | 
					            client_id="test",
 | 
				
			||||||
            authorization_flow=create_test_flow(),
 | 
					            authorization_flow=create_test_flow(),
 | 
				
			||||||
            redirect_uris=[RedirectURI(RedirectURIMatchingMode.REGEX, "+")],
 | 
					            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "+")],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        with self.assertRaises(RedirectUriError) as cm:
 | 
					        with self.assertRaises(RedirectUriError):
 | 
				
			||||||
 | 
					            request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
 | 
				
			||||||
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
 | 
					        with self.assertRaises(RedirectUriError):
 | 
				
			||||||
            request = self.factory.get(
 | 
					            request = self.factory.get(
 | 
				
			||||||
                "/",
 | 
					                "/",
 | 
				
			||||||
                data={
 | 
					                data={
 | 
				
			||||||
@ -193,22 +187,23 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            OAuthAuthorizationParams.from_request(request)
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
        self.assertEqual(cm.exception.cause, "redirect_uri_no_match")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_redirect_uri_regex(self):
 | 
					    def test_empty_redirect_uri(self):
 | 
				
			||||||
        """test valid redirect URI (regex)"""
 | 
					        """test empty redirect URI (configure in provider)"""
 | 
				
			||||||
        OAuth2Provider.objects.create(
 | 
					        OAuth2Provider.objects.create(
 | 
				
			||||||
            name=generate_id(),
 | 
					            name=generate_id(),
 | 
				
			||||||
            client_id="test",
 | 
					            client_id="test",
 | 
				
			||||||
            authorization_flow=create_test_flow(),
 | 
					            authorization_flow=create_test_flow(),
 | 
				
			||||||
            redirect_uris=[RedirectURI(RedirectURIMatchingMode.REGEX, ".+")],
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					        with self.assertRaises(RedirectUriError):
 | 
				
			||||||
 | 
					            request = self.factory.get("/", data={"response_type": "code", "client_id": "test"})
 | 
				
			||||||
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
        request = self.factory.get(
 | 
					        request = self.factory.get(
 | 
				
			||||||
            "/",
 | 
					            "/",
 | 
				
			||||||
            data={
 | 
					            data={
 | 
				
			||||||
                "response_type": "code",
 | 
					                "response_type": "code",
 | 
				
			||||||
                "client_id": "test",
 | 
					                "client_id": "test",
 | 
				
			||||||
                "redirect_uri": "http://foo.bar.baz",
 | 
					                "redirect_uri": "http://localhost",
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        OAuthAuthorizationParams.from_request(request)
 | 
					        OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
@ -263,7 +258,7 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
            GrantTypes.IMPLICIT,
 | 
					            GrantTypes.IMPLICIT,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        # Implicit without openid scope
 | 
					        # Implicit without openid scope
 | 
				
			||||||
        with self.assertRaises(AuthorizeError) as cm:
 | 
					        with self.assertRaises(AuthorizeError):
 | 
				
			||||||
            request = self.factory.get(
 | 
					            request = self.factory.get(
 | 
				
			||||||
                "/",
 | 
					                "/",
 | 
				
			||||||
                data={
 | 
					                data={
 | 
				
			||||||
@ -290,7 +285,7 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
        self.assertEqual(
 | 
					        self.assertEqual(
 | 
				
			||||||
            OAuthAuthorizationParams.from_request(request).grant_type, GrantTypes.HYBRID
 | 
					            OAuthAuthorizationParams.from_request(request).grant_type, GrantTypes.HYBRID
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        with self.assertRaises(AuthorizeError) as cm:
 | 
					        with self.assertRaises(AuthorizeError):
 | 
				
			||||||
            request = self.factory.get(
 | 
					            request = self.factory.get(
 | 
				
			||||||
                "/",
 | 
					                "/",
 | 
				
			||||||
                data={
 | 
					                data={
 | 
				
			||||||
@ -300,7 +295,6 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            OAuthAuthorizationParams.from_request(request)
 | 
					            OAuthAuthorizationParams.from_request(request)
 | 
				
			||||||
        self.assertEqual(cm.exception.error, "unsupported_response_type")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_full_code(self):
 | 
					    def test_full_code(self):
 | 
				
			||||||
        """Test full authorization"""
 | 
					        """Test full authorization"""
 | 
				
			||||||
@ -393,8 +387,7 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
            self.assertEqual(
 | 
					            self.assertEqual(
 | 
				
			||||||
                response.url,
 | 
					                response.url,
 | 
				
			||||||
                (
 | 
					                (
 | 
				
			||||||
                    f"http://localhost#access_token={token.token}"
 | 
					                    f"http://localhost#id_token={provider.encode(token.id_token.to_dict())}"
 | 
				
			||||||
                    f"&id_token={provider.encode(token.id_token.to_dict())}"
 | 
					 | 
				
			||||||
                    f"&token_type={TOKEN_TYPE}"
 | 
					                    f"&token_type={TOKEN_TYPE}"
 | 
				
			||||||
                    f"&expires_in={int(expires)}&state={state}"
 | 
					                    f"&expires_in={int(expires)}&state={state}"
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
@ -569,7 +562,6 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
                "url": "http://localhost",
 | 
					                "url": "http://localhost",
 | 
				
			||||||
                "title": f"Redirecting to {app.name}...",
 | 
					                "title": f"Redirecting to {app.name}...",
 | 
				
			||||||
                "attrs": {
 | 
					                "attrs": {
 | 
				
			||||||
                    "access_token": token.token,
 | 
					 | 
				
			||||||
                    "id_token": provider.encode(token.id_token.to_dict()),
 | 
					                    "id_token": provider.encode(token.id_token.to_dict()),
 | 
				
			||||||
                    "token_type": TOKEN_TYPE,
 | 
					                    "token_type": TOKEN_TYPE,
 | 
				
			||||||
                    "expires_in": "3600",
 | 
					                    "expires_in": "3600",
 | 
				
			||||||
@ -621,54 +613,3 @@ class TestAuthorize(OAuthTestCase):
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_openid_missing_invalid(self):
 | 
					 | 
				
			||||||
        """test request requiring an OpenID scope to be set"""
 | 
					 | 
				
			||||||
        OAuth2Provider.objects.create(
 | 
					 | 
				
			||||||
            name=generate_id(),
 | 
					 | 
				
			||||||
            client_id="test",
 | 
					 | 
				
			||||||
            authorization_flow=create_test_flow(),
 | 
					 | 
				
			||||||
            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://localhost")],
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        request = self.factory.get(
 | 
					 | 
				
			||||||
            "/",
 | 
					 | 
				
			||||||
            data={
 | 
					 | 
				
			||||||
                "response_type": "id_token",
 | 
					 | 
				
			||||||
                "client_id": "test",
 | 
					 | 
				
			||||||
                "redirect_uri": "http://localhost",
 | 
					 | 
				
			||||||
                "scope": "",
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        with self.assertRaises(AuthorizeError) as cm:
 | 
					 | 
				
			||||||
            OAuthAuthorizationParams.from_request(request)
 | 
					 | 
				
			||||||
        self.assertEqual(cm.exception.cause, "scope_openid_missing")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @apply_blueprint("system/providers-oauth2.yaml")
 | 
					 | 
				
			||||||
    def test_offline_access_invalid(self):
 | 
					 | 
				
			||||||
        """test request for offline_access with invalid response type"""
 | 
					 | 
				
			||||||
        provider = OAuth2Provider.objects.create(
 | 
					 | 
				
			||||||
            name=generate_id(),
 | 
					 | 
				
			||||||
            client_id="test",
 | 
					 | 
				
			||||||
            authorization_flow=create_test_flow(),
 | 
					 | 
				
			||||||
            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://localhost")],
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        provider.property_mappings.set(
 | 
					 | 
				
			||||||
            ScopeMapping.objects.filter(
 | 
					 | 
				
			||||||
                managed__in=[
 | 
					 | 
				
			||||||
                    "goauthentik.io/providers/oauth2/scope-openid",
 | 
					 | 
				
			||||||
                    "goauthentik.io/providers/oauth2/scope-offline_access",
 | 
					 | 
				
			||||||
                ]
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        request = self.factory.get(
 | 
					 | 
				
			||||||
            "/",
 | 
					 | 
				
			||||||
            data={
 | 
					 | 
				
			||||||
                "response_type": "id_token",
 | 
					 | 
				
			||||||
                "client_id": "test",
 | 
					 | 
				
			||||||
                "redirect_uri": "http://localhost",
 | 
					 | 
				
			||||||
                "scope": f"{SCOPE_OPENID} {SCOPE_OFFLINE_ACCESS}",
 | 
					 | 
				
			||||||
                "nonce": generate_id(),
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        parsed = OAuthAuthorizationParams.from_request(request)
 | 
					 | 
				
			||||||
        self.assertNotIn(SCOPE_OFFLINE_ACCESS, parsed.scope)
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -150,12 +150,12 @@ class OAuthAuthorizationParams:
 | 
				
			|||||||
        self.check_redirect_uri()
 | 
					        self.check_redirect_uri()
 | 
				
			||||||
        self.check_grant()
 | 
					        self.check_grant()
 | 
				
			||||||
        self.check_scope(github_compat)
 | 
					        self.check_scope(github_compat)
 | 
				
			||||||
        self.check_nonce()
 | 
					 | 
				
			||||||
        self.check_code_challenge()
 | 
					 | 
				
			||||||
        if self.request:
 | 
					        if self.request:
 | 
				
			||||||
            raise AuthorizeError(
 | 
					            raise AuthorizeError(
 | 
				
			||||||
                self.redirect_uri, "request_not_supported", self.grant_type, self.state
 | 
					                self.redirect_uri, "request_not_supported", self.grant_type, self.state
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					        self.check_nonce()
 | 
				
			||||||
 | 
					        self.check_code_challenge()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def check_grant(self):
 | 
					    def check_grant(self):
 | 
				
			||||||
        """Check grant"""
 | 
					        """Check grant"""
 | 
				
			||||||
@ -190,7 +190,7 @@ class OAuthAuthorizationParams:
 | 
				
			|||||||
        allowed_redirect_urls = self.provider.redirect_uris
 | 
					        allowed_redirect_urls = self.provider.redirect_uris
 | 
				
			||||||
        if not self.redirect_uri:
 | 
					        if not self.redirect_uri:
 | 
				
			||||||
            LOGGER.warning("Missing redirect uri.")
 | 
					            LOGGER.warning("Missing redirect uri.")
 | 
				
			||||||
            raise RedirectUriError("", allowed_redirect_urls).with_cause("redirect_uri_missing")
 | 
					            raise RedirectUriError("", allowed_redirect_urls)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if len(allowed_redirect_urls) < 1:
 | 
					        if len(allowed_redirect_urls) < 1:
 | 
				
			||||||
            LOGGER.info("Setting redirect for blank redirect_uris", redirect=self.redirect_uri)
 | 
					            LOGGER.info("Setting redirect for blank redirect_uris", redirect=self.redirect_uri)
 | 
				
			||||||
@ -219,14 +219,10 @@ class OAuthAuthorizationParams:
 | 
				
			|||||||
                        provider=self.provider,
 | 
					                        provider=self.provider,
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
        if not match_found:
 | 
					        if not match_found:
 | 
				
			||||||
            raise RedirectUriError(self.redirect_uri, allowed_redirect_urls).with_cause(
 | 
					            raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
 | 
				
			||||||
                "redirect_uri_no_match"
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        # Check against forbidden schemes
 | 
					        # Check against forbidden schemes
 | 
				
			||||||
        if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
 | 
					        if urlparse(self.redirect_uri).scheme in FORBIDDEN_URI_SCHEMES:
 | 
				
			||||||
            raise RedirectUriError(self.redirect_uri, allowed_redirect_urls).with_cause(
 | 
					            raise RedirectUriError(self.redirect_uri, allowed_redirect_urls)
 | 
				
			||||||
                "redirect_uri_forbidden_scheme"
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def check_scope(self, github_compat=False):
 | 
					    def check_scope(self, github_compat=False):
 | 
				
			||||||
        """Ensure openid scope is set in Hybrid flows, or when requesting an id_token"""
 | 
					        """Ensure openid scope is set in Hybrid flows, or when requesting an id_token"""
 | 
				
			||||||
@ -255,9 +251,7 @@ class OAuthAuthorizationParams:
 | 
				
			|||||||
            or self.response_type in [ResponseTypes.ID_TOKEN, ResponseTypes.ID_TOKEN_TOKEN]
 | 
					            or self.response_type in [ResponseTypes.ID_TOKEN, ResponseTypes.ID_TOKEN_TOKEN]
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            LOGGER.warning("Missing 'openid' scope.")
 | 
					            LOGGER.warning("Missing 'openid' scope.")
 | 
				
			||||||
            raise AuthorizeError(
 | 
					            raise AuthorizeError(self.redirect_uri, "invalid_scope", self.grant_type, self.state)
 | 
				
			||||||
                self.redirect_uri, "invalid_scope", self.grant_type, self.state
 | 
					 | 
				
			||||||
            ).with_cause("scope_openid_missing")
 | 
					 | 
				
			||||||
        if SCOPE_OFFLINE_ACCESS in self.scope:
 | 
					        if SCOPE_OFFLINE_ACCESS in self.scope:
 | 
				
			||||||
            # https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
 | 
					            # https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
 | 
				
			||||||
            # Don't explicitly request consent with offline_access, as the spec allows for
 | 
					            # Don't explicitly request consent with offline_access, as the spec allows for
 | 
				
			||||||
@ -292,9 +286,7 @@ class OAuthAuthorizationParams:
 | 
				
			|||||||
            return
 | 
					            return
 | 
				
			||||||
        if not self.nonce:
 | 
					        if not self.nonce:
 | 
				
			||||||
            LOGGER.warning("Missing nonce for OpenID Request")
 | 
					            LOGGER.warning("Missing nonce for OpenID Request")
 | 
				
			||||||
            raise AuthorizeError(
 | 
					            raise AuthorizeError(self.redirect_uri, "invalid_request", self.grant_type, self.state)
 | 
				
			||||||
                self.redirect_uri, "invalid_request", self.grant_type, self.state
 | 
					 | 
				
			||||||
            ).with_cause("none_missing")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def check_code_challenge(self):
 | 
					    def check_code_challenge(self):
 | 
				
			||||||
        """PKCE validation of the transformation method."""
 | 
					        """PKCE validation of the transformation method."""
 | 
				
			||||||
@ -353,10 +345,10 @@ class AuthorizationFlowInitView(PolicyAccessView):
 | 
				
			|||||||
                self.request, github_compat=self.github_compat
 | 
					                self.request, github_compat=self.github_compat
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        except AuthorizeError as error:
 | 
					        except AuthorizeError as error:
 | 
				
			||||||
            LOGGER.warning(error.description, redirect_uri=error.redirect_uri, cause=error.cause)
 | 
					            LOGGER.warning(error.description, redirect_uri=error.redirect_uri)
 | 
				
			||||||
            raise RequestValidationError(error.get_response(self.request)) from None
 | 
					            raise RequestValidationError(error.get_response(self.request)) from None
 | 
				
			||||||
        except OAuth2Error as error:
 | 
					        except OAuth2Error as error:
 | 
				
			||||||
            LOGGER.warning(error.description, cause=error.cause)
 | 
					            LOGGER.warning(error.description)
 | 
				
			||||||
            raise RequestValidationError(
 | 
					            raise RequestValidationError(
 | 
				
			||||||
                bad_request_message(self.request, error.description, title=error.error)
 | 
					                bad_request_message(self.request, error.description, title=error.error)
 | 
				
			||||||
            ) from None
 | 
					            ) from None
 | 
				
			||||||
@ -638,7 +630,6 @@ class OAuthFulfillmentStage(StageView):
 | 
				
			|||||||
        if self.params.response_type in [
 | 
					        if self.params.response_type in [
 | 
				
			||||||
            ResponseTypes.ID_TOKEN_TOKEN,
 | 
					            ResponseTypes.ID_TOKEN_TOKEN,
 | 
				
			||||||
            ResponseTypes.CODE_ID_TOKEN_TOKEN,
 | 
					            ResponseTypes.CODE_ID_TOKEN_TOKEN,
 | 
				
			||||||
            ResponseTypes.ID_TOKEN,
 | 
					 | 
				
			||||||
            ResponseTypes.CODE_TOKEN,
 | 
					            ResponseTypes.CODE_TOKEN,
 | 
				
			||||||
        ]:
 | 
					        ]:
 | 
				
			||||||
            query_fragment["access_token"] = token.token
 | 
					            query_fragment["access_token"] = token.token
 | 
				
			||||||
 | 
				
			|||||||
@ -190,6 +190,7 @@ class SAMLProviderSerializer(ProviderSerializer):
 | 
				
			|||||||
            "sign_response",
 | 
					            "sign_response",
 | 
				
			||||||
            "sp_binding",
 | 
					            "sp_binding",
 | 
				
			||||||
            "default_relay_state",
 | 
					            "default_relay_state",
 | 
				
			||||||
 | 
					            "default_name_id_policy",
 | 
				
			||||||
            "url_download_metadata",
 | 
					            "url_download_metadata",
 | 
				
			||||||
            "url_sso_post",
 | 
					            "url_sso_post",
 | 
				
			||||||
            "url_sso_redirect",
 | 
					            "url_sso_redirect",
 | 
				
			||||||
 | 
				
			|||||||
@ -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",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@ -12,6 +12,7 @@ from authentik.core.models import PropertyMapping, Provider
 | 
				
			|||||||
from authentik.crypto.models import CertificateKeyPair
 | 
					from authentik.crypto.models import CertificateKeyPair
 | 
				
			||||||
from authentik.lib.models import DomainlessURLValidator
 | 
					from authentik.lib.models import DomainlessURLValidator
 | 
				
			||||||
from authentik.lib.utils.time import timedelta_string_validator
 | 
					from authentik.lib.utils.time import timedelta_string_validator
 | 
				
			||||||
 | 
					from authentik.sources.saml.models import SAMLNameIDPolicy
 | 
				
			||||||
from authentik.sources.saml.processors.constants import (
 | 
					from authentik.sources.saml.processors.constants import (
 | 
				
			||||||
    DSA_SHA1,
 | 
					    DSA_SHA1,
 | 
				
			||||||
    ECDSA_SHA1,
 | 
					    ECDSA_SHA1,
 | 
				
			||||||
@ -179,6 +180,9 @@ class SAMLProvider(Provider):
 | 
				
			|||||||
    default_relay_state = models.TextField(
 | 
					    default_relay_state = models.TextField(
 | 
				
			||||||
        default="", blank=True, help_text=_("Default relay_state value for IDP-initiated logins")
 | 
					        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_assertion = models.BooleanField(default=True)
 | 
				
			||||||
    sign_response = models.BooleanField(default=False)
 | 
					    sign_response = models.BooleanField(default=False)
 | 
				
			||||||
 | 
				
			|||||||
@ -205,6 +205,13 @@ class AssertionProcessor:
 | 
				
			|||||||
    def get_name_id(self) -> Element:
 | 
					    def get_name_id(self) -> Element:
 | 
				
			||||||
        """Get NameID Element"""
 | 
					        """Get NameID Element"""
 | 
				
			||||||
        name_id = Element(f"{{{NS_SAML_ASSERTION}}}NameID")
 | 
					        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
 | 
					        name_id.attrib["Format"] = self.auth_n_request.name_id_policy
 | 
				
			||||||
        # persistent is used as a fallback, so always generate it
 | 
					        # persistent is used as a fallback, so always generate it
 | 
				
			||||||
        persistent = self.http_request.user.uid
 | 
					        persistent = self.http_request.user.uid
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ from authentik.lib.xml import lxml_from_string
 | 
				
			|||||||
from authentik.providers.saml.exceptions import CannotHandleAssertion
 | 
					from authentik.providers.saml.exceptions import CannotHandleAssertion
 | 
				
			||||||
from authentik.providers.saml.models import SAMLProvider
 | 
					from authentik.providers.saml.models import SAMLProvider
 | 
				
			||||||
from authentik.providers.saml.utils.encoding import decode_base64_and_inflate
 | 
					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 (
 | 
					from authentik.sources.saml.processors.constants import (
 | 
				
			||||||
    DSA_SHA1,
 | 
					    DSA_SHA1,
 | 
				
			||||||
    NS_MAP,
 | 
					    NS_MAP,
 | 
				
			||||||
@ -175,7 +176,9 @@ class AuthNRequestParser:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def idp_initiated(self) -> AuthNRequest:
 | 
					    def idp_initiated(self) -> AuthNRequest:
 | 
				
			||||||
        """Create IdP Initiated AuthNRequest"""
 | 
					        """Create IdP Initiated AuthNRequest"""
 | 
				
			||||||
        relay_state = None
 | 
					        request = AuthNRequest(relay_state=None)
 | 
				
			||||||
        if self.provider.default_relay_state != "":
 | 
					        if self.provider.default_relay_state != "":
 | 
				
			||||||
            relay_state = self.provider.default_relay_state
 | 
					            request.relay_state = self.provider.default_relay_state
 | 
				
			||||||
        return AuthNRequest(relay_state=relay_state)
 | 
					        if self.provider.default_name_id_policy != SAMLNameIDPolicy.UNSPECIFIED:
 | 
				
			||||||
 | 
					            request.name_id_policy = self.provider.default_name_id_policy
 | 
				
			||||||
 | 
					        return request
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ from authentik.crypto.models import CertificateKeyPair
 | 
				
			|||||||
from authentik.flows.models import Flow
 | 
					from authentik.flows.models import Flow
 | 
				
			||||||
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
 | 
					from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
 | 
				
			||||||
from authentik.providers.saml.utils.encoding import PEM_FOOTER, PEM_HEADER
 | 
					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 (
 | 
					from authentik.sources.saml.processors.constants import (
 | 
				
			||||||
    NS_MAP,
 | 
					    NS_MAP,
 | 
				
			||||||
    NS_SAML_METADATA,
 | 
					    NS_SAML_METADATA,
 | 
				
			||||||
@ -46,6 +47,7 @@ class ServiceProviderMetadata:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    auth_n_request_signed: bool
 | 
					    auth_n_request_signed: bool
 | 
				
			||||||
    assertion_signed: bool
 | 
					    assertion_signed: bool
 | 
				
			||||||
 | 
					    name_id_policy: SAMLNameIDPolicy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    signing_keypair: CertificateKeyPair | None = None
 | 
					    signing_keypair: CertificateKeyPair | None = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -60,6 +62,7 @@ class ServiceProviderMetadata:
 | 
				
			|||||||
        provider.issuer = self.entity_id
 | 
					        provider.issuer = self.entity_id
 | 
				
			||||||
        provider.sp_binding = self.acs_binding
 | 
					        provider.sp_binding = self.acs_binding
 | 
				
			||||||
        provider.acs_url = self.acs_location
 | 
					        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:
 | 
					        if self.signing_keypair and self.auth_n_request_signed:
 | 
				
			||||||
            self.signing_keypair.name = f"Provider {name} - SAML Signing Certificate"
 | 
					            self.signing_keypair.name = f"Provider {name} - SAML Signing Certificate"
 | 
				
			||||||
            self.signing_keypair.save()
 | 
					            self.signing_keypair.save()
 | 
				
			||||||
@ -148,6 +151,11 @@ class ServiceProviderMetadataParser:
 | 
				
			|||||||
        if signing_keypair:
 | 
					        if signing_keypair:
 | 
				
			||||||
            self.check_signature(root, 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(
 | 
					        return ServiceProviderMetadata(
 | 
				
			||||||
            entity_id=entity_id,
 | 
					            entity_id=entity_id,
 | 
				
			||||||
            acs_binding=acs_binding,
 | 
					            acs_binding=acs_binding,
 | 
				
			||||||
@ -155,4 +163,5 @@ class ServiceProviderMetadataParser:
 | 
				
			|||||||
            auth_n_request_signed=auth_n_request_signed,
 | 
					            auth_n_request_signed=auth_n_request_signed,
 | 
				
			||||||
            assertion_signed=assertion_signed,
 | 
					            assertion_signed=assertion_signed,
 | 
				
			||||||
            signing_keypair=signing_keypair,
 | 
					            signing_keypair=signing_keypair,
 | 
				
			||||||
 | 
					            name_id_policy=name_id_policy,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
                     cacheDuration="PT604800S"
 | 
					                     cacheDuration="PT604800S"
 | 
				
			||||||
                     entityID="http://localhost:8080/saml/metadata">
 | 
					                     entityID="http://localhost:8080/saml/metadata">
 | 
				
			||||||
    <md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
 | 
					    <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"
 | 
					        <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
 | 
				
			||||||
                                     Location="http://localhost:8080/saml/acs"
 | 
					                                     Location="http://localhost:8080/saml/acs"
 | 
				
			||||||
                                     index="1" />
 | 
					                                     index="1" />
 | 
				
			||||||
 | 
				
			|||||||
@ -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.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
 | 
				
			||||||
from authentik.providers.saml.processors.metadata import MetadataProcessor
 | 
					from authentik.providers.saml.processors.metadata import MetadataProcessor
 | 
				
			||||||
from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser
 | 
					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
 | 
					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.acs_url, "http://localhost:8080/saml/acs")
 | 
				
			||||||
        self.assertEqual(provider.issuer, "http://localhost:8080/saml/metadata")
 | 
					        self.assertEqual(provider.issuer, "http://localhost:8080/saml/metadata")
 | 
				
			||||||
        self.assertEqual(provider.sp_binding, SAMLBindings.POST)
 | 
					        self.assertEqual(provider.sp_binding, SAMLBindings.POST)
 | 
				
			||||||
 | 
					        self.assertEqual(provider.default_name_id_policy, SAMLNameIDPolicy.EMAIL)
 | 
				
			||||||
        self.assertEqual(
 | 
					        self.assertEqual(
 | 
				
			||||||
            len(provider.property_mappings.all()),
 | 
					            len(provider.property_mappings.all()),
 | 
				
			||||||
            len(SAMLPropertyMapping.objects.exclude(managed__isnull=True)),
 | 
					            len(SAMLPropertyMapping.objects.exclude(managed__isnull=True)),
 | 
				
			||||||
 | 
				
			|||||||
@ -166,6 +166,7 @@ SPECTACULAR_SETTINGS = {
 | 
				
			|||||||
        "UserVerificationEnum": "authentik.stages.authenticator_webauthn.models.UserVerification",
 | 
					        "UserVerificationEnum": "authentik.stages.authenticator_webauthn.models.UserVerification",
 | 
				
			||||||
        "UserTypeEnum": "authentik.core.models.UserTypes",
 | 
					        "UserTypeEnum": "authentik.core.models.UserTypes",
 | 
				
			||||||
        "OutgoingSyncDeleteAction": "authentik.lib.sync.outgoing.models.OutgoingSyncDeleteAction",
 | 
					        "OutgoingSyncDeleteAction": "authentik.lib.sync.outgoing.models.OutgoingSyncDeleteAction",
 | 
				
			||||||
 | 
					        "SAMLNameIDPolicyEnum": "authentik.sources.saml.models.SAMLNameIDPolicy",
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE": False,
 | 
					    "ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE": False,
 | 
				
			||||||
    "ENUM_GENERATE_CHOICE_DESCRIPTION": False,
 | 
					    "ENUM_GENERATE_CHOICE_DESCRIPTION": False,
 | 
				
			||||||
 | 
				
			|||||||
@ -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.",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@ -39,6 +39,7 @@ from authentik.sources.saml.processors.constants import (
 | 
				
			|||||||
    SAML_NAME_ID_FORMAT_EMAIL,
 | 
					    SAML_NAME_ID_FORMAT_EMAIL,
 | 
				
			||||||
    SAML_NAME_ID_FORMAT_PERSISTENT,
 | 
					    SAML_NAME_ID_FORMAT_PERSISTENT,
 | 
				
			||||||
    SAML_NAME_ID_FORMAT_TRANSIENT,
 | 
					    SAML_NAME_ID_FORMAT_TRANSIENT,
 | 
				
			||||||
 | 
					    SAML_NAME_ID_FORMAT_UNSPECIFIED,
 | 
				
			||||||
    SAML_NAME_ID_FORMAT_WINDOWS,
 | 
					    SAML_NAME_ID_FORMAT_WINDOWS,
 | 
				
			||||||
    SAML_NAME_ID_FORMAT_X509,
 | 
					    SAML_NAME_ID_FORMAT_X509,
 | 
				
			||||||
    SHA1,
 | 
					    SHA1,
 | 
				
			||||||
@ -73,6 +74,7 @@ class SAMLNameIDPolicy(models.TextChoices):
 | 
				
			|||||||
    X509 = SAML_NAME_ID_FORMAT_X509
 | 
					    X509 = SAML_NAME_ID_FORMAT_X509
 | 
				
			||||||
    WINDOWS = SAML_NAME_ID_FORMAT_WINDOWS
 | 
					    WINDOWS = SAML_NAME_ID_FORMAT_WINDOWS
 | 
				
			||||||
    TRANSIENT = SAML_NAME_ID_FORMAT_TRANSIENT
 | 
					    TRANSIENT = SAML_NAME_ID_FORMAT_TRANSIENT
 | 
				
			||||||
 | 
					    UNSPECIFIED = SAML_NAME_ID_FORMAT_UNSPECIFIED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SAMLSource(Source):
 | 
					class SAMLSource(Source):
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
    "$schema": "http://json-schema.org/draft-07/schema",
 | 
					    "$schema": "http://json-schema.org/draft-07/schema",
 | 
				
			||||||
    "$id": "https://goauthentik.io/blueprints/schema.json",
 | 
					    "$id": "https://goauthentik.io/blueprints/schema.json",
 | 
				
			||||||
    "type": "object",
 | 
					    "type": "object",
 | 
				
			||||||
    "title": "authentik 2025.6.1 Blueprint schema",
 | 
					    "title": "authentik 2025.6.2 Blueprint schema",
 | 
				
			||||||
    "required": [
 | 
					    "required": [
 | 
				
			||||||
        "version",
 | 
					        "version",
 | 
				
			||||||
        "entries"
 | 
					        "entries"
 | 
				
			||||||
@ -9233,6 +9233,18 @@
 | 
				
			|||||||
                    "type": "string",
 | 
					                    "type": "string",
 | 
				
			||||||
                    "title": "Default relay state",
 | 
					                    "title": "Default relay state",
 | 
				
			||||||
                    "description": "Default relay_state value for IDP-initiated logins"
 | 
					                    "description": "Default relay_state value for IDP-initiated logins"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                "default_name_id_policy": {
 | 
				
			||||||
 | 
					                    "type": "string",
 | 
				
			||||||
 | 
					                    "enum": [
 | 
				
			||||||
 | 
					                        "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
 | 
				
			||||||
 | 
					                        "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
 | 
				
			||||||
 | 
					                        "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName",
 | 
				
			||||||
 | 
					                        "urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
 | 
				
			||||||
 | 
					                        "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
 | 
				
			||||||
 | 
					                        "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                    "title": "Default name id policy"
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "required": []
 | 
					            "required": []
 | 
				
			||||||
@ -11655,7 +11667,8 @@
 | 
				
			|||||||
                        "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
 | 
					                        "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
 | 
				
			||||||
                        "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName",
 | 
					                        "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName",
 | 
				
			||||||
                        "urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
 | 
					                        "urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
 | 
				
			||||||
                        "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
 | 
					                        "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
 | 
				
			||||||
 | 
					                        "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
 | 
				
			||||||
                    ],
 | 
					                    ],
 | 
				
			||||||
                    "title": "Name id policy",
 | 
					                    "title": "Name id policy",
 | 
				
			||||||
                    "description": "NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent."
 | 
					                    "description": "NameID Policy sent to the IdP. Can be unset, in which case no Policy is sent."
 | 
				
			||||||
 | 
				
			|||||||
@ -31,7 +31,7 @@ services:
 | 
				
			|||||||
    volumes:
 | 
					    volumes:
 | 
				
			||||||
      - redis:/data
 | 
					      - redis:/data
 | 
				
			||||||
  server:
 | 
					  server:
 | 
				
			||||||
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.1}
 | 
					    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
 | 
				
			||||||
    restart: unless-stopped
 | 
					    restart: unless-stopped
 | 
				
			||||||
    command: server
 | 
					    command: server
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
@ -55,7 +55,7 @@ services:
 | 
				
			|||||||
      redis:
 | 
					      redis:
 | 
				
			||||||
        condition: service_healthy
 | 
					        condition: service_healthy
 | 
				
			||||||
  worker:
 | 
					  worker:
 | 
				
			||||||
    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.1}
 | 
					    image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
 | 
				
			||||||
    restart: unless-stopped
 | 
					    restart: unless-stopped
 | 
				
			||||||
    command: worker
 | 
					    command: worker
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							@ -18,7 +18,7 @@ require (
 | 
				
			|||||||
	github.com/gorilla/sessions v1.4.0
 | 
						github.com/gorilla/sessions v1.4.0
 | 
				
			||||||
	github.com/gorilla/websocket v1.5.3
 | 
						github.com/gorilla/websocket v1.5.3
 | 
				
			||||||
	github.com/grafana/pyroscope-go v1.2.2
 | 
						github.com/grafana/pyroscope-go v1.2.2
 | 
				
			||||||
	github.com/jellydator/ttlcache/v3 v3.3.0
 | 
						github.com/jellydator/ttlcache/v3 v3.4.0
 | 
				
			||||||
	github.com/mitchellh/mapstructure v1.5.0
 | 
						github.com/mitchellh/mapstructure v1.5.0
 | 
				
			||||||
	github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
 | 
						github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484
 | 
				
			||||||
	github.com/pires/go-proxyproto v0.8.1
 | 
						github.com/pires/go-proxyproto v0.8.1
 | 
				
			||||||
@ -29,7 +29,7 @@ require (
 | 
				
			|||||||
	github.com/spf13/cobra v1.9.1
 | 
						github.com/spf13/cobra v1.9.1
 | 
				
			||||||
	github.com/stretchr/testify v1.10.0
 | 
						github.com/stretchr/testify v1.10.0
 | 
				
			||||||
	github.com/wwt/guac v1.3.2
 | 
						github.com/wwt/guac v1.3.2
 | 
				
			||||||
	goauthentik.io/api/v3 v3.2025061.2
 | 
						goauthentik.io/api/v3 v3.2025062.1
 | 
				
			||||||
	golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
 | 
						golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
 | 
				
			||||||
	golang.org/x/oauth2 v0.30.0
 | 
						golang.org/x/oauth2 v0.30.0
 | 
				
			||||||
	golang.org/x/sync v0.15.0
 | 
						golang.org/x/sync v0.15.0
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										8
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								go.sum
									
									
									
									
									
								
							@ -203,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/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 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
 | 
				
			||||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
 | 
					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.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY=
 | 
				
			||||||
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
 | 
					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 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 | 
				
			||||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 | 
					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=
 | 
					github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 | 
				
			||||||
@ -298,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.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 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 | 
				
			||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
 | 
					go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
 | 
				
			||||||
goauthentik.io/api/v3 v3.2025061.2 h1:bKmrl82Gz6J8lz3f+QIH9g+MEkl3MvkMXF34GktesA0=
 | 
					goauthentik.io/api/v3 v3.2025062.1 h1:spvILDpDDWJNO3pM6QGqmryx6NvSchr1E8H60J/XUCA=
 | 
				
			||||||
goauthentik.io/api/v3 v3.2025061.2/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
 | 
					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-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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
				
			||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
					golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 | 
				
			||||||
 | 
				
			|||||||
@ -33,4 +33,4 @@ func UserAgent() string {
 | 
				
			|||||||
	return fmt.Sprintf("authentik@%s", FullVersion())
 | 
						return fmt.Sprintf("authentik@%s", FullVersion())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const VERSION = "2025.6.1"
 | 
					const VERSION = "2025.6.2"
 | 
				
			||||||
 | 
				
			|||||||
@ -26,7 +26,7 @@ Parameters:
 | 
				
			|||||||
    Description: authentik Docker image
 | 
					    Description: authentik Docker image
 | 
				
			||||||
  AuthentikVersion:
 | 
					  AuthentikVersion:
 | 
				
			||||||
    Type: String
 | 
					    Type: String
 | 
				
			||||||
    Default: 2025.6.1
 | 
					    Default: 2025.6.2
 | 
				
			||||||
    Description: authentik Docker image tag
 | 
					    Description: authentik Docker image tag
 | 
				
			||||||
  AuthentikServerCPU:
 | 
					  AuthentikServerCPU:
 | 
				
			||||||
    Type: Number
 | 
					    Type: Number
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -1,12 +1,12 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "name": "@goauthentik/authentik",
 | 
					    "name": "@goauthentik/authentik",
 | 
				
			||||||
    "version": "2025.6.1",
 | 
					    "version": "2025.6.2",
 | 
				
			||||||
    "lockfileVersion": 3,
 | 
					    "lockfileVersion": 3,
 | 
				
			||||||
    "requires": true,
 | 
					    "requires": true,
 | 
				
			||||||
    "packages": {
 | 
					    "packages": {
 | 
				
			||||||
        "": {
 | 
					        "": {
 | 
				
			||||||
            "name": "@goauthentik/authentik",
 | 
					            "name": "@goauthentik/authentik",
 | 
				
			||||||
            "version": "2025.6.1",
 | 
					            "version": "2025.6.2",
 | 
				
			||||||
            "devDependencies": {
 | 
					            "devDependencies": {
 | 
				
			||||||
                "@trivago/prettier-plugin-sort-imports": "^5.2.2",
 | 
					                "@trivago/prettier-plugin-sort-imports": "^5.2.2",
 | 
				
			||||||
                "prettier": "^3.3.3",
 | 
					                "prettier": "^3.3.3",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "name": "@goauthentik/authentik",
 | 
					    "name": "@goauthentik/authentik",
 | 
				
			||||||
    "version": "2025.6.1",
 | 
					    "version": "2025.6.2",
 | 
				
			||||||
    "private": true,
 | 
					    "private": true,
 | 
				
			||||||
    "type": "module",
 | 
					    "type": "module",
 | 
				
			||||||
    "devDependencies": {
 | 
					    "devDependencies": {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										182
									
								
								packages/eslint-config/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										182
									
								
								packages/eslint-config/package-lock.json
									
									
									
										generated
									
									
									
								
							@ -216,9 +216,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@eslint/config-array": {
 | 
					        "node_modules/@eslint/config-array": {
 | 
				
			||||||
            "version": "0.20.0",
 | 
					            "version": "0.20.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
 | 
					            "integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
 | 
				
			||||||
            "license": "Apache-2.0",
 | 
					            "license": "Apache-2.0",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@eslint/object-schema": "^2.1.6",
 | 
					                "@eslint/object-schema": "^2.1.6",
 | 
				
			||||||
@ -274,9 +274,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@eslint/js": {
 | 
					        "node_modules/@eslint/js": {
 | 
				
			||||||
            "version": "9.28.0",
 | 
					            "version": "9.29.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
 | 
					            "integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
@ -576,17 +576,17 @@
 | 
				
			|||||||
            "license": "MIT"
 | 
					            "license": "MIT"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/eslint-plugin": {
 | 
					        "node_modules/@typescript-eslint/eslint-plugin": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==",
 | 
					            "integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@eslint-community/regexpp": "^4.10.0",
 | 
					                "@eslint-community/regexpp": "^4.10.0",
 | 
				
			||||||
                "@typescript-eslint/scope-manager": "8.34.0",
 | 
					                "@typescript-eslint/scope-manager": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/type-utils": "8.34.0",
 | 
					                "@typescript-eslint/type-utils": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/utils": "8.34.0",
 | 
					                "@typescript-eslint/utils": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/visitor-keys": "8.34.0",
 | 
					                "@typescript-eslint/visitor-keys": "8.34.1",
 | 
				
			||||||
                "graphemer": "^1.4.0",
 | 
					                "graphemer": "^1.4.0",
 | 
				
			||||||
                "ignore": "^7.0.0",
 | 
					                "ignore": "^7.0.0",
 | 
				
			||||||
                "natural-compare": "^1.4.0",
 | 
					                "natural-compare": "^1.4.0",
 | 
				
			||||||
@ -600,7 +600,7 @@
 | 
				
			|||||||
                "url": "https://opencollective.com/typescript-eslint"
 | 
					                "url": "https://opencollective.com/typescript-eslint"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "peerDependencies": {
 | 
					            "peerDependencies": {
 | 
				
			||||||
                "@typescript-eslint/parser": "^8.34.0",
 | 
					                "@typescript-eslint/parser": "^8.34.1",
 | 
				
			||||||
                "eslint": "^8.57.0 || ^9.0.0",
 | 
					                "eslint": "^8.57.0 || ^9.0.0",
 | 
				
			||||||
                "typescript": ">=4.8.4 <5.9.0"
 | 
					                "typescript": ">=4.8.4 <5.9.0"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -616,16 +616,16 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/parser": {
 | 
					        "node_modules/@typescript-eslint/parser": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==",
 | 
					            "integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/scope-manager": "8.34.0",
 | 
					                "@typescript-eslint/scope-manager": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/types": "8.34.0",
 | 
					                "@typescript-eslint/types": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/typescript-estree": "8.34.0",
 | 
					                "@typescript-eslint/typescript-estree": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/visitor-keys": "8.34.0",
 | 
					                "@typescript-eslint/visitor-keys": "8.34.1",
 | 
				
			||||||
                "debug": "^4.3.4"
 | 
					                "debug": "^4.3.4"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
@ -641,14 +641,14 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/project-service": {
 | 
					        "node_modules/@typescript-eslint/project-service": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==",
 | 
					            "integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/tsconfig-utils": "^8.34.0",
 | 
					                "@typescript-eslint/tsconfig-utils": "^8.34.1",
 | 
				
			||||||
                "@typescript-eslint/types": "^8.34.0",
 | 
					                "@typescript-eslint/types": "^8.34.1",
 | 
				
			||||||
                "debug": "^4.3.4"
 | 
					                "debug": "^4.3.4"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
@ -663,14 +663,14 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/scope-manager": {
 | 
					        "node_modules/@typescript-eslint/scope-manager": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==",
 | 
					            "integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/types": "8.34.0",
 | 
					                "@typescript-eslint/types": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/visitor-keys": "8.34.0"
 | 
					                "@typescript-eslint/visitor-keys": "8.34.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
@ -681,9 +681,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/tsconfig-utils": {
 | 
					        "node_modules/@typescript-eslint/tsconfig-utils": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==",
 | 
					            "integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
@ -698,14 +698,14 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/type-utils": {
 | 
					        "node_modules/@typescript-eslint/type-utils": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==",
 | 
					            "integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/typescript-estree": "8.34.0",
 | 
					                "@typescript-eslint/typescript-estree": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/utils": "8.34.0",
 | 
					                "@typescript-eslint/utils": "8.34.1",
 | 
				
			||||||
                "debug": "^4.3.4",
 | 
					                "debug": "^4.3.4",
 | 
				
			||||||
                "ts-api-utils": "^2.1.0"
 | 
					                "ts-api-utils": "^2.1.0"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@ -722,9 +722,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/types": {
 | 
					        "node_modules/@typescript-eslint/types": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==",
 | 
					            "integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
@ -736,16 +736,16 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/typescript-estree": {
 | 
					        "node_modules/@typescript-eslint/typescript-estree": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==",
 | 
					            "integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/project-service": "8.34.0",
 | 
					                "@typescript-eslint/project-service": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/tsconfig-utils": "8.34.0",
 | 
					                "@typescript-eslint/tsconfig-utils": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/types": "8.34.0",
 | 
					                "@typescript-eslint/types": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/visitor-keys": "8.34.0",
 | 
					                "@typescript-eslint/visitor-keys": "8.34.1",
 | 
				
			||||||
                "debug": "^4.3.4",
 | 
					                "debug": "^4.3.4",
 | 
				
			||||||
                "fast-glob": "^3.3.2",
 | 
					                "fast-glob": "^3.3.2",
 | 
				
			||||||
                "is-glob": "^4.0.3",
 | 
					                "is-glob": "^4.0.3",
 | 
				
			||||||
@ -765,9 +765,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
 | 
					        "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
 | 
				
			||||||
            "version": "2.0.1",
 | 
					            "version": "2.0.2",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
 | 
				
			||||||
            "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
 | 
					            "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
@ -804,16 +804,16 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/utils": {
 | 
					        "node_modules/@typescript-eslint/utils": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==",
 | 
					            "integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@eslint-community/eslint-utils": "^4.7.0",
 | 
					                "@eslint-community/eslint-utils": "^4.7.0",
 | 
				
			||||||
                "@typescript-eslint/scope-manager": "8.34.0",
 | 
					                "@typescript-eslint/scope-manager": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/types": "8.34.0",
 | 
					                "@typescript-eslint/types": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/typescript-estree": "8.34.0"
 | 
					                "@typescript-eslint/typescript-estree": "8.34.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
@ -828,14 +828,14 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/visitor-keys": {
 | 
					        "node_modules/@typescript-eslint/visitor-keys": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==",
 | 
					            "integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/types": "8.34.0",
 | 
					                "@typescript-eslint/types": "8.34.1",
 | 
				
			||||||
                "eslint-visitor-keys": "^4.2.0"
 | 
					                "eslint-visitor-keys": "^4.2.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
@ -846,9 +846,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/acorn": {
 | 
					        "node_modules/acorn": {
 | 
				
			||||||
            "version": "8.14.1",
 | 
					            "version": "8.15.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
 | 
					            "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "bin": {
 | 
					            "bin": {
 | 
				
			||||||
                "acorn": "bin/acorn"
 | 
					                "acorn": "bin/acorn"
 | 
				
			||||||
@ -1554,18 +1554,18 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/eslint": {
 | 
					        "node_modules/eslint": {
 | 
				
			||||||
            "version": "9.28.0",
 | 
					            "version": "9.29.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
 | 
					            "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@eslint-community/eslint-utils": "^4.2.0",
 | 
					                "@eslint-community/eslint-utils": "^4.2.0",
 | 
				
			||||||
                "@eslint-community/regexpp": "^4.12.1",
 | 
					                "@eslint-community/regexpp": "^4.12.1",
 | 
				
			||||||
                "@eslint/config-array": "^0.20.0",
 | 
					                "@eslint/config-array": "^0.20.1",
 | 
				
			||||||
                "@eslint/config-helpers": "^0.2.1",
 | 
					                "@eslint/config-helpers": "^0.2.1",
 | 
				
			||||||
                "@eslint/core": "^0.14.0",
 | 
					                "@eslint/core": "^0.14.0",
 | 
				
			||||||
                "@eslint/eslintrc": "^3.3.1",
 | 
					                "@eslint/eslintrc": "^3.3.1",
 | 
				
			||||||
                "@eslint/js": "9.28.0",
 | 
					                "@eslint/js": "9.29.0",
 | 
				
			||||||
                "@eslint/plugin-kit": "^0.3.1",
 | 
					                "@eslint/plugin-kit": "^0.3.1",
 | 
				
			||||||
                "@humanfs/node": "^0.16.6",
 | 
					                "@humanfs/node": "^0.16.6",
 | 
				
			||||||
                "@humanwhocodes/module-importer": "^1.0.1",
 | 
					                "@humanwhocodes/module-importer": "^1.0.1",
 | 
				
			||||||
@ -1577,9 +1577,9 @@
 | 
				
			|||||||
                "cross-spawn": "^7.0.6",
 | 
					                "cross-spawn": "^7.0.6",
 | 
				
			||||||
                "debug": "^4.3.2",
 | 
					                "debug": "^4.3.2",
 | 
				
			||||||
                "escape-string-regexp": "^4.0.0",
 | 
					                "escape-string-regexp": "^4.0.0",
 | 
				
			||||||
                "eslint-scope": "^8.3.0",
 | 
					                "eslint-scope": "^8.4.0",
 | 
				
			||||||
                "eslint-visitor-keys": "^4.2.0",
 | 
					                "eslint-visitor-keys": "^4.2.1",
 | 
				
			||||||
                "espree": "^10.3.0",
 | 
					                "espree": "^10.4.0",
 | 
				
			||||||
                "esquery": "^1.5.0",
 | 
					                "esquery": "^1.5.0",
 | 
				
			||||||
                "esutils": "^2.0.2",
 | 
					                "esutils": "^2.0.2",
 | 
				
			||||||
                "fast-deep-equal": "^3.1.3",
 | 
					                "fast-deep-equal": "^3.1.3",
 | 
				
			||||||
@ -1792,9 +1792,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/eslint-scope": {
 | 
					        "node_modules/eslint-scope": {
 | 
				
			||||||
            "version": "8.3.0",
 | 
					            "version": "8.4.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
 | 
					            "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
 | 
				
			||||||
            "license": "BSD-2-Clause",
 | 
					            "license": "BSD-2-Clause",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "esrecurse": "^4.3.0",
 | 
					                "esrecurse": "^4.3.0",
 | 
				
			||||||
@ -1808,9 +1808,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/eslint-visitor-keys": {
 | 
					        "node_modules/eslint-visitor-keys": {
 | 
				
			||||||
            "version": "4.2.0",
 | 
					            "version": "4.2.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
 | 
					            "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
 | 
				
			||||||
            "license": "Apache-2.0",
 | 
					            "license": "Apache-2.0",
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
@ -1820,14 +1820,14 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/espree": {
 | 
					        "node_modules/espree": {
 | 
				
			||||||
            "version": "10.3.0",
 | 
					            "version": "10.4.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
 | 
					            "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
 | 
				
			||||||
            "license": "BSD-2-Clause",
 | 
					            "license": "BSD-2-Clause",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "acorn": "^8.14.0",
 | 
					                "acorn": "^8.15.0",
 | 
				
			||||||
                "acorn-jsx": "^5.3.2",
 | 
					                "acorn-jsx": "^5.3.2",
 | 
				
			||||||
                "eslint-visitor-keys": "^4.2.0"
 | 
					                "eslint-visitor-keys": "^4.2.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
@ -4035,15 +4035,15 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/typescript-eslint": {
 | 
					        "node_modules/typescript-eslint": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==",
 | 
					            "integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/eslint-plugin": "8.34.0",
 | 
					                "@typescript-eslint/eslint-plugin": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/parser": "8.34.0",
 | 
					                "@typescript-eslint/parser": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/utils": "8.34.0"
 | 
					                "@typescript-eslint/utils": "8.34.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
[project]
 | 
					[project]
 | 
				
			||||||
name = "authentik"
 | 
					name = "authentik"
 | 
				
			||||||
version = "2025.6.1"
 | 
					version = "2025.6.2"
 | 
				
			||||||
description = ""
 | 
					description = ""
 | 
				
			||||||
authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
 | 
					authors = [{ name = "authentik Team", email = "hello@goauthentik.io" }]
 | 
				
			||||||
requires-python = "==3.13.*"
 | 
					requires-python = "==3.13.*"
 | 
				
			||||||
@ -48,7 +48,7 @@ dependencies = [
 | 
				
			|||||||
    "packaging==25.0",
 | 
					    "packaging==25.0",
 | 
				
			||||||
    "paramiko==3.5.1",
 | 
					    "paramiko==3.5.1",
 | 
				
			||||||
    "psycopg[c,pool]==3.2.9",
 | 
					    "psycopg[c,pool]==3.2.9",
 | 
				
			||||||
    "pydantic==2.11.5",
 | 
					    "pydantic==2.11.7",
 | 
				
			||||||
    "pydantic-scim==0.0.8",
 | 
					    "pydantic-scim==0.0.8",
 | 
				
			||||||
    "pyjwt==2.10.1",
 | 
					    "pyjwt==2.10.1",
 | 
				
			||||||
    "pyrad==2.4",
 | 
					    "pyrad==2.4",
 | 
				
			||||||
@ -68,7 +68,7 @@ dependencies = [
 | 
				
			|||||||
    "urllib3<3",
 | 
					    "urllib3<3",
 | 
				
			||||||
    "uvicorn[standard]==0.34.3",
 | 
					    "uvicorn[standard]==0.34.3",
 | 
				
			||||||
    "watchdog==6.0.0",
 | 
					    "watchdog==6.0.0",
 | 
				
			||||||
    "webauthn==2.5.2",
 | 
					    "webauthn==2.6.0",
 | 
				
			||||||
    "wsproto==1.2.0",
 | 
					    "wsproto==1.2.0",
 | 
				
			||||||
    "xmlsec==1.3.15",
 | 
					    "xmlsec==1.3.15",
 | 
				
			||||||
    "zxcvbn==4.5.0",
 | 
					    "zxcvbn==4.5.0",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										43
									
								
								schema.yml
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								schema.yml
									
									
									
									
									
								
							@ -1,7 +1,7 @@
 | 
				
			|||||||
openapi: 3.0.3
 | 
					openapi: 3.0.3
 | 
				
			||||||
info:
 | 
					info:
 | 
				
			||||||
  title: authentik
 | 
					  title: authentik
 | 
				
			||||||
  version: 2025.6.1
 | 
					  version: 2025.6.2
 | 
				
			||||||
  description: Making authentication simple.
 | 
					  description: Making authentication simple.
 | 
				
			||||||
  contact:
 | 
					  contact:
 | 
				
			||||||
    email: hello@goauthentik.io
 | 
					    email: hello@goauthentik.io
 | 
				
			||||||
@ -22454,6 +22454,17 @@ paths:
 | 
				
			|||||||
        schema:
 | 
					        schema:
 | 
				
			||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
          format: uuid
 | 
					          format: uuid
 | 
				
			||||||
 | 
					      - in: query
 | 
				
			||||||
 | 
					        name: default_name_id_policy
 | 
				
			||||||
 | 
					        schema:
 | 
				
			||||||
 | 
					          type: string
 | 
				
			||||||
 | 
					          enum:
 | 
				
			||||||
 | 
					          - urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
 | 
				
			||||||
 | 
					          - urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
 | 
				
			||||||
 | 
					          - urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
 | 
				
			||||||
 | 
					          - urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
 | 
				
			||||||
 | 
					          - urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
 | 
				
			||||||
 | 
					          - urn:oasis:names:tc:SAML:2.0:nameid-format:transient
 | 
				
			||||||
      - in: query
 | 
					      - in: query
 | 
				
			||||||
        name: default_relay_state
 | 
					        name: default_relay_state
 | 
				
			||||||
        schema:
 | 
					        schema:
 | 
				
			||||||
@ -29670,6 +29681,7 @@ paths:
 | 
				
			|||||||
          enum:
 | 
					          enum:
 | 
				
			||||||
          - urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
 | 
					          - urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
 | 
				
			||||||
          - urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
 | 
					          - urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
 | 
				
			||||||
 | 
					          - urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
 | 
				
			||||||
          - urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
 | 
					          - urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
 | 
				
			||||||
          - urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
 | 
					          - urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
 | 
				
			||||||
          - urn:oasis:names:tc:SAML:2.0:nameid-format:transient
 | 
					          - urn:oasis:names:tc:SAML:2.0:nameid-format:transient
 | 
				
			||||||
@ -48745,14 +48757,6 @@ components:
 | 
				
			|||||||
      - mode
 | 
					      - mode
 | 
				
			||||||
      - name
 | 
					      - name
 | 
				
			||||||
      - user_attribute
 | 
					      - user_attribute
 | 
				
			||||||
    NameIdPolicyEnum:
 | 
					 | 
				
			||||||
      enum:
 | 
					 | 
				
			||||||
      - urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
 | 
					 | 
				
			||||||
      - urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
 | 
					 | 
				
			||||||
      - urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
 | 
					 | 
				
			||||||
      - urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
 | 
					 | 
				
			||||||
      - urn:oasis:names:tc:SAML:2.0:nameid-format:transient
 | 
					 | 
				
			||||||
      type: string
 | 
					 | 
				
			||||||
    NetworkBindingEnum:
 | 
					    NetworkBindingEnum:
 | 
				
			||||||
      enum:
 | 
					      enum:
 | 
				
			||||||
      - no_binding
 | 
					      - no_binding
 | 
				
			||||||
@ -54501,6 +54505,8 @@ components:
 | 
				
			|||||||
        default_relay_state:
 | 
					        default_relay_state:
 | 
				
			||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
          description: Default relay_state value for IDP-initiated logins
 | 
					          description: Default relay_state value for IDP-initiated logins
 | 
				
			||||||
 | 
					        default_name_id_policy:
 | 
				
			||||||
 | 
					          $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
 | 
				
			||||||
    PatchedSAMLSourcePropertyMappingRequest:
 | 
					    PatchedSAMLSourcePropertyMappingRequest:
 | 
				
			||||||
      type: object
 | 
					      type: object
 | 
				
			||||||
      description: SAMLSourcePropertyMapping Serializer
 | 
					      description: SAMLSourcePropertyMapping Serializer
 | 
				
			||||||
@ -54594,7 +54600,7 @@ components:
 | 
				
			|||||||
            be a security risk, as no validation of the request ID is done.
 | 
					            be a security risk, as no validation of the request ID is done.
 | 
				
			||||||
        name_id_policy:
 | 
					        name_id_policy:
 | 
				
			||||||
          allOf:
 | 
					          allOf:
 | 
				
			||||||
          - $ref: '#/components/schemas/NameIdPolicyEnum'
 | 
					          - $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
 | 
				
			||||||
          description: NameID Policy sent to the IdP. Can be unset, in which case
 | 
					          description: NameID Policy sent to the IdP. Can be unset, in which case
 | 
				
			||||||
            no Policy is sent.
 | 
					            no Policy is sent.
 | 
				
			||||||
        binding_type:
 | 
					        binding_type:
 | 
				
			||||||
@ -57305,6 +57311,15 @@ components:
 | 
				
			|||||||
      required:
 | 
					      required:
 | 
				
			||||||
      - download_url
 | 
					      - download_url
 | 
				
			||||||
      - metadata
 | 
					      - metadata
 | 
				
			||||||
 | 
					    SAMLNameIDPolicyEnum:
 | 
				
			||||||
 | 
					      enum:
 | 
				
			||||||
 | 
					      - urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
 | 
				
			||||||
 | 
					      - urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
 | 
				
			||||||
 | 
					      - urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
 | 
				
			||||||
 | 
					      - urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
 | 
				
			||||||
 | 
					      - urn:oasis:names:tc:SAML:2.0:nameid-format:transient
 | 
				
			||||||
 | 
					      - urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
 | 
				
			||||||
 | 
					      type: string
 | 
				
			||||||
    SAMLPropertyMapping:
 | 
					    SAMLPropertyMapping:
 | 
				
			||||||
      type: object
 | 
					      type: object
 | 
				
			||||||
      description: SAMLPropertyMapping Serializer
 | 
					      description: SAMLPropertyMapping Serializer
 | 
				
			||||||
@ -57522,6 +57537,8 @@ components:
 | 
				
			|||||||
        default_relay_state:
 | 
					        default_relay_state:
 | 
				
			||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
          description: Default relay_state value for IDP-initiated logins
 | 
					          description: Default relay_state value for IDP-initiated logins
 | 
				
			||||||
 | 
					        default_name_id_policy:
 | 
				
			||||||
 | 
					          $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
 | 
				
			||||||
        url_download_metadata:
 | 
					        url_download_metadata:
 | 
				
			||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
          description: Get metadata download URL
 | 
					          description: Get metadata download URL
 | 
				
			||||||
@ -57694,6 +57711,8 @@ components:
 | 
				
			|||||||
        default_relay_state:
 | 
					        default_relay_state:
 | 
				
			||||||
          type: string
 | 
					          type: string
 | 
				
			||||||
          description: Default relay_state value for IDP-initiated logins
 | 
					          description: Default relay_state value for IDP-initiated logins
 | 
				
			||||||
 | 
					        default_name_id_policy:
 | 
				
			||||||
 | 
					          $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
 | 
				
			||||||
      required:
 | 
					      required:
 | 
				
			||||||
      - acs_url
 | 
					      - acs_url
 | 
				
			||||||
      - authorization_flow
 | 
					      - authorization_flow
 | 
				
			||||||
@ -57802,7 +57821,7 @@ components:
 | 
				
			|||||||
            be a security risk, as no validation of the request ID is done.
 | 
					            be a security risk, as no validation of the request ID is done.
 | 
				
			||||||
        name_id_policy:
 | 
					        name_id_policy:
 | 
				
			||||||
          allOf:
 | 
					          allOf:
 | 
				
			||||||
          - $ref: '#/components/schemas/NameIdPolicyEnum'
 | 
					          - $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
 | 
				
			||||||
          description: NameID Policy sent to the IdP. Can be unset, in which case
 | 
					          description: NameID Policy sent to the IdP. Can be unset, in which case
 | 
				
			||||||
            no Policy is sent.
 | 
					            no Policy is sent.
 | 
				
			||||||
        binding_type:
 | 
					        binding_type:
 | 
				
			||||||
@ -57992,7 +58011,7 @@ components:
 | 
				
			|||||||
            be a security risk, as no validation of the request ID is done.
 | 
					            be a security risk, as no validation of the request ID is done.
 | 
				
			||||||
        name_id_policy:
 | 
					        name_id_policy:
 | 
				
			||||||
          allOf:
 | 
					          allOf:
 | 
				
			||||||
          - $ref: '#/components/schemas/NameIdPolicyEnum'
 | 
					          - $ref: '#/components/schemas/SAMLNameIDPolicyEnum'
 | 
				
			||||||
          description: NameID Policy sent to the IdP. Can be unset, in which case
 | 
					          description: NameID Policy sent to the IdP. Can be unset, in which case
 | 
				
			||||||
            no Policy is sent.
 | 
					            no Policy is sent.
 | 
				
			||||||
        binding_type:
 | 
					        binding_type:
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ services:
 | 
				
			|||||||
    network_mode: host
 | 
					    network_mode: host
 | 
				
			||||||
    restart: always
 | 
					    restart: always
 | 
				
			||||||
  mailpit:
 | 
					  mailpit:
 | 
				
			||||||
    image: docker.io/axllent/mailpit:v1.26.0
 | 
					    image: docker.io/axllent/mailpit:v1.26.1
 | 
				
			||||||
    ports:
 | 
					    ports:
 | 
				
			||||||
      - 1025:1025
 | 
					      - 1025:1025
 | 
				
			||||||
      - 8025:8025
 | 
					      - 8025:8025
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								uv.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										18
									
								
								uv.lock
									
									
									
										generated
									
									
									
								
							@ -165,7 +165,7 @@ wheels = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "authentik"
 | 
					name = "authentik"
 | 
				
			||||||
version = "2025.6.1"
 | 
					version = "2025.6.2"
 | 
				
			||||||
source = { editable = "." }
 | 
					source = { editable = "." }
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
    { name = "argon2-cffi" },
 | 
					    { name = "argon2-cffi" },
 | 
				
			||||||
@ -309,7 +309,7 @@ requires-dist = [
 | 
				
			|||||||
    { name = "packaging", specifier = "==25.0" },
 | 
					    { name = "packaging", specifier = "==25.0" },
 | 
				
			||||||
    { name = "paramiko", specifier = "==3.5.1" },
 | 
					    { name = "paramiko", specifier = "==3.5.1" },
 | 
				
			||||||
    { name = "psycopg", extras = ["c", "pool"], specifier = "==3.2.9" },
 | 
					    { name = "psycopg", extras = ["c", "pool"], specifier = "==3.2.9" },
 | 
				
			||||||
    { name = "pydantic", specifier = "==2.11.5" },
 | 
					    { name = "pydantic", specifier = "==2.11.7" },
 | 
				
			||||||
    { name = "pydantic-scim", specifier = "==0.0.8" },
 | 
					    { name = "pydantic-scim", specifier = "==0.0.8" },
 | 
				
			||||||
    { name = "pyjwt", specifier = "==2.10.1" },
 | 
					    { name = "pyjwt", specifier = "==2.10.1" },
 | 
				
			||||||
    { name = "pyrad", specifier = "==2.4" },
 | 
					    { name = "pyrad", specifier = "==2.4" },
 | 
				
			||||||
@ -329,7 +329,7 @@ requires-dist = [
 | 
				
			|||||||
    { name = "urllib3", specifier = "<3" },
 | 
					    { name = "urllib3", specifier = "<3" },
 | 
				
			||||||
    { name = "uvicorn", extras = ["standard"], specifier = "==0.34.3" },
 | 
					    { name = "uvicorn", extras = ["standard"], specifier = "==0.34.3" },
 | 
				
			||||||
    { name = "watchdog", specifier = "==6.0.0" },
 | 
					    { name = "watchdog", specifier = "==6.0.0" },
 | 
				
			||||||
    { name = "webauthn", specifier = "==2.5.2" },
 | 
					    { name = "webauthn", specifier = "==2.6.0" },
 | 
				
			||||||
    { name = "wsproto", specifier = "==1.2.0" },
 | 
					    { name = "wsproto", specifier = "==1.2.0" },
 | 
				
			||||||
    { name = "xmlsec", specifier = "==1.3.15" },
 | 
					    { name = "xmlsec", specifier = "==1.3.15" },
 | 
				
			||||||
    { name = "zxcvbn", specifier = "==4.5.0" },
 | 
					    { name = "zxcvbn", specifier = "==4.5.0" },
 | 
				
			||||||
@ -2463,7 +2463,7 @@ wheels = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "pydantic"
 | 
					name = "pydantic"
 | 
				
			||||||
version = "2.11.5"
 | 
					version = "2.11.7"
 | 
				
			||||||
source = { registry = "https://pypi.org/simple" }
 | 
					source = { registry = "https://pypi.org/simple" }
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
    { name = "annotated-types" },
 | 
					    { name = "annotated-types" },
 | 
				
			||||||
@ -2471,9 +2471,9 @@ dependencies = [
 | 
				
			|||||||
    { name = "typing-extensions" },
 | 
					    { name = "typing-extensions" },
 | 
				
			||||||
    { name = "typing-inspection" },
 | 
					    { name = "typing-inspection" },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
sdist = { url = "https://files.pythonhosted.org/packages/f0/86/8ce9040065e8f924d642c58e4a344e33163a07f6b57f836d0d734e0ad3fb/pydantic-2.11.5.tar.gz", hash = "sha256:7f853db3d0ce78ce8bbb148c401c2cdd6431b3473c0cdff2755c7690952a7b7a", size = 787102, upload-time = "2025-05-22T21:18:08.761Z" }
 | 
					sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" }
 | 
				
			||||||
wheels = [
 | 
					wheels = [
 | 
				
			||||||
    { url = "https://files.pythonhosted.org/packages/b5/69/831ed22b38ff9b4b64b66569f0e5b7b97cf3638346eb95a2147fdb49ad5f/pydantic-2.11.5-py3-none-any.whl", hash = "sha256:f9c26ba06f9747749ca1e5c94d6a85cb84254577553c8785576fd38fa64dc0f7", size = 444229, upload-time = "2025-05-22T21:18:06.329Z" },
 | 
					    { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[package.optional-dependencies]
 | 
					[package.optional-dependencies]
 | 
				
			||||||
@ -3391,7 +3391,7 @@ wheels = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "webauthn"
 | 
					name = "webauthn"
 | 
				
			||||||
version = "2.5.2"
 | 
					version = "2.6.0"
 | 
				
			||||||
source = { registry = "https://pypi.org/simple" }
 | 
					source = { registry = "https://pypi.org/simple" }
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
    { name = "asn1crypto" },
 | 
					    { name = "asn1crypto" },
 | 
				
			||||||
@ -3399,9 +3399,9 @@ dependencies = [
 | 
				
			|||||||
    { name = "cryptography" },
 | 
					    { name = "cryptography" },
 | 
				
			||||||
    { name = "pyopenssl" },
 | 
					    { name = "pyopenssl" },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
sdist = { url = "https://files.pythonhosted.org/packages/8d/92/8d2a4eec83d8e7feacdaad37c6eb6eb922100cecce5c14a41d8069a59a03/webauthn-2.5.2.tar.gz", hash = "sha256:09c13dfc1c68c810f32fa4d89b1d37acb9f9ae9091c9d7019e313be4525a95ef", size = 124114, upload-time = "2025-03-07T19:44:05.243Z" }
 | 
					sdist = { url = "https://files.pythonhosted.org/packages/63/38/5792cb2034673c162a721df0ad65825699516ee0c938a65670ad3cdabf6c/webauthn-2.6.0.tar.gz", hash = "sha256:13cf5b009a64cef569599ffecf24550df1d7c0cd4fbaea870f937148484a80b4", size = 123608, upload-time = "2025-06-16T22:25:26.76Z" }
 | 
				
			||||||
wheels = [
 | 
					wheels = [
 | 
				
			||||||
    { url = "https://files.pythonhosted.org/packages/7f/fe/f6ae41de9f383439e30b303a67f6f45d2fceabedaedc34c62f74d58c5c73/webauthn-2.5.2-py3-none-any.whl", hash = "sha256:44246e496e617eb5e2f51165046b9f0197fcdf470f69cd6734061a27ba365f8e", size = 71624, upload-time = "2025-03-07T19:44:03.728Z" },
 | 
					    { url = "https://files.pythonhosted.org/packages/56/c5/b1bba7f6a50caca77f37003e098f48f8dc68d990aba8a03ac8376016430b/webauthn-2.6.0-py3-none-any.whl", hash = "sha256:459973eb5780c1f41bec42b682acf587456b185733398a0b99a0714705b79447", size = 71189, upload-time = "2025-06-16T22:25:25.535Z" },
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1703
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1703
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -93,7 +93,7 @@
 | 
				
			|||||||
        "@floating-ui/dom": "^1.6.11",
 | 
					        "@floating-ui/dom": "^1.6.11",
 | 
				
			||||||
        "@formatjs/intl-listformat": "^7.7.11",
 | 
					        "@formatjs/intl-listformat": "^7.7.11",
 | 
				
			||||||
        "@fortawesome/fontawesome-free": "^6.7.2",
 | 
					        "@fortawesome/fontawesome-free": "^6.7.2",
 | 
				
			||||||
        "@goauthentik/api": "^2025.6.1-1749515784",
 | 
					        "@goauthentik/api": "^2025.6.2-1750112513",
 | 
				
			||||||
        "@lit/context": "^1.1.2",
 | 
					        "@lit/context": "^1.1.2",
 | 
				
			||||||
        "@lit/localize": "^0.12.2",
 | 
					        "@lit/localize": "^0.12.2",
 | 
				
			||||||
        "@lit/reactive-element": "^2.0.4",
 | 
					        "@lit/reactive-element": "^2.0.4",
 | 
				
			||||||
@ -102,10 +102,9 @@
 | 
				
			|||||||
        "@open-wc/lit-helpers": "^0.7.0",
 | 
					        "@open-wc/lit-helpers": "^0.7.0",
 | 
				
			||||||
        "@patternfly/elements": "^4.1.0",
 | 
					        "@patternfly/elements": "^4.1.0",
 | 
				
			||||||
        "@patternfly/patternfly": "^4.224.2",
 | 
					        "@patternfly/patternfly": "^4.224.2",
 | 
				
			||||||
        "@sentry/browser": "^9.28.1",
 | 
					        "@sentry/browser": "^9.30.0",
 | 
				
			||||||
        "@spotlightjs/spotlight": "^3.0.0",
 | 
					        "@spotlightjs/spotlight": "^3.0.0",
 | 
				
			||||||
        "@webcomponents/webcomponentsjs": "^2.8.0",
 | 
					        "@webcomponents/webcomponentsjs": "^2.8.0",
 | 
				
			||||||
        "base64-js": "^1.5.1",
 | 
					 | 
				
			||||||
        "change-case": "^5.4.4",
 | 
					        "change-case": "^5.4.4",
 | 
				
			||||||
        "chart.js": "^4.4.9",
 | 
					        "chart.js": "^4.4.9",
 | 
				
			||||||
        "chartjs-adapter-date-fns": "^3.0.0",
 | 
					        "chartjs-adapter-date-fns": "^3.0.0",
 | 
				
			||||||
@ -137,6 +136,7 @@
 | 
				
			|||||||
        "trusted-types": "^2.0.0",
 | 
					        "trusted-types": "^2.0.0",
 | 
				
			||||||
        "ts-pattern": "^5.7.1",
 | 
					        "ts-pattern": "^5.7.1",
 | 
				
			||||||
        "unist-util-visit": "^5.0.0",
 | 
					        "unist-util-visit": "^5.0.0",
 | 
				
			||||||
 | 
					        "webauthn-polyfills": "^0.1.7",
 | 
				
			||||||
        "webcomponent-qr-code": "^1.2.0",
 | 
					        "webcomponent-qr-code": "^1.2.0",
 | 
				
			||||||
        "yaml": "^2.8.0"
 | 
					        "yaml": "^2.8.0"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
@ -170,16 +170,16 @@
 | 
				
			|||||||
        "@types/react-dom": "^19.1.5",
 | 
					        "@types/react-dom": "^19.1.5",
 | 
				
			||||||
        "@typescript-eslint/eslint-plugin": "^8.8.0",
 | 
					        "@typescript-eslint/eslint-plugin": "^8.8.0",
 | 
				
			||||||
        "@typescript-eslint/parser": "^8.8.0",
 | 
					        "@typescript-eslint/parser": "^8.8.0",
 | 
				
			||||||
        "@wdio/browser-runner": "9.4",
 | 
					        "@wdio/browser-runner": "9.15",
 | 
				
			||||||
        "@wdio/cli": "9.4",
 | 
					        "@wdio/cli": "9.15",
 | 
				
			||||||
        "@wdio/spec-reporter": "^9.1.2",
 | 
					        "@wdio/spec-reporter": "^9.15.0",
 | 
				
			||||||
        "@web/test-runner": "^0.20.2",
 | 
					        "@web/test-runner": "^0.20.2",
 | 
				
			||||||
        "chromedriver": "^136.0.3",
 | 
					        "chromedriver": "^136.0.3",
 | 
				
			||||||
        "esbuild": "^0.25.5",
 | 
					        "esbuild": "^0.25.5",
 | 
				
			||||||
        "esbuild-plugin-copy": "^2.1.1",
 | 
					        "esbuild-plugin-copy": "^2.1.1",
 | 
				
			||||||
        "esbuild-plugin-polyfill-node": "^0.3.0",
 | 
					        "esbuild-plugin-polyfill-node": "^0.3.0",
 | 
				
			||||||
        "esbuild-plugins-node-modules-polyfill": "^1.7.0",
 | 
					        "esbuild-plugins-node-modules-polyfill": "^1.7.0",
 | 
				
			||||||
        "eslint": "^9.28.0",
 | 
					        "eslint": "^9.29.0",
 | 
				
			||||||
        "eslint-plugin-lit": "^2.1.1",
 | 
					        "eslint-plugin-lit": "^2.1.1",
 | 
				
			||||||
        "eslint-plugin-wc": "^3.0.1",
 | 
					        "eslint-plugin-wc": "^3.0.1",
 | 
				
			||||||
        "github-slugger": "^2.0.0",
 | 
					        "github-slugger": "^2.0.0",
 | 
				
			||||||
@ -194,7 +194,7 @@
 | 
				
			|||||||
        "storybook-addon-mock": "^5.0.0",
 | 
					        "storybook-addon-mock": "^5.0.0",
 | 
				
			||||||
        "turnstile-types": "^1.2.3",
 | 
					        "turnstile-types": "^1.2.3",
 | 
				
			||||||
        "typescript": "^5.8.3",
 | 
					        "typescript": "^5.8.3",
 | 
				
			||||||
        "typescript-eslint": "^8.34.0",
 | 
					        "typescript-eslint": "^8.34.1",
 | 
				
			||||||
        "vite-plugin-lit-css": "^2.0.0",
 | 
					        "vite-plugin-lit-css": "^2.0.0",
 | 
				
			||||||
        "vite-tsconfig-paths": "^5.0.1",
 | 
					        "vite-tsconfig-paths": "^5.0.1",
 | 
				
			||||||
        "wireit": "^0.14.12"
 | 
					        "wireit": "^0.14.12"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								web/packages/core/types/node.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								web/packages/core/types/node.d.ts
									
									
									
									
										vendored
									
									
								
							@ -14,7 +14,7 @@ declare module "module" {
 | 
				
			|||||||
         * const relativeDirname = dirname(fileURLToPath(import.meta.url));
 | 
					         * const relativeDirname = dirname(fileURLToPath(import.meta.url));
 | 
				
			||||||
         * ```
 | 
					         * ```
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        // eslint-disable-next-line no-var
 | 
					
 | 
				
			||||||
        var __dirname: string;
 | 
					        var __dirname: string;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -11,11 +11,11 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "dependencies": {
 | 
					    "dependencies": {
 | 
				
			||||||
        "@goauthentik/api": "^2024.6.0-1719577139",
 | 
					        "@goauthentik/api": "^2024.6.0-1719577139",
 | 
				
			||||||
        "base64-js": "^1.5.1",
 | 
					 | 
				
			||||||
        "bootstrap": "^4.6.1",
 | 
					        "bootstrap": "^4.6.1",
 | 
				
			||||||
        "formdata-polyfill": "^4.0.10",
 | 
					        "formdata-polyfill": "^4.0.10",
 | 
				
			||||||
        "jquery": "^3.7.1",
 | 
					        "jquery": "^3.7.1",
 | 
				
			||||||
        "weakmap-polyfill": "^2.0.4"
 | 
					        "weakmap-polyfill": "^2.0.4",
 | 
				
			||||||
 | 
					        "webauthn-polyfills": "^0.1.7"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "devDependencies": {
 | 
					    "devDependencies": {
 | 
				
			||||||
        "@goauthentik/core": "^1.0.0",
 | 
					        "@goauthentik/core": "^1.0.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { fromByteArray } from "base64-js";
 | 
					 | 
				
			||||||
import "formdata-polyfill";
 | 
					import "formdata-polyfill";
 | 
				
			||||||
import $ from "jquery";
 | 
					import $ from "jquery";
 | 
				
			||||||
import "weakmap-polyfill";
 | 
					import "weakmap-polyfill";
 | 
				
			||||||
 | 
					import "webauthn-polyfills";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    type AuthenticatorValidationChallenge,
 | 
					    type AuthenticatorValidationChallenge,
 | 
				
			||||||
@ -257,47 +257,9 @@ class AutosubmitStage extends Stage<AutosubmitChallenge> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Assertion {
 | 
					 | 
				
			||||||
    id: string;
 | 
					 | 
				
			||||||
    rawId: string;
 | 
					 | 
				
			||||||
    type: string;
 | 
					 | 
				
			||||||
    registrationClientExtensions: string;
 | 
					 | 
				
			||||||
    response: {
 | 
					 | 
				
			||||||
        clientDataJSON: string;
 | 
					 | 
				
			||||||
        attestationObject: string;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface AuthAssertion {
 | 
					 | 
				
			||||||
    id: string;
 | 
					 | 
				
			||||||
    rawId: string;
 | 
					 | 
				
			||||||
    type: string;
 | 
					 | 
				
			||||||
    assertionClientExtensions: string;
 | 
					 | 
				
			||||||
    response: {
 | 
					 | 
				
			||||||
        clientDataJSON: string;
 | 
					 | 
				
			||||||
        authenticatorData: string;
 | 
					 | 
				
			||||||
        signature: string;
 | 
					 | 
				
			||||||
        userHandle: string | null;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge> {
 | 
					class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge> {
 | 
				
			||||||
    deviceChallenge?: DeviceChallenge;
 | 
					    deviceChallenge?: DeviceChallenge;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    b64enc(buf: Uint8Array): string {
 | 
					 | 
				
			||||||
        return fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    b64RawEnc(buf: Uint8Array): string {
 | 
					 | 
				
			||||||
        return fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    u8arr(input: string): Uint8Array {
 | 
					 | 
				
			||||||
        return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) =>
 | 
					 | 
				
			||||||
            c.charCodeAt(0),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    checkWebAuthnSupport(): boolean {
 | 
					    checkWebAuthnSupport(): boolean {
 | 
				
			||||||
        if ("credentials" in navigator) {
 | 
					        if ("credentials" in navigator) {
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
@ -310,98 +272,6 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Transforms items in the credentialCreateOptions generated on the server
 | 
					 | 
				
			||||||
     * into byte arrays expected by the navigator.credentials.create() call
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    transformCredentialCreateOptions(
 | 
					 | 
				
			||||||
        credentialCreateOptions: PublicKeyCredentialCreationOptions,
 | 
					 | 
				
			||||||
        userId: string,
 | 
					 | 
				
			||||||
    ): PublicKeyCredentialCreationOptions {
 | 
					 | 
				
			||||||
        const user = credentialCreateOptions.user;
 | 
					 | 
				
			||||||
        // Because json can't contain raw bytes, the server base64-encodes the User ID
 | 
					 | 
				
			||||||
        // So to get the base64 encoded byte array, we first need to convert it to a regular
 | 
					 | 
				
			||||||
        // string, then a byte array, re-encode it and wrap that in an array.
 | 
					 | 
				
			||||||
        const stringId = decodeURIComponent(window.atob(userId));
 | 
					 | 
				
			||||||
        user.id = this.u8arr(this.b64enc(this.u8arr(stringId)));
 | 
					 | 
				
			||||||
        const challenge = this.u8arr(credentialCreateOptions.challenge.toString());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return Object.assign({}, credentialCreateOptions, {
 | 
					 | 
				
			||||||
            challenge,
 | 
					 | 
				
			||||||
            user,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Transforms the binary data in the credential into base64 strings
 | 
					 | 
				
			||||||
     * for posting to the server.
 | 
					 | 
				
			||||||
     * @param {PublicKeyCredential} newAssertion
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    transformNewAssertionForServer(newAssertion: PublicKeyCredential): Assertion {
 | 
					 | 
				
			||||||
        const attObj = new Uint8Array(
 | 
					 | 
				
			||||||
            (newAssertion.response as AuthenticatorAttestationResponse).attestationObject,
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        const clientDataJSON = new Uint8Array(newAssertion.response.clientDataJSON);
 | 
					 | 
				
			||||||
        const rawId = new Uint8Array(newAssertion.rawId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const registrationClientExtensions = newAssertion.getClientExtensionResults();
 | 
					 | 
				
			||||||
        return {
 | 
					 | 
				
			||||||
            id: newAssertion.id,
 | 
					 | 
				
			||||||
            rawId: this.b64enc(rawId),
 | 
					 | 
				
			||||||
            type: newAssertion.type,
 | 
					 | 
				
			||||||
            registrationClientExtensions: JSON.stringify(registrationClientExtensions),
 | 
					 | 
				
			||||||
            response: {
 | 
					 | 
				
			||||||
                clientDataJSON: this.b64enc(clientDataJSON),
 | 
					 | 
				
			||||||
                attestationObject: this.b64enc(attObj),
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    transformCredentialRequestOptions(
 | 
					 | 
				
			||||||
        credentialRequestOptions: PublicKeyCredentialRequestOptions,
 | 
					 | 
				
			||||||
    ): PublicKeyCredentialRequestOptions {
 | 
					 | 
				
			||||||
        const challenge = this.u8arr(credentialRequestOptions.challenge.toString());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const allowCredentials = (credentialRequestOptions.allowCredentials || []).map(
 | 
					 | 
				
			||||||
            (credentialDescriptor) => {
 | 
					 | 
				
			||||||
                const id = this.u8arr(credentialDescriptor.id.toString());
 | 
					 | 
				
			||||||
                return Object.assign({}, credentialDescriptor, { id });
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return Object.assign({}, credentialRequestOptions, {
 | 
					 | 
				
			||||||
            challenge,
 | 
					 | 
				
			||||||
            allowCredentials,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Encodes the binary data in the assertion into strings for posting to the server.
 | 
					 | 
				
			||||||
     * @param {PublicKeyCredential} newAssertion
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    transformAssertionForServer(newAssertion: PublicKeyCredential): AuthAssertion {
 | 
					 | 
				
			||||||
        const response = newAssertion.response as AuthenticatorAssertionResponse;
 | 
					 | 
				
			||||||
        const authData = new Uint8Array(response.authenticatorData);
 | 
					 | 
				
			||||||
        const clientDataJSON = new Uint8Array(response.clientDataJSON);
 | 
					 | 
				
			||||||
        const rawId = new Uint8Array(newAssertion.rawId);
 | 
					 | 
				
			||||||
        const sig = new Uint8Array(response.signature);
 | 
					 | 
				
			||||||
        const assertionClientExtensions = newAssertion.getClientExtensionResults();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return {
 | 
					 | 
				
			||||||
            id: newAssertion.id,
 | 
					 | 
				
			||||||
            rawId: this.b64enc(rawId),
 | 
					 | 
				
			||||||
            type: newAssertion.type,
 | 
					 | 
				
			||||||
            assertionClientExtensions: JSON.stringify(assertionClientExtensions),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            response: {
 | 
					 | 
				
			||||||
                clientDataJSON: this.b64RawEnc(clientDataJSON),
 | 
					 | 
				
			||||||
                signature: this.b64RawEnc(sig),
 | 
					 | 
				
			||||||
                authenticatorData: this.b64RawEnc(authData),
 | 
					 | 
				
			||||||
                userHandle: null,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    render() {
 | 
					    render() {
 | 
				
			||||||
        if (this.challenge.deviceChallenges.length === 1) {
 | 
					        if (this.challenge.deviceChallenges.length === 1) {
 | 
				
			||||||
            this.deviceChallenge = this.challenge.deviceChallenges[0];
 | 
					            this.deviceChallenge = this.challenge.deviceChallenges[0];
 | 
				
			||||||
@ -505,8 +375,8 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
 | 
				
			|||||||
            `);
 | 
					            `);
 | 
				
			||||||
        navigator.credentials
 | 
					        navigator.credentials
 | 
				
			||||||
            .get({
 | 
					            .get({
 | 
				
			||||||
                publicKey: this.transformCredentialRequestOptions(
 | 
					                publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(
 | 
				
			||||||
                    this.deviceChallenge?.challenge as PublicKeyCredentialRequestOptions,
 | 
					                    this.deviceChallenge?.challenge as PublicKeyCredentialRequestOptionsJSON,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .then((assertion) => {
 | 
					            .then((assertion) => {
 | 
				
			||||||
@ -514,15 +384,9 @@ class AuthenticatorValidateStage extends Stage<AuthenticatorValidationChallenge>
 | 
				
			|||||||
                    throw new Error("No assertion");
 | 
					                    throw new Error("No assertion");
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    // we now have an authentication assertion! encode the byte arrays contained
 | 
					 | 
				
			||||||
                    // in the assertion data as strings for posting to the server
 | 
					 | 
				
			||||||
                    const transformedAssertionForServer = this.transformAssertionForServer(
 | 
					 | 
				
			||||||
                        assertion as PublicKeyCredential,
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    // post the assertion to the server for verification.
 | 
					                    // post the assertion to the server for verification.
 | 
				
			||||||
                    this.executor.submit({
 | 
					                    this.executor.submit({
 | 
				
			||||||
                        webauthn: transformedAssertionForServer,
 | 
					                        webauthn: (assertion as PublicKeyCredential).toJSON(),
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
                } catch (err) {
 | 
					                } catch (err) {
 | 
				
			||||||
                    throw new Error(`Error when validating assertion on server: ${err}`);
 | 
					                    throw new Error(`Error when validating assertion on server: ${err}`);
 | 
				
			||||||
 | 
				
			|||||||
@ -88,7 +88,8 @@ export class RecentEventsCard extends Table<Event> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return super.renderEmpty(
 | 
					        return super.renderEmpty(
 | 
				
			||||||
            html`<ak-empty-state header=${msg("No Events found.")}>
 | 
					            html`<ak-empty-state
 | 
				
			||||||
 | 
					                ><span slot="header">${msg("No Events found.")}</span>
 | 
				
			||||||
                <div slot="body">${msg("No matching events could be found.")}</div>
 | 
					                <div slot="body">${msg("No matching events could be found.")}</div>
 | 
				
			||||||
            </ak-empty-state>`,
 | 
					            </ak-empty-state>`,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ import { policyEngineModes } from "@goauthentik/admin/policies/PolicyEngineModes
 | 
				
			|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
 | 
					import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
 | 
				
			||||||
import "@goauthentik/components/ak-file-input";
 | 
					import "@goauthentik/components/ak-file-input";
 | 
				
			||||||
import "@goauthentik/components/ak-radio-input";
 | 
					import "@goauthentik/components/ak-radio-input";
 | 
				
			||||||
 | 
					import "@goauthentik/components/ak-slug-input";
 | 
				
			||||||
import "@goauthentik/components/ak-switch-input";
 | 
					import "@goauthentik/components/ak-switch-input";
 | 
				
			||||||
import "@goauthentik/components/ak-text-input";
 | 
					import "@goauthentik/components/ak-text-input";
 | 
				
			||||||
import "@goauthentik/components/ak-textarea-input";
 | 
					import "@goauthentik/components/ak-textarea-input";
 | 
				
			||||||
@ -130,14 +131,14 @@ export class ApplicationForm extends WithCapabilitiesConfig(ModelForm<Applicatio
 | 
				
			|||||||
                required
 | 
					                required
 | 
				
			||||||
                help=${msg("Application's display Name.")}
 | 
					                help=${msg("Application's display Name.")}
 | 
				
			||||||
            ></ak-text-input>
 | 
					            ></ak-text-input>
 | 
				
			||||||
            <ak-text-input
 | 
					            <ak-slug-input
 | 
				
			||||||
                name="slug"
 | 
					                name="slug"
 | 
				
			||||||
                value=${ifDefined(this.instance?.slug)}
 | 
					                value=${ifDefined(this.instance?.slug)}
 | 
				
			||||||
                label=${msg("Slug")}
 | 
					                label=${msg("Slug")}
 | 
				
			||||||
                required
 | 
					                required
 | 
				
			||||||
                help=${msg("Internal application name used in URLs.")}
 | 
					                help=${msg("Internal application name used in URLs.")}
 | 
				
			||||||
                input-hint="code"
 | 
					                input-hint="code"
 | 
				
			||||||
            ></ak-text-input>
 | 
					            ></ak-slug-input>
 | 
				
			||||||
            <ak-text-input
 | 
					            <ak-text-input
 | 
				
			||||||
                name="group"
 | 
					                name="group"
 | 
				
			||||||
                value=${ifDefined(this.instance?.group)}
 | 
					                value=${ifDefined(this.instance?.group)}
 | 
				
			||||||
 | 
				
			|||||||
@ -117,13 +117,11 @@ export class ApplicationWizardApplicationStep extends ApplicationWizardStep {
 | 
				
			|||||||
                    ?invalid=${this.errors.has("name")}
 | 
					                    ?invalid=${this.errors.has("name")}
 | 
				
			||||||
                    .errorMessages=${errors.name ?? this.errorMessages("name")}
 | 
					                    .errorMessages=${errors.name ?? this.errorMessages("name")}
 | 
				
			||||||
                    help=${msg("Application's display Name.")}
 | 
					                    help=${msg("Application's display Name.")}
 | 
				
			||||||
                    id="ak-application-wizard-details-name"
 | 
					 | 
				
			||||||
                ></ak-text-input>
 | 
					                ></ak-text-input>
 | 
				
			||||||
                <ak-slug-input
 | 
					                <ak-slug-input
 | 
				
			||||||
                    name="slug"
 | 
					                    name="slug"
 | 
				
			||||||
                    value=${ifDefined(app.slug)}
 | 
					                    value=${ifDefined(app.slug)}
 | 
				
			||||||
                    label=${msg("Slug")}
 | 
					                    label=${msg("Slug")}
 | 
				
			||||||
                    source="#ak-application-wizard-details-name"
 | 
					 | 
				
			||||||
                    required
 | 
					                    required
 | 
				
			||||||
                    ?invalid=${errors.slug ?? this.errors.has("slug")}
 | 
					                    ?invalid=${errors.slug ?? this.errors.has("slug")}
 | 
				
			||||||
                    .errorMessages=${this.errorMessages("slug")}
 | 
					                    .errorMessages=${this.errorMessages("slug")}
 | 
				
			||||||
 | 
				
			|||||||
@ -115,7 +115,8 @@ export class ApplicationWizardBindingsStep extends ApplicationWizardStep {
 | 
				
			|||||||
                    .columns=${COLUMNS}
 | 
					                    .columns=${COLUMNS}
 | 
				
			||||||
                    .content=${[]}
 | 
					                    .content=${[]}
 | 
				
			||||||
                ></ak-select-table>
 | 
					                ></ak-select-table>
 | 
				
			||||||
                <ak-empty-state header=${msg("No bound policies.")} icon="pf-icon-module">
 | 
					                <ak-empty-state icon="pf-icon-module"
 | 
				
			||||||
 | 
					                    ><span slot="header">${msg("No bound policies.")} </span>
 | 
				
			||||||
                    <div slot="body">${msg("No policies are currently bound to this object.")}</div>
 | 
					                    <div slot="body">${msg("No policies are currently bound to this object.")}</div>
 | 
				
			||||||
                    <div slot="primary">
 | 
					                    <div slot="primary">
 | 
				
			||||||
                        <button
 | 
					                        <button
 | 
				
			||||||
 | 
				
			|||||||
@ -135,7 +135,8 @@ export class BoundStagesList extends Table<FlowStageBinding> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    renderEmpty(): TemplateResult {
 | 
					    renderEmpty(): TemplateResult {
 | 
				
			||||||
        return super.renderEmpty(
 | 
					        return super.renderEmpty(
 | 
				
			||||||
            html`<ak-empty-state header=${msg("No Stages bound")} icon="pf-icon-module">
 | 
					            html`<ak-empty-state icon="pf-icon-module">
 | 
				
			||||||
 | 
					                <span slot="header">${msg("No Stages bound")}</span>
 | 
				
			||||||
                <div slot="body">${msg("No stages are currently bound to this flow.")}</div>
 | 
					                <div slot="body">${msg("No stages are currently bound to this flow.")}</div>
 | 
				
			||||||
                <div slot="primary">
 | 
					                <div slot="primary">
 | 
				
			||||||
                    <ak-stage-wizard
 | 
					                    <ak-stage-wizard
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ import { DesignationToLabel, LayoutToLabel } from "@goauthentik/admin/flows/util
 | 
				
			|||||||
import { policyEngineModes } from "@goauthentik/admin/policies/PolicyEngineModes";
 | 
					import { policyEngineModes } from "@goauthentik/admin/policies/PolicyEngineModes";
 | 
				
			||||||
import { AuthenticationEnum } from "@goauthentik/api/dist/models/AuthenticationEnum";
 | 
					import { AuthenticationEnum } from "@goauthentik/api/dist/models/AuthenticationEnum";
 | 
				
			||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
 | 
					import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
 | 
				
			||||||
 | 
					import "@goauthentik/components/ak-slug-input.js";
 | 
				
			||||||
import "@goauthentik/elements/forms/FormGroup";
 | 
					import "@goauthentik/elements/forms/FormGroup";
 | 
				
			||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
 | 
					import "@goauthentik/elements/forms/HorizontalFormElement";
 | 
				
			||||||
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
 | 
					import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
 | 
				
			||||||
@ -91,17 +92,16 @@ export class FlowForm extends WithCapabilitiesConfig(ModelForm<Flow, string>) {
 | 
				
			|||||||
                />
 | 
					                />
 | 
				
			||||||
                <p class="pf-c-form__helper-text">${msg("Shown as the Title in Flow pages.")}</p>
 | 
					                <p class="pf-c-form__helper-text">${msg("Shown as the Title in Flow pages.")}</p>
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            </ak-form-element-horizontal>
 | 
				
			||||||
            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">
 | 
					
 | 
				
			||||||
                <input
 | 
					            <ak-slug-input
 | 
				
			||||||
                    type="text"
 | 
					                name="slug"
 | 
				
			||||||
                    value="${ifDefined(this.instance?.slug)}"
 | 
					                value=${ifDefined(this.instance?.slug)}
 | 
				
			||||||
                    class="pf-c-form-control pf-m-monospace"
 | 
					                label=${msg("Slug")}
 | 
				
			||||||
                    autocomplete="off"
 | 
					 | 
				
			||||||
                    spellcheck="false"
 | 
					 | 
				
			||||||
                required
 | 
					                required
 | 
				
			||||||
                />
 | 
					                help=${msg("Visible in the URL.")}
 | 
				
			||||||
                <p class="pf-c-form__helper-text">${msg("Visible in the URL.")}</p>
 | 
					                input-hint="code"
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            ></ak-slug-input>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <ak-form-element-horizontal label=${msg("Designation")} required name="designation">
 | 
					            <ak-form-element-horizontal label=${msg("Designation")} required name="designation">
 | 
				
			||||||
                <select class="pf-c-form-control">
 | 
					                <select class="pf-c-form-control">
 | 
				
			||||||
                    <option value="" ?selected=${this.instance?.designation === undefined}>
 | 
					                    <option value="" ?selected=${this.instance?.designation === undefined}>
 | 
				
			||||||
 | 
				
			|||||||
@ -198,7 +198,8 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    renderEmpty(): TemplateResult {
 | 
					    renderEmpty(): TemplateResult {
 | 
				
			||||||
        return super.renderEmpty(
 | 
					        return super.renderEmpty(
 | 
				
			||||||
            html`<ak-empty-state header=${msg("No Policies bound.")} icon="pf-icon-module">
 | 
					            html`<ak-empty-state icon="pf-icon-module"
 | 
				
			||||||
 | 
					                ><span slot="header">${msg("No Policies bound.")}</span>
 | 
				
			||||||
                <div slot="body">${msg("No policies are currently bound to this object.")}</div>
 | 
					                <div slot="body">${msg("No policies are currently bound to this object.")}</div>
 | 
				
			||||||
                <div slot="primary">
 | 
					                <div slot="primary">
 | 
				
			||||||
                    <ak-policy-wizard
 | 
					                    <ak-policy-wizard
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,7 @@ import {
 | 
				
			|||||||
    FlowsInstancesListDesignationEnum,
 | 
					    FlowsInstancesListDesignationEnum,
 | 
				
			||||||
    PropertymappingsApi,
 | 
					    PropertymappingsApi,
 | 
				
			||||||
    PropertymappingsProviderSamlListRequest,
 | 
					    PropertymappingsProviderSamlListRequest,
 | 
				
			||||||
 | 
					    SAMLNameIDPolicyEnum,
 | 
				
			||||||
    SAMLPropertyMapping,
 | 
					    SAMLPropertyMapping,
 | 
				
			||||||
    SAMLProvider,
 | 
					    SAMLProvider,
 | 
				
			||||||
    SpBindingEnum,
 | 
					    SpBindingEnum,
 | 
				
			||||||
@ -316,6 +317,54 @@ export function renderForm(
 | 
				
			|||||||
                        "When using IDP-initiated logins, the relay state will be set to this value.",
 | 
					                        "When using IDP-initiated logins, the relay state will be set to this value.",
 | 
				
			||||||
                    )}
 | 
					                    )}
 | 
				
			||||||
                ></ak-text-input>
 | 
					                ></ak-text-input>
 | 
				
			||||||
 | 
					                <ak-form-element-horizontal
 | 
				
			||||||
 | 
					                    label=${msg("Default NameID Policy")}
 | 
				
			||||||
 | 
					                    required
 | 
				
			||||||
 | 
					                    name="defaultNameIdPolicy"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                    <select class="pf-c-form-control">
 | 
				
			||||||
 | 
					                        <option
 | 
				
			||||||
 | 
					                            value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
 | 
				
			||||||
 | 
					                            ?selected=${provider?.defaultNameIdPolicy ===
 | 
				
			||||||
 | 
					                            SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            ${msg("Persistent")}
 | 
				
			||||||
 | 
					                        </option>
 | 
				
			||||||
 | 
					                        <option
 | 
				
			||||||
 | 
					                            value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
 | 
				
			||||||
 | 
					                            ?selected=${provider?.defaultNameIdPolicy ===
 | 
				
			||||||
 | 
					                            SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            ${msg("Email address")}
 | 
				
			||||||
 | 
					                        </option>
 | 
				
			||||||
 | 
					                        <option
 | 
				
			||||||
 | 
					                            value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
 | 
				
			||||||
 | 
					                            ?selected=${provider?.defaultNameIdPolicy ===
 | 
				
			||||||
 | 
					                            SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            ${msg("Windows")}
 | 
				
			||||||
 | 
					                        </option>
 | 
				
			||||||
 | 
					                        <option
 | 
				
			||||||
 | 
					                            value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
 | 
				
			||||||
 | 
					                            ?selected=${provider?.defaultNameIdPolicy ===
 | 
				
			||||||
 | 
					                            SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            ${msg("X509 Subject")}
 | 
				
			||||||
 | 
					                        </option>
 | 
				
			||||||
 | 
					                        <option
 | 
				
			||||||
 | 
					                            value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
 | 
				
			||||||
 | 
					                            ?selected=${provider?.defaultNameIdPolicy ===
 | 
				
			||||||
 | 
					                            SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                            ${msg("Transient")}
 | 
				
			||||||
 | 
					                        </option>
 | 
				
			||||||
 | 
					                    </select>
 | 
				
			||||||
 | 
					                    <p class="pf-c-form__helper-text">
 | 
				
			||||||
 | 
					                        ${msg(
 | 
				
			||||||
 | 
					                            "Configure the default NameID Policy used by IDP-initiated logins and when an incoming assertion doesn't specify a NameID Policy (also applies when using a custom NameID Mapping).",
 | 
				
			||||||
 | 
					                        )}
 | 
				
			||||||
 | 
					                    </p>
 | 
				
			||||||
 | 
					                </ak-form-element-horizontal>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                <ak-radio-input
 | 
					                <ak-radio-input
 | 
				
			||||||
                    name="digestAlgorithm"
 | 
					                    name="digestAlgorithm"
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ import {
 | 
				
			|||||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
 | 
					import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
 | 
				
			||||||
import "@goauthentik/components/ak-secret-text-input.js";
 | 
					import "@goauthentik/components/ak-secret-text-input.js";
 | 
				
			||||||
import "@goauthentik/components/ak-secret-textarea-input.js";
 | 
					import "@goauthentik/components/ak-secret-textarea-input.js";
 | 
				
			||||||
 | 
					import "@goauthentik/components/ak-slug-input.js";
 | 
				
			||||||
import "@goauthentik/components/ak-switch-input";
 | 
					import "@goauthentik/components/ak-switch-input";
 | 
				
			||||||
import "@goauthentik/components/ak-text-input";
 | 
					import "@goauthentik/components/ak-text-input";
 | 
				
			||||||
import "@goauthentik/components/ak-textarea-input";
 | 
					import "@goauthentik/components/ak-textarea-input";
 | 
				
			||||||
@ -87,12 +88,13 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
 | 
				
			|||||||
                value=${ifDefined(this.instance?.name)}
 | 
					                value=${ifDefined(this.instance?.name)}
 | 
				
			||||||
                required
 | 
					                required
 | 
				
			||||||
            ></ak-text-input>
 | 
					            ></ak-text-input>
 | 
				
			||||||
            <ak-text-input
 | 
					            <ak-slug-input
 | 
				
			||||||
                name="slug"
 | 
					                name="slug"
 | 
				
			||||||
                label=${msg("Slug")}
 | 
					 | 
				
			||||||
                value=${ifDefined(this.instance?.slug)}
 | 
					                value=${ifDefined(this.instance?.slug)}
 | 
				
			||||||
 | 
					                label=${msg("Slug")}
 | 
				
			||||||
                required
 | 
					                required
 | 
				
			||||||
            ></ak-text-input>
 | 
					                input-hint="code"
 | 
				
			||||||
 | 
					            ></ak-slug-input>
 | 
				
			||||||
            <ak-switch-input
 | 
					            <ak-switch-input
 | 
				
			||||||
                name="enabled"
 | 
					                name="enabled"
 | 
				
			||||||
                ?checked=${this.instance?.enabled ?? true}
 | 
					                ?checked=${this.instance?.enabled ?? true}
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ import { placeholderHelperText } from "@goauthentik/admin/helperText";
 | 
				
			|||||||
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
 | 
					import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
 | 
				
			||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
 | 
					import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
 | 
				
			||||||
import "@goauthentik/components/ak-secret-text-input.js";
 | 
					import "@goauthentik/components/ak-secret-text-input.js";
 | 
				
			||||||
 | 
					import "@goauthentik/components/ak-slug-input.js";
 | 
				
			||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
					import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
				
			||||||
import "@goauthentik/elements/forms/FormGroup";
 | 
					import "@goauthentik/elements/forms/FormGroup";
 | 
				
			||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
 | 
					import "@goauthentik/elements/forms/HorizontalFormElement";
 | 
				
			||||||
@ -54,14 +55,15 @@ export class LDAPSourceForm extends BaseSourceForm<LDAPSource> {
 | 
				
			|||||||
                    required
 | 
					                    required
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            </ak-form-element-horizontal>
 | 
				
			||||||
            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">
 | 
					
 | 
				
			||||||
                <input
 | 
					            <ak-slug-input
 | 
				
			||||||
                    type="text"
 | 
					                name="slug"
 | 
				
			||||||
                    value="${ifDefined(this.instance?.slug)}"
 | 
					                value=${ifDefined(this.instance?.slug)}
 | 
				
			||||||
                    class="pf-c-form-control"
 | 
					                label=${msg("Slug")}
 | 
				
			||||||
                required
 | 
					                required
 | 
				
			||||||
                />
 | 
					                input-hint="code"
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            ></ak-slug-input>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <ak-form-element-horizontal name="enabled">
 | 
					            <ak-form-element-horizontal name="enabled">
 | 
				
			||||||
                <label class="pf-c-switch">
 | 
					                <label class="pf-c-switch">
 | 
				
			||||||
                    <input
 | 
					                    <input
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,7 @@ import {
 | 
				
			|||||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
 | 
					import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
 | 
				
			||||||
import "@goauthentik/components/ak-radio-input";
 | 
					import "@goauthentik/components/ak-radio-input";
 | 
				
			||||||
import "@goauthentik/components/ak-secret-textarea-input.js";
 | 
					import "@goauthentik/components/ak-secret-textarea-input.js";
 | 
				
			||||||
 | 
					import "@goauthentik/components/ak-slug-input.js";
 | 
				
			||||||
import "@goauthentik/elements/CodeMirror";
 | 
					import "@goauthentik/elements/CodeMirror";
 | 
				
			||||||
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
 | 
					import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
 | 
				
			||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
					import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
				
			||||||
@ -267,16 +268,13 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
 | 
				
			|||||||
                    required
 | 
					                    required
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            </ak-form-element-horizontal>
 | 
				
			||||||
            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">
 | 
					            <ak-slug-input
 | 
				
			||||||
                <input
 | 
					                name="slug"
 | 
				
			||||||
                    type="text"
 | 
					                value=${ifDefined(this.instance?.slug)}
 | 
				
			||||||
                    value="${ifDefined(this.instance?.slug)}"
 | 
					                label=${msg("Slug")}
 | 
				
			||||||
                    class="pf-c-form-control pf-m-monospace"
 | 
					 | 
				
			||||||
                    autocomplete="off"
 | 
					 | 
				
			||||||
                    spellcheck="false"
 | 
					 | 
				
			||||||
                required
 | 
					                required
 | 
				
			||||||
                />
 | 
					                input-hint="code"
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            ></ak-slug-input>
 | 
				
			||||||
            <ak-form-element-horizontal name="enabled">
 | 
					            <ak-form-element-horizontal name="enabled">
 | 
				
			||||||
                <label class="pf-c-switch">
 | 
					                <label class="pf-c-switch">
 | 
				
			||||||
                    <input
 | 
					                    <input
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,7 @@ import {
 | 
				
			|||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
 | 
					import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
 | 
				
			||||||
import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex";
 | 
					import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex";
 | 
				
			||||||
import { ascii_letters, digits, randomString } from "@goauthentik/common/utils";
 | 
					import { ascii_letters, digits, randomString } from "@goauthentik/common/utils";
 | 
				
			||||||
 | 
					import "@goauthentik/components/ak-slug-input.js";
 | 
				
			||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
					import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
				
			||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
					import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
				
			||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
 | 
					import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js";
 | 
				
			||||||
@ -183,14 +184,15 @@ export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSo
 | 
				
			|||||||
                    required
 | 
					                    required
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            </ak-form-element-horizontal>
 | 
				
			||||||
            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">
 | 
					
 | 
				
			||||||
                <input
 | 
					            <ak-slug-input
 | 
				
			||||||
                    type="text"
 | 
					                name="slug"
 | 
				
			||||||
                    value="${ifDefined(this.instance?.slug)}"
 | 
					                value=${ifDefined(this.instance?.slug)}
 | 
				
			||||||
                    class="pf-c-form-control"
 | 
					                label=${msg("Slug")}
 | 
				
			||||||
                required
 | 
					                required
 | 
				
			||||||
                />
 | 
					                input-hint="code"
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            ></ak-slug-input>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <ak-form-element-horizontal name="enabled">
 | 
					            <ak-form-element-horizontal name="enabled">
 | 
				
			||||||
                <label class="pf-c-switch">
 | 
					                <label class="pf-c-switch">
 | 
				
			||||||
                    <input
 | 
					                    <input
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ import {
 | 
				
			|||||||
    UserMatchingModeToLabel,
 | 
					    UserMatchingModeToLabel,
 | 
				
			||||||
} from "@goauthentik/admin/sources/oauth/utils";
 | 
					} from "@goauthentik/admin/sources/oauth/utils";
 | 
				
			||||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
 | 
					import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
 | 
				
			||||||
 | 
					import "@goauthentik/components/ak-slug-input.js";
 | 
				
			||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
					import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
				
			||||||
import "@goauthentik/elements/forms/FormGroup";
 | 
					import "@goauthentik/elements/forms/FormGroup";
 | 
				
			||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
 | 
					import "@goauthentik/elements/forms/HorizontalFormElement";
 | 
				
			||||||
@ -25,7 +26,7 @@ import {
 | 
				
			|||||||
    DigestAlgorithmEnum,
 | 
					    DigestAlgorithmEnum,
 | 
				
			||||||
    FlowsInstancesListDesignationEnum,
 | 
					    FlowsInstancesListDesignationEnum,
 | 
				
			||||||
    GroupMatchingModeEnum,
 | 
					    GroupMatchingModeEnum,
 | 
				
			||||||
    NameIdPolicyEnum,
 | 
					    SAMLNameIDPolicyEnum,
 | 
				
			||||||
    SAMLSource,
 | 
					    SAMLSource,
 | 
				
			||||||
    SignatureAlgorithmEnum,
 | 
					    SignatureAlgorithmEnum,
 | 
				
			||||||
    SourcesApi,
 | 
					    SourcesApi,
 | 
				
			||||||
@ -89,14 +90,15 @@ export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSo
 | 
				
			|||||||
                    required
 | 
					                    required
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            </ak-form-element-horizontal>
 | 
				
			||||||
            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">
 | 
					
 | 
				
			||||||
                <input
 | 
					            <ak-slug-input
 | 
				
			||||||
                    type="text"
 | 
					                name="slug"
 | 
				
			||||||
                    value="${ifDefined(this.instance?.slug)}"
 | 
					                value=${ifDefined(this.instance?.slug)}
 | 
				
			||||||
                    class="pf-c-form-control"
 | 
					                label=${msg("Slug")}
 | 
				
			||||||
                required
 | 
					                required
 | 
				
			||||||
                />
 | 
					                input-hint="code"
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            ></ak-slug-input>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <ak-form-element-horizontal name="enabled">
 | 
					            <ak-form-element-horizontal name="enabled">
 | 
				
			||||||
                <label class="pf-c-switch">
 | 
					                <label class="pf-c-switch">
 | 
				
			||||||
                    <input
 | 
					                    <input
 | 
				
			||||||
@ -351,37 +353,37 @@ export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSo
 | 
				
			|||||||
                    >
 | 
					                    >
 | 
				
			||||||
                        <select class="pf-c-form-control">
 | 
					                        <select class="pf-c-form-control">
 | 
				
			||||||
                            <option
 | 
					                            <option
 | 
				
			||||||
                                value=${NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
 | 
					                                value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
 | 
				
			||||||
                                ?selected=${this.instance?.nameIdPolicy ===
 | 
					                                ?selected=${this.instance?.nameIdPolicy ===
 | 
				
			||||||
                                NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
 | 
					                                SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
                                ${msg("Persistent")}
 | 
					                                ${msg("Persistent")}
 | 
				
			||||||
                            </option>
 | 
					                            </option>
 | 
				
			||||||
                            <option
 | 
					                            <option
 | 
				
			||||||
                                value=${NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
 | 
					                                value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
 | 
				
			||||||
                                ?selected=${this.instance?.nameIdPolicy ===
 | 
					                                ?selected=${this.instance?.nameIdPolicy ===
 | 
				
			||||||
                                NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
 | 
					                                SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
                                ${msg("Email address")}
 | 
					                                ${msg("Email address")}
 | 
				
			||||||
                            </option>
 | 
					                            </option>
 | 
				
			||||||
                            <option
 | 
					                            <option
 | 
				
			||||||
                                value=${NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
 | 
					                                value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
 | 
				
			||||||
                                ?selected=${this.instance?.nameIdPolicy ===
 | 
					                                ?selected=${this.instance?.nameIdPolicy ===
 | 
				
			||||||
                                NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
 | 
					                                SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
                                ${msg("Windows")}
 | 
					                                ${msg("Windows")}
 | 
				
			||||||
                            </option>
 | 
					                            </option>
 | 
				
			||||||
                            <option
 | 
					                            <option
 | 
				
			||||||
                                value=${NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
 | 
					                                value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
 | 
				
			||||||
                                ?selected=${this.instance?.nameIdPolicy ===
 | 
					                                ?selected=${this.instance?.nameIdPolicy ===
 | 
				
			||||||
                                NameIdPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
 | 
					                                SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
                                ${msg("X509 Subject")}
 | 
					                                ${msg("X509 Subject")}
 | 
				
			||||||
                            </option>
 | 
					                            </option>
 | 
				
			||||||
                            <option
 | 
					                            <option
 | 
				
			||||||
                                value=${NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
 | 
					                                value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
 | 
				
			||||||
                                ?selected=${this.instance?.nameIdPolicy ===
 | 
					                                ?selected=${this.instance?.nameIdPolicy ===
 | 
				
			||||||
                                NameIdPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
 | 
					                                SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
 | 
				
			||||||
                            >
 | 
					                            >
 | 
				
			||||||
                                ${msg("Transient")}
 | 
					                                ${msg("Transient")}
 | 
				
			||||||
                            </option>
 | 
					                            </option>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
import { placeholderHelperText } from "@goauthentik/admin/helperText";
 | 
					import { placeholderHelperText } from "@goauthentik/admin/helperText";
 | 
				
			||||||
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
 | 
					import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm";
 | 
				
			||||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
 | 
					import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
 | 
				
			||||||
 | 
					import "@goauthentik/components/ak-slug-input.js";
 | 
				
			||||||
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
					import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
 | 
				
			||||||
import "@goauthentik/elements/forms/FormGroup";
 | 
					import "@goauthentik/elements/forms/FormGroup";
 | 
				
			||||||
import "@goauthentik/elements/forms/HorizontalFormElement";
 | 
					import "@goauthentik/elements/forms/HorizontalFormElement";
 | 
				
			||||||
@ -48,14 +49,15 @@ export class SCIMSourceForm extends BaseSourceForm<SCIMSource> {
 | 
				
			|||||||
                    required
 | 
					                    required
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            </ak-form-element-horizontal>
 | 
				
			||||||
            <ak-form-element-horizontal label=${msg("Slug")} required name="slug">
 | 
					
 | 
				
			||||||
                <input
 | 
					            <ak-slug-input
 | 
				
			||||||
                    type="text"
 | 
					                name="slug"
 | 
				
			||||||
                    value="${ifDefined(this.instance?.slug)}"
 | 
					                value=${ifDefined(this.instance?.slug)}
 | 
				
			||||||
                    class="pf-c-form-control"
 | 
					                label=${msg("Slug")}
 | 
				
			||||||
                required
 | 
					                required
 | 
				
			||||||
                />
 | 
					                input-hint="code"
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            ></ak-slug-input>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <ak-form-element-horizontal name="enabled">
 | 
					            <ak-form-element-horizontal name="enabled">
 | 
				
			||||||
                <div class="pf-c-check">
 | 
					                <div class="pf-c-check">
 | 
				
			||||||
                    <input
 | 
					                    <input
 | 
				
			||||||
 | 
				
			|||||||
@ -41,14 +41,27 @@ export class InvitationForm extends ModelForm<Invitation, string> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    renderForm(): TemplateResult {
 | 
					    renderForm(): TemplateResult {
 | 
				
			||||||
        return html` <ak-form-element-horizontal slugMode label=${msg("Name")} required name="name">
 | 
					        const checkSlug = (ev: InputEvent) => {
 | 
				
			||||||
 | 
					            if (ev && ev.target && ev.target instanceof HTMLInputElement) {
 | 
				
			||||||
 | 
					                ev.target.value = (ev.target.value ?? "").replace(/[^a-z0-9-]/g, "");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return html` <ak-form-element-horizontal label=${msg("Name")} required name="name">
 | 
				
			||||||
                <input
 | 
					                <input
 | 
				
			||||||
                    type="text"
 | 
					                    type="text"
 | 
				
			||||||
 | 
					                    id="admin-stages-invitation-name"
 | 
				
			||||||
                    value="${this.instance?.name || ""}"
 | 
					                    value="${this.instance?.name || ""}"
 | 
				
			||||||
                    class="pf-c-form-control"
 | 
					                    class="pf-c-form-control"
 | 
				
			||||||
                    required
 | 
					                    required
 | 
				
			||||||
 | 
					                    @input=${(ev: InputEvent) => checkSlug(ev)}
 | 
				
			||||||
                    data-ak-slug="true"
 | 
					                    data-ak-slug="true"
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
 | 
					                <p class="pf-c-form__helper-text">
 | 
				
			||||||
 | 
					                    ${msg(
 | 
				
			||||||
 | 
					                        "The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.",
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
 | 
					                </p>
 | 
				
			||||||
            </ak-form-element-horizontal>
 | 
					            </ak-form-element-horizontal>
 | 
				
			||||||
            <ak-form-element-horizontal label=${msg("Expires")} required name="expires">
 | 
					            <ak-form-element-horizontal label=${msg("Expires")} required name="expires">
 | 
				
			||||||
                <input
 | 
					                <input
 | 
				
			||||||
 | 
				
			|||||||
@ -1,21 +1,5 @@
 | 
				
			|||||||
import * as base64js from "base64-js";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import { msg } from "@lit/localize";
 | 
					import { msg } from "@lit/localize";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function b64enc(buf: Uint8Array): string {
 | 
					 | 
				
			||||||
    return base64js.fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function b64RawEnc(buf: Uint8Array): string {
 | 
					 | 
				
			||||||
    return base64js.fromByteArray(buf).replace(/\+/g, "-").replace(/\//g, "_");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function u8arr(input: string): Uint8Array {
 | 
					 | 
				
			||||||
    return Uint8Array.from(atob(input.replace(/_/g, "/").replace(/-/g, "+")), (c) =>
 | 
					 | 
				
			||||||
        c.charCodeAt(0),
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function checkWebAuthnSupport() {
 | 
					export function checkWebAuthnSupport() {
 | 
				
			||||||
    if ("credentials" in navigator) {
 | 
					    if ("credentials" in navigator) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
@ -25,121 +9,3 @@ export function checkWebAuthnSupport() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    throw new Error(msg("WebAuthn not supported by browser."));
 | 
					    throw new Error(msg("WebAuthn not supported by browser."));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Transforms items in the credentialCreateOptions generated on the server
 | 
					 | 
				
			||||||
 * into byte arrays expected by the navigator.credentials.create() call
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export function transformCredentialCreateOptions(
 | 
					 | 
				
			||||||
    credentialCreateOptions: PublicKeyCredentialCreationOptions,
 | 
					 | 
				
			||||||
    userId: string,
 | 
					 | 
				
			||||||
): PublicKeyCredentialCreationOptions {
 | 
					 | 
				
			||||||
    const user = credentialCreateOptions.user;
 | 
					 | 
				
			||||||
    // Because json can't contain raw bytes, the server base64-encodes the User ID
 | 
					 | 
				
			||||||
    // So to get the base64 encoded byte array, we first need to convert it to a regular
 | 
					 | 
				
			||||||
    // string, then a byte array, re-encode it and wrap that in an array.
 | 
					 | 
				
			||||||
    const stringId = decodeURIComponent(window.atob(userId));
 | 
					 | 
				
			||||||
    user.id = u8arr(b64enc(u8arr(stringId)));
 | 
					 | 
				
			||||||
    const challenge = u8arr(credentialCreateOptions.challenge.toString());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        ...credentialCreateOptions,
 | 
					 | 
				
			||||||
        challenge,
 | 
					 | 
				
			||||||
        user,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface Assertion {
 | 
					 | 
				
			||||||
    id: string;
 | 
					 | 
				
			||||||
    rawId: string;
 | 
					 | 
				
			||||||
    type: string;
 | 
					 | 
				
			||||||
    registrationClientExtensions: string;
 | 
					 | 
				
			||||||
    response: {
 | 
					 | 
				
			||||||
        clientDataJSON: string;
 | 
					 | 
				
			||||||
        attestationObject: string;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Transforms the binary data in the credential into base64 strings
 | 
					 | 
				
			||||||
 * for posting to the server.
 | 
					 | 
				
			||||||
 * @param {PublicKeyCredential} newAssertion
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export function transformNewAssertionForServer(newAssertion: PublicKeyCredential): Assertion {
 | 
					 | 
				
			||||||
    const attObj = new Uint8Array(
 | 
					 | 
				
			||||||
        (newAssertion.response as AuthenticatorAttestationResponse).attestationObject,
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    const clientDataJSON = new Uint8Array(newAssertion.response.clientDataJSON);
 | 
					 | 
				
			||||||
    const rawId = new Uint8Array(newAssertion.rawId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const registrationClientExtensions = newAssertion.getClientExtensionResults();
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        id: newAssertion.id,
 | 
					 | 
				
			||||||
        rawId: b64enc(rawId),
 | 
					 | 
				
			||||||
        type: newAssertion.type,
 | 
					 | 
				
			||||||
        registrationClientExtensions: JSON.stringify(registrationClientExtensions),
 | 
					 | 
				
			||||||
        response: {
 | 
					 | 
				
			||||||
            clientDataJSON: b64enc(clientDataJSON),
 | 
					 | 
				
			||||||
            attestationObject: b64enc(attObj),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export function transformCredentialRequestOptions(
 | 
					 | 
				
			||||||
    credentialRequestOptions: PublicKeyCredentialRequestOptions,
 | 
					 | 
				
			||||||
): PublicKeyCredentialRequestOptions {
 | 
					 | 
				
			||||||
    const challenge = u8arr(credentialRequestOptions.challenge.toString());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const allowCredentials = (credentialRequestOptions.allowCredentials || []).map(
 | 
					 | 
				
			||||||
        (credentialDescriptor) => {
 | 
					 | 
				
			||||||
            const id = u8arr(credentialDescriptor.id.toString());
 | 
					 | 
				
			||||||
            return Object.assign({}, credentialDescriptor, { id });
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        ...credentialRequestOptions,
 | 
					 | 
				
			||||||
        challenge,
 | 
					 | 
				
			||||||
        allowCredentials,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export interface AuthAssertion {
 | 
					 | 
				
			||||||
    id: string;
 | 
					 | 
				
			||||||
    rawId: string;
 | 
					 | 
				
			||||||
    type: string;
 | 
					 | 
				
			||||||
    assertionClientExtensions: string;
 | 
					 | 
				
			||||||
    response: {
 | 
					 | 
				
			||||||
        clientDataJSON: string;
 | 
					 | 
				
			||||||
        authenticatorData: string;
 | 
					 | 
				
			||||||
        signature: string;
 | 
					 | 
				
			||||||
        userHandle: string | null;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Encodes the binary data in the assertion into strings for posting to the server.
 | 
					 | 
				
			||||||
 * @param {PublicKeyCredential} newAssertion
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
export function transformAssertionForServer(newAssertion: PublicKeyCredential): AuthAssertion {
 | 
					 | 
				
			||||||
    const response = newAssertion.response as AuthenticatorAssertionResponse;
 | 
					 | 
				
			||||||
    const authData = new Uint8Array(response.authenticatorData);
 | 
					 | 
				
			||||||
    const clientDataJSON = new Uint8Array(response.clientDataJSON);
 | 
					 | 
				
			||||||
    const rawId = new Uint8Array(newAssertion.rawId);
 | 
					 | 
				
			||||||
    const sig = new Uint8Array(response.signature);
 | 
					 | 
				
			||||||
    const assertionClientExtensions = newAssertion.getClientExtensionResults();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        id: newAssertion.id,
 | 
					 | 
				
			||||||
        rawId: b64enc(rawId),
 | 
					 | 
				
			||||||
        type: newAssertion.type,
 | 
					 | 
				
			||||||
        assertionClientExtensions: JSON.stringify(assertionClientExtensions),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        response: {
 | 
					 | 
				
			||||||
            clientDataJSON: b64RawEnc(clientDataJSON),
 | 
					 | 
				
			||||||
            signature: b64RawEnc(sig),
 | 
					 | 
				
			||||||
            authenticatorData: b64RawEnc(authData),
 | 
					 | 
				
			||||||
            userHandle: null,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
import { me } from "@goauthentik/common/users.js";
 | 
					import { me } from "@goauthentik/common/users.js";
 | 
				
			||||||
import { isUserRoute } from "@goauthentik/elements/router/utils.js";
 | 
					import { isUserRoute } from "@goauthentik/elements/router/utils.js";
 | 
				
			||||||
 | 
					import { deepmerge, deepmergeInto } from "deepmerge-ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { UiThemeEnum, UserSelf } from "@goauthentik/api";
 | 
					import { UiThemeEnum, UserSelf } from "@goauthentik/api";
 | 
				
			||||||
import { CurrentBrand } from "@goauthentik/api";
 | 
					import { CurrentBrand } from "@goauthentik/api";
 | 
				
			||||||
@ -96,13 +97,12 @@ export class DefaultUIConfig implements UIConfig {
 | 
				
			|||||||
let globalUiConfig: Promise<UIConfig>;
 | 
					let globalUiConfig: Promise<UIConfig>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function getConfigForUser(user: UserSelf): UIConfig {
 | 
					export function getConfigForUser(user: UserSelf): UIConfig {
 | 
				
			||||||
    const settings = user.settings;
 | 
					    const settings = user.settings as UIConfig;
 | 
				
			||||||
    let config = new DefaultUIConfig();
 | 
					    const config = new DefaultUIConfig();
 | 
				
			||||||
    if (!settings) {
 | 
					    if (!settings) {
 | 
				
			||||||
        return config;
 | 
					        return config;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    config = Object.assign(new DefaultUIConfig(), settings);
 | 
					    return deepmerge({ ...config }, settings);
 | 
				
			||||||
    return config;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function uiConfig(): Promise<UIConfig> {
 | 
					export function uiConfig(): Promise<UIConfig> {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
import { formatSlug } from "@goauthentik/elements/router/utils.js";
 | 
					import { bound } from "@goauthentik/elements/decorators/bound.js";
 | 
				
			||||||
 | 
					import { kebabCase } from "change-case";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { html } from "lit";
 | 
					import { html } from "lit";
 | 
				
			||||||
import { customElement, property, query } from "lit/decorators.js";
 | 
					import { customElement, property, query } from "lit/decorators.js";
 | 
				
			||||||
@ -6,59 +7,83 @@ import { ifDefined } from "lit/directives/if-defined.js";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import { HorizontalLightComponent } from "./HorizontalLightComponent";
 | 
					import { HorizontalLightComponent } from "./HorizontalLightComponent";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const slugify = (s: string) => kebabCase(s, { suffixCharacters: "-" });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @element ak-slug-input
 | 
				
			||||||
 | 
					 * @class AkSlugInput
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * A wrapper around `ak-form-element-horizontal` and a text input control that listens for input on
 | 
				
			||||||
 | 
					 * a peer text input control and automatically mirrors that control's value, transforming the value
 | 
				
			||||||
 | 
					 * into a slug and displaying it separately.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the user manually changes the slug, mirroring and transformation stop. If, after that, both
 | 
				
			||||||
 | 
					 * fields are cleared manually, mirroring and transformation resume.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * ## Limitations:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Both the source text field and the slug field must be rendered in the same render pass (i.e.,
 | 
				
			||||||
 | 
					 * part of the same singular call to a `render` function) so that the slug field can find its
 | 
				
			||||||
 | 
					 * source.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * For the same reason, both the source text field and the slug field must share the same immediate
 | 
				
			||||||
 | 
					 * parent DOM object.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Since we expect the source text field and the slug to be part of the same form and rendered not
 | 
				
			||||||
 | 
					 * just in the same form but in the same form group, these are not considered burdensome
 | 
				
			||||||
 | 
					 * restrictions.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
@customElement("ak-slug-input")
 | 
					@customElement("ak-slug-input")
 | 
				
			||||||
export class AkSlugInput extends HorizontalLightComponent<string> {
 | 
					export class AkSlugInput extends HorizontalLightComponent<string> {
 | 
				
			||||||
    @property({ type: String, reflect: true })
 | 
					    /**
 | 
				
			||||||
    value = "";
 | 
					     * A selector indicating the source text input control. Must be unique within the whole DOM
 | 
				
			||||||
 | 
					     * context of the slug and source controls. The most common use in authentik is the default:
 | 
				
			||||||
 | 
					     * slugifying the "name" of something.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    @property({ type: String })
 | 
					    @property({ type: String })
 | 
				
			||||||
    source = "";
 | 
					    public source = "[name='name']";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    origin?: HTMLInputElement | null;
 | 
					    @property({ type: String, reflect: true })
 | 
				
			||||||
 | 
					    public value = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @query("input")
 | 
					    @query("input")
 | 
				
			||||||
    input!: HTMLInputElement;
 | 
					    private input!: HTMLInputElement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    touched: boolean = false;
 | 
					    #origin?: HTMLInputElement | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor() {
 | 
					    #touched: boolean = false;
 | 
				
			||||||
        super();
 | 
					 | 
				
			||||||
        this.slugify = this.slugify.bind(this);
 | 
					 | 
				
			||||||
        this.handleTouch = this.handleTouch.bind(this);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    firstUpdated() {
 | 
					 | 
				
			||||||
        this.input.addEventListener("input", this.handleTouch);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Do not stop propagation of this event; it must be sent up the tree so that a parent
 | 
					    // Do not stop propagation of this event; it must be sent up the tree so that a parent
 | 
				
			||||||
    // component, such as a custom forms manager, may receive it.
 | 
					    // component, such as a custom forms manager, may receive it.
 | 
				
			||||||
    handleTouch(ev: Event) {
 | 
					    protected handleTouch(ev: Event) {
 | 
				
			||||||
        this.input.value = formatSlug(this.input.value);
 | 
					        this.value = this.input.value = slugify(this.input.value);
 | 
				
			||||||
        this.value = this.input.value;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.origin && this.origin.value === "" && this.input.value === "") {
 | 
					        // Reset 'touched' status if the slug & target have been reset
 | 
				
			||||||
            this.touched = false;
 | 
					        if (this.#origin && this.#origin.value === "" && this.input.value === "") {
 | 
				
			||||||
 | 
					            this.#touched = false;
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (ev && ev.target && ev.target instanceof HTMLInputElement) {
 | 
					        if (ev && ev.target && ev.target instanceof HTMLInputElement) {
 | 
				
			||||||
            this.touched = true;
 | 
					            this.#touched = true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    slugify(ev: Event) {
 | 
					    @bound
 | 
				
			||||||
 | 
					    protected slugify(ev: Event) {
 | 
				
			||||||
        if (!(ev && ev.target && ev.target instanceof HTMLInputElement)) {
 | 
					        if (!(ev && ev.target && ev.target instanceof HTMLInputElement)) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Reset 'touched' status if the slug & target have been reset
 | 
					        // Reset 'touched' status if the slug & target have been reset
 | 
				
			||||||
        if (ev.target.value === "" && this.input.value === "") {
 | 
					        if (ev.target.value === "" && this.input.value === "") {
 | 
				
			||||||
            this.touched = false;
 | 
					            this.#touched = false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Don't proceed if the user has hand-modified the slug
 | 
					        // Don't proceed if the user has hand-modified the slug. (Note the order of statements: if
 | 
				
			||||||
        if (this.touched) {
 | 
					        // the user hand modified the slug to be empty as part of resetting the slug/source
 | 
				
			||||||
 | 
					        // relationship, that's a "not-touched" condition and falls through.)
 | 
				
			||||||
 | 
					        if (this.#touched) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -67,7 +92,7 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
 | 
				
			|||||||
        // "any event which adds or removes a character but leaves the rest of the slug looking like
 | 
					        // "any event which adds or removes a character but leaves the rest of the slug looking like
 | 
				
			||||||
        // the previous iteration, set it to the current iteration."
 | 
					        // the previous iteration, set it to the current iteration."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const newSlug = formatSlug(ev.target.value);
 | 
					        const newSlug = slugify(ev.target.value);
 | 
				
			||||||
        const oldSlug = this.input.value;
 | 
					        const oldSlug = this.input.value;
 | 
				
			||||||
        const [shorter, longer] =
 | 
					        const [shorter, longer] =
 | 
				
			||||||
            newSlug.length < oldSlug.length ? [newSlug, oldSlug] : [oldSlug, newSlug];
 | 
					            newSlug.length < oldSlug.length ? [newSlug, oldSlug] : [oldSlug, newSlug];
 | 
				
			||||||
@ -81,7 +106,6 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
 | 
				
			|||||||
        // to listeners, both the name and value of the host must match those of the target
 | 
					        // to listeners, both the name and value of the host must match those of the target
 | 
				
			||||||
        // input. The name is already handled since it's both required and automatically
 | 
					        // input. The name is already handled since it's both required and automatically
 | 
				
			||||||
        // forwarded to our templated input, but the value must also be set.
 | 
					        // forwarded to our templated input, but the value must also be set.
 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.value = this.input.value = newSlug;
 | 
					        this.value = this.input.value = newSlug;
 | 
				
			||||||
        this.dispatchEvent(
 | 
					        this.dispatchEvent(
 | 
				
			||||||
            new Event("input", {
 | 
					            new Event("input", {
 | 
				
			||||||
@ -91,38 +115,36 @@ export class AkSlugInput extends HorizontalLightComponent<string> {
 | 
				
			|||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    connectedCallback() {
 | 
					    public override disconnectedCallback() {
 | 
				
			||||||
        super.connectedCallback();
 | 
					        if (this.#origin) {
 | 
				
			||||||
 | 
					            this.#origin.removeEventListener("input", this.slugify);
 | 
				
			||||||
        // Set up listener on source element, so we can slugify the content.
 | 
					 | 
				
			||||||
        setTimeout(() => {
 | 
					 | 
				
			||||||
            if (this.source) {
 | 
					 | 
				
			||||||
                const rootNode = this.getRootNode();
 | 
					 | 
				
			||||||
                if (rootNode instanceof ShadowRoot || rootNode instanceof Document) {
 | 
					 | 
				
			||||||
                    this.origin = rootNode.querySelector(this.source);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if (this.origin) {
 | 
					 | 
				
			||||||
                    this.origin.addEventListener("input", this.slugify);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }, 0);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    disconnectedCallback() {
 | 
					 | 
				
			||||||
        if (this.origin) {
 | 
					 | 
				
			||||||
            this.origin.removeEventListener("input", this.slugify);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        super.disconnectedCallback();
 | 
					        super.disconnectedCallback();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    renderControl() {
 | 
					    public override renderControl() {
 | 
				
			||||||
        return html`<input
 | 
					        return html`<input
 | 
				
			||||||
 | 
					            @input=${(ev: Event) => this.handleTouch(ev)}
 | 
				
			||||||
            type="text"
 | 
					            type="text"
 | 
				
			||||||
            value=${ifDefined(this.value)}
 | 
					            value=${ifDefined(this.value)}
 | 
				
			||||||
            class="pf-c-form-control"
 | 
					            class="pf-c-form-control"
 | 
				
			||||||
            ?required=${this.required}
 | 
					            ?required=${this.required}
 | 
				
			||||||
        />`;
 | 
					        />`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public override firstUpdated() {
 | 
				
			||||||
 | 
					        if (!this.source) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const rootNode = this.getRootNode();
 | 
				
			||||||
 | 
					        if (rootNode instanceof ShadowRoot || rootNode instanceof Document) {
 | 
				
			||||||
 | 
					            this.#origin = rootNode.querySelector(this.source);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (this.#origin) {
 | 
				
			||||||
 | 
					            this.#origin.addEventListener("input", this.slugify);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default AkSlugInput;
 | 
					export default AkSlugInput;
 | 
				
			||||||
 | 
				
			|||||||
@ -94,7 +94,8 @@ export class ObjectChangelog extends Table<Event> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    renderEmpty(): TemplateResult {
 | 
					    renderEmpty(): TemplateResult {
 | 
				
			||||||
        return super.renderEmpty(
 | 
					        return super.renderEmpty(
 | 
				
			||||||
            html`<ak-empty-state header=${msg("No Events found.")}>
 | 
					            html`<ak-empty-state
 | 
				
			||||||
 | 
					                ><span slot="header">${msg("No Events found.")}</span>
 | 
				
			||||||
                <div slot="body">${msg("No matching events could be found.")}</div>
 | 
					                <div slot="body">${msg("No matching events could be found.")}</div>
 | 
				
			||||||
            </ak-empty-state>`,
 | 
					            </ak-empty-state>`,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
				
			|||||||
@ -66,7 +66,8 @@ export class UserEvents extends Table<Event> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    renderEmpty(): TemplateResult {
 | 
					    renderEmpty(): TemplateResult {
 | 
				
			||||||
        return super.renderEmpty(
 | 
					        return super.renderEmpty(
 | 
				
			||||||
            html`<ak-empty-state header=${msg("No Events found.")}>
 | 
					            html`<ak-empty-state
 | 
				
			||||||
 | 
					                ><span slot="header">${msg("No Events found.")}</span>
 | 
				
			||||||
                <div slot="body">${msg("No matching events could be found.")}</div>
 | 
					                <div slot="body">${msg("No matching events could be found.")}</div>
 | 
				
			||||||
            </ak-empty-state>`,
 | 
					            </ak-empty-state>`,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ import { AKElement } from "@goauthentik/elements/Base";
 | 
				
			|||||||
import "@goauthentik/elements/Spinner";
 | 
					import "@goauthentik/elements/Spinner";
 | 
				
			||||||
import { type SlottedTemplateResult, type Spread } from "@goauthentik/elements/types";
 | 
					import { type SlottedTemplateResult, type Spread } from "@goauthentik/elements/types";
 | 
				
			||||||
import { spread } from "@open-wc/lit-helpers";
 | 
					import { spread } from "@open-wc/lit-helpers";
 | 
				
			||||||
 | 
					import { SlotController } from "@patternfly/pfe-core/controllers/slot-controller.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { msg } from "@lit/localize";
 | 
					import { msg } from "@lit/localize";
 | 
				
			||||||
import { css, html, nothing } from "lit";
 | 
					import { css, html, nothing } from "lit";
 | 
				
			||||||
@ -33,6 +34,8 @@ export class EmptyState extends AKElement implements IEmptyState {
 | 
				
			|||||||
    @property()
 | 
					    @property()
 | 
				
			||||||
    header?: string;
 | 
					    header?: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    slots = new SlotController(this, "header", "body", "primary");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static get styles() {
 | 
					    static get styles() {
 | 
				
			||||||
        return [
 | 
					        return [
 | 
				
			||||||
            PFBase,
 | 
					            PFBase,
 | 
				
			||||||
@ -48,6 +51,12 @@ export class EmptyState extends AKElement implements IEmptyState {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render() {
 | 
					    render() {
 | 
				
			||||||
 | 
					        const showHeader = this.loading || this.slots.hasSlotted("header");
 | 
				
			||||||
 | 
					        const header = () =>
 | 
				
			||||||
 | 
					            this.slots.hasSlotted("header")
 | 
				
			||||||
 | 
					                ? html`<slot name="header"></slot>`
 | 
				
			||||||
 | 
					                : html`<span>${msg("Loading")}</span>`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return html`<div class="pf-c-empty-state ${this.fullHeight && "pf-m-full-height"}">
 | 
					        return html`<div class="pf-c-empty-state ${this.fullHeight && "pf-m-full-height"}">
 | 
				
			||||||
            <div class="pf-c-empty-state__content">
 | 
					            <div class="pf-c-empty-state__content">
 | 
				
			||||||
                ${this.loading
 | 
					                ${this.loading
 | 
				
			||||||
@ -59,15 +68,17 @@ export class EmptyState extends AKElement implements IEmptyState {
 | 
				
			|||||||
                          "fa-question-circle"} pf-c-empty-state__icon"
 | 
					                          "fa-question-circle"} pf-c-empty-state__icon"
 | 
				
			||||||
                          aria-hidden="true"
 | 
					                          aria-hidden="true"
 | 
				
			||||||
                      ></i>`}
 | 
					                      ></i>`}
 | 
				
			||||||
                <h1 class="pf-c-title pf-m-lg">
 | 
					                ${showHeader ? html` <h1 class="pf-c-title pf-m-lg">${header()}</h1>` : nothing}
 | 
				
			||||||
                    ${this.loading && this.header === undefined ? msg("Loading") : this.header}
 | 
					                ${this.slots.hasSlotted("body")
 | 
				
			||||||
                </h1>
 | 
					                    ? html` <div class="pf-c-empty-state__body">
 | 
				
			||||||
                <div class="pf-c-empty-state__body">
 | 
					 | 
				
			||||||
                          <slot name="body"></slot>
 | 
					                          <slot name="body"></slot>
 | 
				
			||||||
                </div>
 | 
					                      </div>`
 | 
				
			||||||
                <div class="pf-c-empty-state__primary">
 | 
					                    : nothing}
 | 
				
			||||||
 | 
					                ${this.slots.hasSlotted("primary")
 | 
				
			||||||
 | 
					                    ? html` <div class="pf-c-empty-state__primary">
 | 
				
			||||||
                          <slot name="primary"></slot>
 | 
					                          <slot name="primary"></slot>
 | 
				
			||||||
                </div>
 | 
					                      </div>`
 | 
				
			||||||
 | 
					                    : nothing}
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </div>`;
 | 
					        </div>`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -200,7 +200,8 @@ export abstract class AKChart<T> extends AKElement {
 | 
				
			|||||||
            <div class="container">
 | 
					            <div class="container">
 | 
				
			||||||
                ${this.error
 | 
					                ${this.error
 | 
				
			||||||
                    ? html`
 | 
					                    ? html`
 | 
				
			||||||
                          <ak-empty-state header="${msg("Failed to fetch data.")}" icon="fa-times">
 | 
					                          <ak-empty-state icon="fa-times"
 | 
				
			||||||
 | 
					                              ><span slot="header">${msg("Failed to fetch data.")}</span>
 | 
				
			||||||
                              <p slot="body">${pluckErrorDetail(this.error)}</p>
 | 
					                              <p slot="body">${pluckErrorDetail(this.error)}</p>
 | 
				
			||||||
                          </ak-empty-state>
 | 
					                          </ak-empty-state>
 | 
				
			||||||
                      `
 | 
					                      `
 | 
				
			||||||
 | 
				
			|||||||
@ -40,7 +40,9 @@ export class LogViewer extends Table<LogEvent> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    renderEmpty(): TemplateResult {
 | 
					    renderEmpty(): TemplateResult {
 | 
				
			||||||
        return super.renderEmpty(
 | 
					        return super.renderEmpty(
 | 
				
			||||||
            html`<ak-empty-state header=${msg("No log messages.")}> </ak-empty-state>`,
 | 
					            html`<ak-empty-state
 | 
				
			||||||
 | 
					                ><span slot="header">${msg("No log messages.")}</span>
 | 
				
			||||||
 | 
					            </ak-empty-state>`,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,6 @@ import { AKElement } from "@goauthentik/elements/Base";
 | 
				
			|||||||
import { HorizontalFormElement } from "@goauthentik/elements/forms/HorizontalFormElement";
 | 
					import { HorizontalFormElement } from "@goauthentik/elements/forms/HorizontalFormElement";
 | 
				
			||||||
import { PreventFormSubmit } from "@goauthentik/elements/forms/helpers";
 | 
					import { PreventFormSubmit } from "@goauthentik/elements/forms/helpers";
 | 
				
			||||||
import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
 | 
					import { showMessage } from "@goauthentik/elements/messages/MessageContainer";
 | 
				
			||||||
import { formatSlug } from "@goauthentik/elements/router/utils.js";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { msg } from "@lit/localize";
 | 
					import { msg } from "@lit/localize";
 | 
				
			||||||
import { CSSResult, TemplateResult, css, html } from "lit";
 | 
					import { CSSResult, TemplateResult, css, html } from "lit";
 | 
				
			||||||
@ -197,39 +196,6 @@ export abstract class Form<T> extends AKElement {
 | 
				
			|||||||
        return this.successMessage;
 | 
					        return this.successMessage;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * After rendering the form, if there is both a `name` and `slug` element within the form,
 | 
					 | 
				
			||||||
     * events the `name` element so that the slug will always have a slugified version of the
 | 
					 | 
				
			||||||
     * `name.`. This duplicates functionality within ak-form-element-horizontal.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    updated(): void {
 | 
					 | 
				
			||||||
        this.shadowRoot
 | 
					 | 
				
			||||||
            ?.querySelectorAll("ak-form-element-horizontal[name=name]")
 | 
					 | 
				
			||||||
            .forEach((nameInput) => {
 | 
					 | 
				
			||||||
                const input = nameInput.firstElementChild as HTMLInputElement;
 | 
					 | 
				
			||||||
                const form = nameInput.closest("form");
 | 
					 | 
				
			||||||
                if (form === null) {
 | 
					 | 
				
			||||||
                    return;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                const slugFieldWrapper = form.querySelector(
 | 
					 | 
				
			||||||
                    "ak-form-element-horizontal[name=slug]",
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                if (!slugFieldWrapper) {
 | 
					 | 
				
			||||||
                    return;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                const slugField = slugFieldWrapper.firstElementChild as HTMLInputElement;
 | 
					 | 
				
			||||||
                // Only attach handler if the slug is already equal to the name
 | 
					 | 
				
			||||||
                // if not, they are probably completely different and shouldn't update
 | 
					 | 
				
			||||||
                // each other
 | 
					 | 
				
			||||||
                if (formatSlug(input.value) !== slugField.value) {
 | 
					 | 
				
			||||||
                    return;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                nameInput.addEventListener("input", () => {
 | 
					 | 
				
			||||||
                    slugField.value = formatSlug(input.value);
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    resetForm(): void {
 | 
					    resetForm(): void {
 | 
				
			||||||
        const form = this.shadowRoot?.querySelector<HTMLFormElement>("form");
 | 
					        const form = this.shadowRoot?.querySelector<HTMLFormElement>("form");
 | 
				
			||||||
        form?.reset();
 | 
					        form?.reset();
 | 
				
			||||||
 | 
				
			|||||||
@ -77,9 +77,6 @@ export class HorizontalFormElement extends AKElement {
 | 
				
			|||||||
    @property({ attribute: false })
 | 
					    @property({ attribute: false })
 | 
				
			||||||
    errorMessages: string[] | string[][] = [];
 | 
					    errorMessages: string[] | string[][] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property({ type: Boolean })
 | 
					 | 
				
			||||||
    slugMode = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _invalid = false;
 | 
					    _invalid = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* If this property changes, we want to make sure the parent control is "opened" so
 | 
					    /* If this property changes, we want to make sure the parent control is "opened" so
 | 
				
			||||||
@ -109,13 +106,6 @@ export class HorizontalFormElement extends AKElement {
 | 
				
			|||||||
        this.querySelectorAll<HTMLInputElement>("input[autofocus]").forEach((input) => {
 | 
					        this.querySelectorAll<HTMLInputElement>("input[autofocus]").forEach((input) => {
 | 
				
			||||||
            input.focus();
 | 
					            input.focus();
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        if (this.name === "slug" || this.slugMode) {
 | 
					 | 
				
			||||||
            this.querySelectorAll<HTMLInputElement>("input[type='text']").forEach((input) => {
 | 
					 | 
				
			||||||
                input.addEventListener("keyup", () => {
 | 
					 | 
				
			||||||
                    input.value = formatSlug(input.value);
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.querySelectorAll("*").forEach((input) => {
 | 
					        this.querySelectorAll("*").forEach((input) => {
 | 
				
			||||||
            if (isAkControl(input) && !input.getAttribute("name")) {
 | 
					            if (isAkControl(input) && !input.getAttribute("name")) {
 | 
				
			||||||
                input.setAttribute("name", this.name);
 | 
					                input.setAttribute("name", this.name);
 | 
				
			||||||
 | 
				
			|||||||
@ -163,7 +163,8 @@ export class NotificationDrawer extends AKElement {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    renderEmpty() {
 | 
					    renderEmpty() {
 | 
				
			||||||
        return html`<ak-empty-state header=${msg("No notifications found.")}>
 | 
					        return html`<ak-empty-state
 | 
				
			||||||
 | 
					            ><span slot="header">${msg("No notifications found.")}</span>
 | 
				
			||||||
            <div slot="body">${msg("You don't have any notifications currently.")}</div>
 | 
					            <div slot="body">${msg("You don't have any notifications currently.")}</div>
 | 
				
			||||||
        </ak-empty-state>`;
 | 
					        </ak-empty-state>`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -288,7 +288,9 @@ export abstract class Table<T> extends AKElement implements TableLike {
 | 
				
			|||||||
        return html`<tr role="row">
 | 
					        return html`<tr role="row">
 | 
				
			||||||
            <td role="cell" colspan="25">
 | 
					            <td role="cell" colspan="25">
 | 
				
			||||||
                <div class="pf-l-bullseye">
 | 
					                <div class="pf-l-bullseye">
 | 
				
			||||||
                    <ak-empty-state loading header=${msg("Loading")}></ak-empty-state>
 | 
					                    <ak-empty-state loading
 | 
				
			||||||
 | 
					                        ><span slot="header">${msg("Loading")}</span></ak-empty-state
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
        </tr>`;
 | 
					        </tr>`;
 | 
				
			||||||
@ -300,8 +302,9 @@ export abstract class Table<T> extends AKElement implements TableLike {
 | 
				
			|||||||
                <td role="cell" colspan="8">
 | 
					                <td role="cell" colspan="8">
 | 
				
			||||||
                    <div class="pf-l-bullseye">
 | 
					                    <div class="pf-l-bullseye">
 | 
				
			||||||
                        ${inner ??
 | 
					                        ${inner ??
 | 
				
			||||||
                        html`<ak-empty-state header="${msg("No objects found.")}"
 | 
					                        html`<ak-empty-state
 | 
				
			||||||
                            ><div slot="primary">${this.renderObjectCreate()}</div>
 | 
					                            ><span slot="header">${msg("No objects found.")}</span> >
 | 
				
			||||||
 | 
					                            <div slot="primary">${this.renderObjectCreate()}</div>
 | 
				
			||||||
                        </ak-empty-state>`}
 | 
					                        </ak-empty-state>`}
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </td>
 | 
					                </td>
 | 
				
			||||||
@ -316,7 +319,8 @@ export abstract class Table<T> extends AKElement implements TableLike {
 | 
				
			|||||||
    renderError(): SlottedTemplateResult {
 | 
					    renderError(): SlottedTemplateResult {
 | 
				
			||||||
        if (!this.error) return nothing;
 | 
					        if (!this.error) return nothing;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return html`<ak-empty-state header="${msg("Failed to fetch objects.")}" icon="fa-ban">
 | 
					        return html`<ak-empty-state icon="fa-ban"
 | 
				
			||||||
 | 
					            ><span slot="header">${msg("Failed to fetch objects.")}</span>
 | 
				
			||||||
            <div slot="body">${pluckErrorDetail(this.error)}</div>
 | 
					            <div slot="body">${pluckErrorDetail(this.error)}</div>
 | 
				
			||||||
        </ak-empty-state>`;
 | 
					        </ak-empty-state>`;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,11 @@ describe("ak-empty-state", () => {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it("should render the default loader", async () => {
 | 
					    it("should render the default loader", async () => {
 | 
				
			||||||
        render(html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`);
 | 
					        render(
 | 
				
			||||||
 | 
					            html`<ak-empty-state loading
 | 
				
			||||||
 | 
					                ><span slot="header">${msg("Loading")}</span>
 | 
				
			||||||
 | 
					            </ak-empty-state>`,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
 | 
					        const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
 | 
				
			||||||
        await expect(empty).toExist();
 | 
					        await expect(empty).toExist();
 | 
				
			||||||
@ -29,7 +33,11 @@ describe("ak-empty-state", () => {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it("should handle standard boolean", async () => {
 | 
					    it("should handle standard boolean", async () => {
 | 
				
			||||||
        render(html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`);
 | 
					        render(
 | 
				
			||||||
 | 
					            html`<ak-empty-state loading
 | 
				
			||||||
 | 
					                ><span slot="header">${msg("Loading")}</span>
 | 
				
			||||||
 | 
					            </ak-empty-state>`,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
 | 
					        const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
 | 
				
			||||||
        await expect(empty).toExist();
 | 
					        await expect(empty).toExist();
 | 
				
			||||||
@ -39,7 +47,11 @@ describe("ak-empty-state", () => {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it("should render a static empty state", async () => {
 | 
					    it("should render a static empty state", async () => {
 | 
				
			||||||
        render(html`<ak-empty-state header=${msg("No messages found")}> </ak-empty-state>`);
 | 
					        render(
 | 
				
			||||||
 | 
					            html`<ak-empty-state
 | 
				
			||||||
 | 
					                ><span slot="header">${msg("No messages found")}</span>
 | 
				
			||||||
 | 
					            </ak-empty-state>`,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
 | 
					        const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
 | 
				
			||||||
        await expect(empty).toExist();
 | 
					        await expect(empty).toExist();
 | 
				
			||||||
@ -51,7 +63,8 @@ describe("ak-empty-state", () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    it("should render a slotted message", async () => {
 | 
					    it("should render a slotted message", async () => {
 | 
				
			||||||
        render(
 | 
					        render(
 | 
				
			||||||
            html`<ak-empty-state header=${msg("No messages found")}>
 | 
					            html`<ak-empty-state
 | 
				
			||||||
 | 
					                ><span slot="header">${msg("No messages found")}</span>
 | 
				
			||||||
                <p slot="body">Try again with a different filter</p>
 | 
					                <p slot="body">Try again with a different filter</p>
 | 
				
			||||||
            </ak-empty-state>`,
 | 
					            </ak-empty-state>`,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,4 @@
 | 
				
			|||||||
import {
 | 
					import { checkWebAuthnSupport } from "@goauthentik/common/helpers/webauthn";
 | 
				
			||||||
    checkWebAuthnSupport,
 | 
					 | 
				
			||||||
    transformAssertionForServer,
 | 
					 | 
				
			||||||
    transformCredentialRequestOptions,
 | 
					 | 
				
			||||||
} from "@goauthentik/common/helpers/webauthn";
 | 
					 | 
				
			||||||
import "@goauthentik/elements/EmptyState";
 | 
					import "@goauthentik/elements/EmptyState";
 | 
				
			||||||
import { BaseDeviceStage } from "@goauthentik/flow/stages/authenticator_validate/base";
 | 
					import { BaseDeviceStage } from "@goauthentik/flow/stages/authenticator_validate/base";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -38,12 +34,12 @@ export class AuthenticatorValidateStageWebAuthn extends BaseDeviceStage<
 | 
				
			|||||||
    async authenticate(): Promise<void> {
 | 
					    async authenticate(): Promise<void> {
 | 
				
			||||||
        // request the authenticator to create an assertion signature using the
 | 
					        // request the authenticator to create an assertion signature using the
 | 
				
			||||||
        // credential private key
 | 
					        // credential private key
 | 
				
			||||||
        let assertion;
 | 
					        let assertion: PublicKeyCredential;
 | 
				
			||||||
        checkWebAuthnSupport();
 | 
					        checkWebAuthnSupport();
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            assertion = await navigator.credentials.get({
 | 
					            assertion = (await navigator.credentials.get({
 | 
				
			||||||
                publicKey: this.transformedCredentialRequestOptions,
 | 
					                publicKey: this.transformedCredentialRequestOptions,
 | 
				
			||||||
            });
 | 
					            })) as PublicKeyCredential;
 | 
				
			||||||
            if (!assertion) {
 | 
					            if (!assertion) {
 | 
				
			||||||
                throw new Error("Assertions is empty");
 | 
					                throw new Error("Assertions is empty");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -51,17 +47,11 @@ export class AuthenticatorValidateStageWebAuthn extends BaseDeviceStage<
 | 
				
			|||||||
            throw new Error(`Error when creating credential: ${err}`);
 | 
					            throw new Error(`Error when creating credential: ${err}`);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // we now have an authentication assertion! encode the byte arrays contained
 | 
					 | 
				
			||||||
        // in the assertion data as strings for posting to the server
 | 
					 | 
				
			||||||
        const transformedAssertionForServer = transformAssertionForServer(
 | 
					 | 
				
			||||||
            assertion as PublicKeyCredential,
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // post the assertion to the server for verification.
 | 
					        // post the assertion to the server for verification.
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            await this.host?.submit(
 | 
					            await this.host?.submit(
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    webauthn: transformedAssertionForServer,
 | 
					                    webauthn: assertion.toJSON(),
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    invisible: true,
 | 
					                    invisible: true,
 | 
				
			||||||
@ -74,12 +64,10 @@ export class AuthenticatorValidateStageWebAuthn extends BaseDeviceStage<
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    updated(changedProperties: PropertyValues<this>) {
 | 
					    updated(changedProperties: PropertyValues<this>) {
 | 
				
			||||||
        if (changedProperties.has("challenge") && this.challenge !== undefined) {
 | 
					        if (changedProperties.has("challenge") && this.challenge !== undefined) {
 | 
				
			||||||
            // convert certain members of the PublicKeyCredentialRequestOptions into
 | 
					 | 
				
			||||||
            // byte arrays as expected by the spec.
 | 
					 | 
				
			||||||
            const credentialRequestOptions = this.deviceChallenge
 | 
					            const credentialRequestOptions = this.deviceChallenge
 | 
				
			||||||
                ?.challenge as PublicKeyCredentialRequestOptions;
 | 
					                ?.challenge as unknown as PublicKeyCredentialRequestOptionsJSON;
 | 
				
			||||||
            this.transformedCredentialRequestOptions =
 | 
					            this.transformedCredentialRequestOptions =
 | 
				
			||||||
                transformCredentialRequestOptions(credentialRequestOptions);
 | 
					                PublicKeyCredential.parseRequestOptionsFromJSON(credentialRequestOptions);
 | 
				
			||||||
            this.authenticateWrapper();
 | 
					            this.authenticateWrapper();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,4 @@
 | 
				
			|||||||
import {
 | 
					import { checkWebAuthnSupport } from "@goauthentik/common/helpers/webauthn";
 | 
				
			||||||
    Assertion,
 | 
					 | 
				
			||||||
    checkWebAuthnSupport,
 | 
					 | 
				
			||||||
    transformCredentialCreateOptions,
 | 
					 | 
				
			||||||
    transformNewAssertionForServer,
 | 
					 | 
				
			||||||
} from "@goauthentik/common/helpers/webauthn";
 | 
					 | 
				
			||||||
import "@goauthentik/elements/EmptyState";
 | 
					import "@goauthentik/elements/EmptyState";
 | 
				
			||||||
import { BaseStage } from "@goauthentik/flow/stages/base";
 | 
					import { BaseStage } from "@goauthentik/flow/stages/base";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -24,10 +19,6 @@ import {
 | 
				
			|||||||
    AuthenticatorWebAuthnChallengeResponseRequest,
 | 
					    AuthenticatorWebAuthnChallengeResponseRequest,
 | 
				
			||||||
} from "@goauthentik/api";
 | 
					} from "@goauthentik/api";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface WebAuthnAuthenticatorRegisterChallengeResponse {
 | 
					 | 
				
			||||||
    response: Assertion;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@customElement("ak-stage-authenticator-webauthn")
 | 
					@customElement("ak-stage-authenticator-webauthn")
 | 
				
			||||||
export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
 | 
					export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
 | 
				
			||||||
    AuthenticatorWebAuthnChallenge,
 | 
					    AuthenticatorWebAuthnChallenge,
 | 
				
			||||||
@ -68,7 +59,7 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        checkWebAuthnSupport();
 | 
					        checkWebAuthnSupport();
 | 
				
			||||||
        // request the authenticator(s) to create a new credential keypair.
 | 
					        // request the authenticator(s) to create a new credential keypair.
 | 
				
			||||||
        let credential;
 | 
					        let credential: PublicKeyCredential;
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            credential = (await navigator.credentials.create({
 | 
					            credential = (await navigator.credentials.create({
 | 
				
			||||||
                publicKey: this.publicKeyCredentialCreateOptions,
 | 
					                publicKey: this.publicKeyCredentialCreateOptions,
 | 
				
			||||||
@ -80,16 +71,12 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
 | 
				
			|||||||
            throw new Error(msg(str`Error creating credential: ${err}`));
 | 
					            throw new Error(msg(str`Error creating credential: ${err}`));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // we now have a new credential! We now need to encode the byte arrays
 | 
					 | 
				
			||||||
        // in the credential into strings, for posting to our server.
 | 
					 | 
				
			||||||
        const newAssertionForServer = transformNewAssertionForServer(credential);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // post the transformed credential data to the server for validation
 | 
					        // post the transformed credential data to the server for validation
 | 
				
			||||||
        // and storing the public key
 | 
					        // and storing the public key
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            await this.host?.submit(
 | 
					            await this.host?.submit(
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    response: newAssertionForServer,
 | 
					                    response: credential.toJSON(),
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    invisible: true,
 | 
					                    invisible: true,
 | 
				
			||||||
@ -118,11 +105,9 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage<
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    updated(changedProperties: PropertyValues<this>) {
 | 
					    updated(changedProperties: PropertyValues<this>) {
 | 
				
			||||||
        if (changedProperties.has("challenge") && this.challenge !== undefined) {
 | 
					        if (changedProperties.has("challenge") && this.challenge !== undefined) {
 | 
				
			||||||
            // convert certain members of the PublicKeyCredentialCreateOptions into
 | 
					            this.publicKeyCredentialCreateOptions =
 | 
				
			||||||
            // byte arrays as expected by the spec.
 | 
					                PublicKeyCredential.parseCreationOptionsFromJSON(
 | 
				
			||||||
            this.publicKeyCredentialCreateOptions = transformCredentialCreateOptions(
 | 
					                    this.challenge?.registration as PublicKeyCredentialCreationOptionsJSON,
 | 
				
			||||||
                this.challenge?.registration as PublicKeyCredentialCreationOptions,
 | 
					 | 
				
			||||||
                this.challenge?.registration.user.id,
 | 
					 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            this.registerWrapper();
 | 
					            this.registerWrapper();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ import "construct-style-sheets-polyfill";
 | 
				
			|||||||
import "@webcomponents/webcomponentsjs";
 | 
					import "@webcomponents/webcomponentsjs";
 | 
				
			||||||
import "lit/polyfill-support.js";
 | 
					import "lit/polyfill-support.js";
 | 
				
			||||||
import "core-js/actual";
 | 
					import "core-js/actual";
 | 
				
			||||||
 | 
					import "webauthn-polyfills";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "@formatjs/intl-listformat/polyfill";
 | 
					import "@formatjs/intl-listformat/polyfill";
 | 
				
			||||||
import "@formatjs/intl-listformat/locale-data/en";
 | 
					import "@formatjs/intl-listformat/locale-data/en";
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								web/types/node.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								web/types/node.d.ts
									
									
									
									
										vendored
									
									
								
							@ -14,7 +14,7 @@ declare module "module" {
 | 
				
			|||||||
         * const relativeDirname = dirname(fileURLToPath(import.meta.url));
 | 
					         * const relativeDirname = dirname(fileURLToPath(import.meta.url));
 | 
				
			||||||
         * ```
 | 
					         * ```
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        // eslint-disable-next-line no-var
 | 
					
 | 
				
			||||||
        var __dirname: string;
 | 
					        var __dirname: string;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -9245,6 +9245,9 @@ Bindings to groups/users are checked against the user of the event.</source>
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -7753,6 +7753,9 @@ Bindings to groups/users are checked against the user of the event.</source>
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -9305,6 +9305,9 @@ Las vinculaciones a grupos o usuarios se comparan con el usuario del evento.</ta
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -9874,6 +9874,9 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -9857,6 +9857,9 @@ Bindings to groups/users are checked against the user of the event.</source>
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -9213,6 +9213,9 @@ Bindings to groups/users are checked against the user of the event.</source>
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -9117,6 +9117,9 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -9540,6 +9540,9 @@ Powiązania z grupami/użytkownikami są sprawdzane względem użytkownika zdarz
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -9549,4 +9549,7 @@ Bindings to groups/users are checked against the user of the event.</source>
 | 
				
			|||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
</body></file></xliff>
 | 
					</body></file></xliff>
 | 
				
			||||||
 | 
				
			|||||||
@ -9632,6 +9632,9 @@ Bindings to groups/users are checked against the user of the event.</source>
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -9604,6 +9604,9 @@ Gruplara/kullanıcılara yapılan bağlamalar, etkinliğin kullanıcısına kar
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -6368,6 +6368,9 @@ Bindings to groups/users are checked against the user of the event.</source>
 | 
				
			|||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</file>
 | 
					</file>
 | 
				
			||||||
</xliff>
 | 
					</xliff>
 | 
				
			||||||
 | 
				
			|||||||
@ -9878,12 +9878,18 @@ Bindings to groups/users are checked against the user of the event.</source>
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="sf9686d31d28fcf7d">
 | 
					<trans-unit id="sf9686d31d28fcf7d">
 | 
				
			||||||
  <source>Show field content</source>
 | 
					  <source>Show field content</source>
 | 
				
			||||||
 | 
					  <target>显示字段内容</target>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="sb1b05a7573ab618c">
 | 
					<trans-unit id="sb1b05a7573ab618c">
 | 
				
			||||||
  <source>Hide field content</source>
 | 
					  <source>Hide field content</source>
 | 
				
			||||||
 | 
					  <target>隐藏字段内容</target>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					  <target>使用 Plex 重新验证身份</target>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -7453,6 +7453,9 @@ Bindings to groups/users are checked against the user of the event.</source>
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -3011,11 +3011,6 @@ doesn't pass when either or both of the selected options are equal or above the
 | 
				
			|||||||
        <source>Load servers</source>
 | 
					        <source>Load servers</source>
 | 
				
			||||||
        <target>加载服务器</target>
 | 
					        <target>加载服务器</target>
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
      </trans-unit>
 | 
					 | 
				
			||||||
      <trans-unit id="s24f405197ede5ebb">
 | 
					 | 
				
			||||||
        <source>Re-authenticate with plex</source>
 | 
					 | 
				
			||||||
        <target>使用 Plex 重新验证身份</target>
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="sc297b2e13c28ecf9">
 | 
					      <trans-unit id="sc297b2e13c28ecf9">
 | 
				
			||||||
        <source>Allow friends to authenticate via Plex, even if you don't share any servers</source>
 | 
					        <source>Allow friends to authenticate via Plex, even if you don't share any servers</source>
 | 
				
			||||||
@ -9880,6 +9875,18 @@ Bindings to groups/users are checked against the user of the event.</source>
 | 
				
			|||||||
<trans-unit id="sb3d5c0a0501669df">
 | 
					<trans-unit id="sb3d5c0a0501669df">
 | 
				
			||||||
  <source>Generate New Certificate-Key Pair</source>
 | 
					  <source>Generate New Certificate-Key Pair</source>
 | 
				
			||||||
  <target>生成新的证书密钥对</target>
 | 
					  <target>生成新的证书密钥对</target>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="sf9686d31d28fcf7d">
 | 
				
			||||||
 | 
					  <source>Show field content</source>
 | 
				
			||||||
 | 
					  <target>显示字段内容</target>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="sb1b05a7573ab618c">
 | 
				
			||||||
 | 
					  <source>Hide field content</source>
 | 
				
			||||||
 | 
					  <target>隐藏字段内容</target>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					  <target>使用 Plex 重新验证身份</target>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -9192,6 +9192,9 @@ Bindings to groups/users are checked against the user of the event.</source>
 | 
				
			|||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
<trans-unit id="s4f820625804ed29b">
 | 
					<trans-unit id="s4f820625804ed29b">
 | 
				
			||||||
  <source>Re-authenticate with Plex</source>
 | 
					  <source>Re-authenticate with Plex</source>
 | 
				
			||||||
 | 
					</trans-unit>
 | 
				
			||||||
 | 
					<trans-unit id="s0433d667ea6eec1a">
 | 
				
			||||||
 | 
					  <source>The name of an invitation must be a slug: only lower case letters, numbers, and the hyphen are permitted here.</source>
 | 
				
			||||||
</trans-unit>
 | 
					</trans-unit>
 | 
				
			||||||
    </body>
 | 
					    </body>
 | 
				
			||||||
  </file>
 | 
					  </file>
 | 
				
			||||||
 | 
				
			|||||||
@ -70,9 +70,6 @@ To check if your config has been applied correctly, you can run the following co
 | 
				
			|||||||
- `AUTHENTIK_POSTGRESQL__USER`: Database user
 | 
					- `AUTHENTIK_POSTGRESQL__USER`: Database user
 | 
				
			||||||
- `AUTHENTIK_POSTGRESQL__PORT`: Database port, defaults to 5432
 | 
					- `AUTHENTIK_POSTGRESQL__PORT`: Database port, defaults to 5432
 | 
				
			||||||
- `AUTHENTIK_POSTGRESQL__PASSWORD`: Database password, defaults to the environment variable `POSTGRES_PASSWORD`
 | 
					- `AUTHENTIK_POSTGRESQL__PASSWORD`: Database password, defaults to the environment variable `POSTGRES_PASSWORD`
 | 
				
			||||||
  {/* TODO: Temporarily deactivated feature, see https://github.com/goauthentik/authentik/issues/14320 */}
 | 
					 | 
				
			||||||
  {/* - `AUTHENTIK_POSTGRESQL__USE_POOL`: Use a [connection pool](https://docs.djangoproject.com/en/stable/ref/databases/#connection-pool) for PostgreSQL connections. Defaults to `false`. :ak-version[2025.4] */}
 | 
					 | 
				
			||||||
  {/* - `AUTHENTIK_POSTGRESQL__POOL_OPTIONS`: Extra configuration to pass to the [ConnectionPool object](https://www.psycopg.org/psycopg3/docs/api/pool.html#psycopg_pool.ConnectionPool) when it is created. Must be a base64-encoded JSON dictionary. Ignored when `USE_POOL` is set to `false`. :ak-version[2025.4] */}
 | 
					 | 
				
			||||||
- `AUTHENTIK_POSTGRESQL__USE_PGBOUNCER`: Adjust configuration to support connection to PgBouncer. Deprecated, see below
 | 
					- `AUTHENTIK_POSTGRESQL__USE_PGBOUNCER`: Adjust configuration to support connection to PgBouncer. Deprecated, see below
 | 
				
			||||||
- `AUTHENTIK_POSTGRESQL__USE_PGPOOL`: Adjust configuration to support connection to Pgpool. Deprecated, see below
 | 
					- `AUTHENTIK_POSTGRESQL__USE_PGPOOL`: Adjust configuration to support connection to Pgpool. Deprecated, see below
 | 
				
			||||||
- `AUTHENTIK_POSTGRESQL__SSLMODE`: Strictness of ssl verification. Defaults to `"verify-ca"`
 | 
					- `AUTHENTIK_POSTGRESQL__SSLMODE`: Strictness of ssl verification. Defaults to `"verify-ca"`
 | 
				
			||||||
@ -85,7 +82,7 @@ To check if your config has been applied correctly, you can run the following co
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
The PostgreSQL settings `HOST`, `PORT`, `USER`, and `PASSWORD` support hot-reloading. Adding and removing read replicas doesn't support hot-reloading.
 | 
					The PostgreSQL settings `HOST`, `PORT`, `USER`, and `PASSWORD` support hot-reloading. Adding and removing read replicas doesn't support hot-reloading.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- `AUTHENTIK_POSTGRESQL__DEFAULT_SCHEMA`:ak-version[2024.12]
 | 
					- `AUTHENTIK_POSTGRESQL__DEFAULT_SCHEMA` :ak-version[2024.12]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    The name of the schema used by default in the database. Defaults to `public`.
 | 
					    The name of the schema used by default in the database. Defaults to `public`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -142,6 +142,17 @@ helm upgrade authentik authentik/authentik -f values.yaml --version ^2025.6
 | 
				
			|||||||
- tenants: fix tenant aware celery scheduler (cherry-pick #14921)
 | 
					- tenants: fix tenant aware celery scheduler (cherry-pick #14921)
 | 
				
			||||||
- web/user: fix user settings flow not loading (cherry-pick #14911) (#14930)
 | 
					- web/user: fix user settings flow not loading (cherry-pick #14911) (#14930)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Fixed in 2025.6.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- brands: fix custom_css being escaped (cherry-pick #14994) (#14996)
 | 
				
			||||||
 | 
					- core: bump django from 5.1.10 to 5.1.11 (cherry-pick #14997) (#15010)
 | 
				
			||||||
 | 
					- core: bump django from 5.1.9 to 5.1.10 (cherry-pick #14951) (#15008)
 | 
				
			||||||
 | 
					- internal/outpost: fix incorrect usage of golang SHA API (cherry-pick #14981) (#14982)
 | 
				
			||||||
 | 
					- providers/rac: fixes prompt data not being merged with connection_settings (cherry-pick #15037) (#15038)
 | 
				
			||||||
 | 
					- stages/email: Only attach logo to email if used (cherry-pick #14835) (#14969)
 | 
				
			||||||
 | 
					- web/elements: fix dual select without sortBy (cherry-pick #14977) (#14979)
 | 
				
			||||||
 | 
					- web/elements: fix typo in localeComparator (cherry-pick #15054) (#15055)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## API Changes
 | 
					## API Changes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### What's New
 | 
					#### What's New
 | 
				
			||||||
 | 
				
			|||||||
@ -27,3 +27,29 @@ uv run ak create_recovery_key 10 akadmin
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This will output a link, that can be used to instantly gain access to authentik as the user specified above. The link is valid for amount of years specified above, in this case, 10 years.
 | 
					This will output a link, that can be used to instantly gain access to authentik as the user specified above. The link is valid for amount of years specified above, in this case, 10 years.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Can't access initial setup flow during installation steps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you're unable to access the initial setup flow (`/if/flow/initial-setup/`) immediately after installing authentik, first try restarting the containers because this often resolves temporary issues.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					However, if the issue persists after restarting, you can directly set the admin password using the following commands:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Docker Compose deployments:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```bash
 | 
				
			||||||
 | 
					    docker compose exec server ak changepassword akadmin
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Kubernetes deployments:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```bash
 | 
				
			||||||
 | 
					    kubectl exec -it deployment/authentik-server -c server -- ak changepassword akadmin
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After following the prompts to set a new password, you can then login via: `https://authentik.company/if/flow/default-authentication-flow/?next=%2F`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After logging in, you can set the email address and other settings for the account by navigating to **Directory** > **Users** and editing the user account.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:::note
 | 
				
			||||||
 | 
					This method bypasses the initial setup flow and should only be used as a last resort. The initial setup flow is the recommended method to configure the administrator user.
 | 
				
			||||||
 | 
					:::
 | 
				
			||||||
 | 
				
			|||||||
@ -49,7 +49,7 @@ After you are connected, execute these commands to create a database backup:
 | 
				
			|||||||
cd /bitnami/postgresql/
 | 
					cd /bitnami/postgresql/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Set the PostgreSQL password from environment variable
 | 
					# Set the PostgreSQL password from environment variable
 | 
				
			||||||
export PGPASSWORD=$POSTGRES_POSTGRES_PASSWORD
 | 
					export PGPASSWORD=$(cat $POSTGRES_PASSWORD_FILE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Create a full database dump
 | 
					# Create a full database dump
 | 
				
			||||||
pg_dump -U $POSTGRES_USER $POSTGRES_DB > /bitnami/postgresql/dump.sql
 | 
					pg_dump -U $POSTGRES_USER $POSTGRES_DB > /bitnami/postgresql/dump.sql
 | 
				
			||||||
@ -117,7 +117,7 @@ cd /bitnami/postgresql/
 | 
				
			|||||||
ls -lh dump.sql
 | 
					ls -lh dump.sql
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Set the PostgreSQL password
 | 
					# Set the PostgreSQL password
 | 
				
			||||||
export PGPASSWORD=$POSTGRES_POSTGRES_PASSWORD
 | 
					export PGPASSWORD=$(cat $POSTGRES_PASSWORD_FILE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Import the database dump
 | 
					# Import the database dump
 | 
				
			||||||
psql -U $POSTGRES_USER $POSTGRES_DB < dump.sql
 | 
					psql -U $POSTGRES_USER $POSTGRES_DB < dump.sql
 | 
				
			||||||
 | 
				
			|||||||
@ -81,7 +81,7 @@ If you want to control user storage and designate Nextcloud administrators, you
 | 
				
			|||||||
    - **Create Scope Mapping**:
 | 
					    - **Create Scope Mapping**:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        - **Name**: `Nextcloud Profile`
 | 
					        - **Name**: `Nextcloud Profile`
 | 
				
			||||||
        - **Scope name**: `profile`
 | 
					        - **Scope name**: `nextcloud`
 | 
				
			||||||
        - **Expression**:
 | 
					        - **Expression**:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ```python
 | 
					            ```python
 | 
				
			||||||
@ -146,7 +146,7 @@ Depending on your Nextcloud configuration, you may need to use `https://nextclou
 | 
				
			|||||||
    - **Client ID**: Client ID from authentik
 | 
					    - **Client ID**: Client ID from authentik
 | 
				
			||||||
    - **Client secret**: Client secret from authentik
 | 
					    - **Client secret**: Client secret from authentik
 | 
				
			||||||
    - **Discovery endpoint**: `https://authentik.company/application/o/<application_slug>/.well-known/openid-configuration`
 | 
					    - **Discovery endpoint**: `https://authentik.company/application/o/<application_slug>/.well-known/openid-configuration`
 | 
				
			||||||
    - **Scope**: `email profile openid`
 | 
					    - **Scope**: `email nextcloud openid`
 | 
				
			||||||
    - Under **Attribute mappings**:
 | 
					    - Under **Attribute mappings**:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        - **User ID mapping**: `sub` (or `user_id` for existing users)
 | 
					        - **User ID mapping**: `sub` (or `user_id` for existing users)
 | 
				
			||||||
@ -161,6 +161,10 @@ Depending on your Nextcloud configuration, you may need to use `https://nextclou
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    - **Use unique user ID**: If this option is disabled, Nextcloud will use the mapped user ID as the Federated Cloud ID.
 | 
					    - **Use unique user ID**: If this option is disabled, Nextcloud will use the mapped user ID as the Federated Cloud ID.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :::note
 | 
				
			||||||
 | 
					    If authentik and Nextcloud are running on the same host, you will need to add `'allow_local_remote_servers' => true` to your nextcloud `config.php` file. This setting allows remote servers with local addresses.
 | 
				
			||||||
 | 
					    :::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    :::tip
 | 
					    :::tip
 | 
				
			||||||
    To avoid a hashed Federated Cloud ID, deselect **Use unique user ID** and use `user_id` for the User ID mapping.
 | 
					    To avoid a hashed Federated Cloud ID, deselect **Use unique user ID** and use `user_id` for the User ID mapping.
 | 
				
			||||||
    :::
 | 
					    :::
 | 
				
			||||||
 | 
				
			|||||||
@ -40,6 +40,7 @@ To support the integration of Zipline with authentik, you need to create an appl
 | 
				
			|||||||
    - Note the **Client ID** and **Client Secret** values because they will be required later.
 | 
					    - Note the **Client ID** and **Client Secret** values because they will be required later.
 | 
				
			||||||
    - Set a `Strict` redirect URI to `https://zipline.company/api/auth/oauth/oidc`.
 | 
					    - Set a `Strict` redirect URI to `https://zipline.company/api/auth/oauth/oidc`.
 | 
				
			||||||
    - Select any available signing key.
 | 
					    - Select any available signing key.
 | 
				
			||||||
 | 
					    - Under **Advanced Protocol Settings** > **Scopes**, add `authentik default OAuth Mapping: OpenID 'offline_access'` to the **Selected Scopes** list.
 | 
				
			||||||
- **Configure Bindings** _(optional)_: Create a [binding](/docs/add-secure-apps/flows-stages/bindings/) (policy, group, or user) to manage the listing and access to applications on a user's **My applications** page.
 | 
					- **Configure Bindings** _(optional)_: Create a [binding](/docs/add-secure-apps/flows-stages/bindings/) (policy, group, or user) to manage the listing and access to applications on a user's **My applications** page.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
3. Click **Submit** to save the new application and provider.
 | 
					3. Click **Submit** to save the new application and provider.
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										224
									
								
								website/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										224
									
								
								website/package-lock.json
									
									
									
										generated
									
									
									
								
							@ -19,11 +19,10 @@
 | 
				
			|||||||
                "@goauthentik/docusaurus-config": "^1.1.0",
 | 
					                "@goauthentik/docusaurus-config": "^1.1.0",
 | 
				
			||||||
                "@goauthentik/tsconfig": "^1.0.4",
 | 
					                "@goauthentik/tsconfig": "^1.0.4",
 | 
				
			||||||
                "@mdx-js/react": "^3.1.0",
 | 
					                "@mdx-js/react": "^3.1.0",
 | 
				
			||||||
                "@swc/html-linux-x64-gnu": "1.12.1",
 | 
					 | 
				
			||||||
                "clsx": "^2.1.1",
 | 
					                "clsx": "^2.1.1",
 | 
				
			||||||
                "docusaurus-plugin-openapi-docs": "^4.4.0",
 | 
					                "docusaurus-plugin-openapi-docs": "^4.4.0",
 | 
				
			||||||
                "docusaurus-theme-openapi-docs": "^4.4.0",
 | 
					                "docusaurus-theme-openapi-docs": "^4.4.0",
 | 
				
			||||||
                "postcss": "^8.5.5",
 | 
					                "postcss": "^8.5.6",
 | 
				
			||||||
                "prism-react-renderer": "^2.4.1",
 | 
					                "prism-react-renderer": "^2.4.1",
 | 
				
			||||||
                "react": "^18.3.1",
 | 
					                "react": "^18.3.1",
 | 
				
			||||||
                "react-before-after-slider-component": "^1.1.8",
 | 
					                "react-before-after-slider-component": "^1.1.8",
 | 
				
			||||||
@ -36,26 +35,26 @@
 | 
				
			|||||||
                "@docusaurus/module-type-aliases": "^3.7.0",
 | 
					                "@docusaurus/module-type-aliases": "^3.7.0",
 | 
				
			||||||
                "@docusaurus/tsconfig": "^3.7.0",
 | 
					                "@docusaurus/tsconfig": "^3.7.0",
 | 
				
			||||||
                "@docusaurus/types": "^3.7.0",
 | 
					                "@docusaurus/types": "^3.7.0",
 | 
				
			||||||
                "@eslint/js": "^9.28.0",
 | 
					                "@eslint/js": "^9.29.0",
 | 
				
			||||||
                "@goauthentik/eslint-config": "^1.0.5",
 | 
					                "@goauthentik/eslint-config": "^1.0.5",
 | 
				
			||||||
                "@goauthentik/prettier-config": "^1.0.5",
 | 
					                "@goauthentik/prettier-config": "^1.0.5",
 | 
				
			||||||
                "@goauthentik/tsconfig": "^1.0.4",
 | 
					                "@goauthentik/tsconfig": "^1.0.4",
 | 
				
			||||||
                "@trivago/prettier-plugin-sort-imports": "^5.2.2",
 | 
					                "@trivago/prettier-plugin-sort-imports": "^5.2.2",
 | 
				
			||||||
                "@types/lodash": "^4.17.17",
 | 
					                "@types/lodash": "^4.17.18",
 | 
				
			||||||
                "@types/node": "^24.0.1",
 | 
					                "@types/node": "^24.0.3",
 | 
				
			||||||
                "@types/postman-collection": "^3.5.11",
 | 
					                "@types/postman-collection": "^3.5.11",
 | 
				
			||||||
                "@types/react": "^18.3.22",
 | 
					                "@types/react": "^18.3.22",
 | 
				
			||||||
                "@types/semver": "^7.7.0",
 | 
					                "@types/semver": "^7.7.0",
 | 
				
			||||||
                "@typescript-eslint/eslint-plugin": "^8.34.0",
 | 
					                "@typescript-eslint/eslint-plugin": "^8.34.1",
 | 
				
			||||||
                "@typescript-eslint/parser": "^8.34.0",
 | 
					                "@typescript-eslint/parser": "^8.34.1",
 | 
				
			||||||
                "cross-env": "^7.0.3",
 | 
					                "cross-env": "^7.0.3",
 | 
				
			||||||
                "eslint": "^9.28.0",
 | 
					                "eslint": "^9.29.0",
 | 
				
			||||||
                "fast-glob": "^3.3.3",
 | 
					                "fast-glob": "^3.3.3",
 | 
				
			||||||
                "npm-run-all": "^4.1.5",
 | 
					                "npm-run-all": "^4.1.5",
 | 
				
			||||||
                "prettier": "^3.5.3",
 | 
					                "prettier": "^3.5.3",
 | 
				
			||||||
                "prettier-plugin-packagejson": "^2.5.15",
 | 
					                "prettier-plugin-packagejson": "^2.5.15",
 | 
				
			||||||
                "typescript": "^5.8.3",
 | 
					                "typescript": "^5.8.3",
 | 
				
			||||||
                "typescript-eslint": "^8.34.0"
 | 
					                "typescript-eslint": "^8.34.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": ">=22.14.0"
 | 
					                "node": ">=22.14.0"
 | 
				
			||||||
@ -4209,9 +4208,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@eslint/config-array": {
 | 
					        "node_modules/@eslint/config-array": {
 | 
				
			||||||
            "version": "0.20.0",
 | 
					            "version": "0.20.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
 | 
					            "integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
 | 
				
			||||||
            "devOptional": true,
 | 
					            "devOptional": true,
 | 
				
			||||||
            "license": "Apache-2.0",
 | 
					            "license": "Apache-2.0",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
@ -4308,9 +4307,9 @@
 | 
				
			|||||||
            "license": "MIT"
 | 
					            "license": "MIT"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@eslint/js": {
 | 
					        "node_modules/@eslint/js": {
 | 
				
			||||||
            "version": "9.28.0",
 | 
					            "version": "9.29.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
 | 
					            "integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
 | 
				
			||||||
            "devOptional": true,
 | 
					            "devOptional": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
@ -6581,9 +6580,9 @@
 | 
				
			|||||||
            "license": "MIT"
 | 
					            "license": "MIT"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@types/lodash": {
 | 
					        "node_modules/@types/lodash": {
 | 
				
			||||||
            "version": "4.17.17",
 | 
					            "version": "4.17.18",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.18.tgz",
 | 
				
			||||||
            "integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==",
 | 
					            "integrity": "sha512-KJ65INaxqxmU6EoCiJmRPZC9H9RVWCRd349tXM2M3O5NA7cY6YL7c0bHAHQ93NOfTObEQ004kd2QVHs/r0+m4g==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT"
 | 
					            "license": "MIT"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@ -6615,9 +6614,9 @@
 | 
				
			|||||||
            "license": "MIT"
 | 
					            "license": "MIT"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@types/node": {
 | 
					        "node_modules/@types/node": {
 | 
				
			||||||
            "version": "24.0.1",
 | 
					            "version": "24.0.3",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.1.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz",
 | 
				
			||||||
            "integrity": "sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw==",
 | 
					            "integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==",
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "undici-types": "~7.8.0"
 | 
					                "undici-types": "~7.8.0"
 | 
				
			||||||
@ -6831,17 +6830,17 @@
 | 
				
			|||||||
            "license": "MIT"
 | 
					            "license": "MIT"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/eslint-plugin": {
 | 
					        "node_modules/@typescript-eslint/eslint-plugin": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-QXwAlHlbcAwNlEEMKQS2RCgJsgXrTJdjXT08xEgbPFa2yYQgVjBymxP5DrfrE7X7iodSzd9qBUHUycdyVJTW1w==",
 | 
					            "integrity": "sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@eslint-community/regexpp": "^4.10.0",
 | 
					                "@eslint-community/regexpp": "^4.10.0",
 | 
				
			||||||
                "@typescript-eslint/scope-manager": "8.34.0",
 | 
					                "@typescript-eslint/scope-manager": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/type-utils": "8.34.0",
 | 
					                "@typescript-eslint/type-utils": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/utils": "8.34.0",
 | 
					                "@typescript-eslint/utils": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/visitor-keys": "8.34.0",
 | 
					                "@typescript-eslint/visitor-keys": "8.34.1",
 | 
				
			||||||
                "graphemer": "^1.4.0",
 | 
					                "graphemer": "^1.4.0",
 | 
				
			||||||
                "ignore": "^7.0.0",
 | 
					                "ignore": "^7.0.0",
 | 
				
			||||||
                "natural-compare": "^1.4.0",
 | 
					                "natural-compare": "^1.4.0",
 | 
				
			||||||
@ -6855,7 +6854,7 @@
 | 
				
			|||||||
                "url": "https://opencollective.com/typescript-eslint"
 | 
					                "url": "https://opencollective.com/typescript-eslint"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "peerDependencies": {
 | 
					            "peerDependencies": {
 | 
				
			||||||
                "@typescript-eslint/parser": "^8.34.0",
 | 
					                "@typescript-eslint/parser": "^8.34.1",
 | 
				
			||||||
                "eslint": "^8.57.0 || ^9.0.0",
 | 
					                "eslint": "^8.57.0 || ^9.0.0",
 | 
				
			||||||
                "typescript": ">=4.8.4 <5.9.0"
 | 
					                "typescript": ">=4.8.4 <5.9.0"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -6871,16 +6870,16 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/parser": {
 | 
					        "node_modules/@typescript-eslint/parser": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-vxXJV1hVFx3IXz/oy2sICsJukaBrtDEQSBiV48/YIV5KWjX1dO+bcIr/kCPrW6weKXvsaGKFNlwH0v2eYdRRbA==",
 | 
					            "integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/scope-manager": "8.34.0",
 | 
					                "@typescript-eslint/scope-manager": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/types": "8.34.0",
 | 
					                "@typescript-eslint/types": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/typescript-estree": "8.34.0",
 | 
					                "@typescript-eslint/typescript-estree": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/visitor-keys": "8.34.0",
 | 
					                "@typescript-eslint/visitor-keys": "8.34.1",
 | 
				
			||||||
                "debug": "^4.3.4"
 | 
					                "debug": "^4.3.4"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
@ -6896,14 +6895,14 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/project-service": {
 | 
					        "node_modules/@typescript-eslint/project-service": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-iEgDALRf970/B2YExmtPMPF54NenZUf4xpL3wsCRx/lgjz6ul/l13R81ozP/ZNuXfnLCS+oPmG7JIxfdNYKELw==",
 | 
					            "integrity": "sha512-nuHlOmFZfuRwLJKDGQOVc0xnQrAmuq1Mj/ISou5044y1ajGNp2BNliIqp7F2LPQ5sForz8lempMFCovfeS1XoA==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/tsconfig-utils": "^8.34.0",
 | 
					                "@typescript-eslint/tsconfig-utils": "^8.34.1",
 | 
				
			||||||
                "@typescript-eslint/types": "^8.34.0",
 | 
					                "@typescript-eslint/types": "^8.34.1",
 | 
				
			||||||
                "debug": "^4.3.4"
 | 
					                "debug": "^4.3.4"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
@ -6918,14 +6917,14 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/scope-manager": {
 | 
					        "node_modules/@typescript-eslint/scope-manager": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-9Ac0X8WiLykl0aj1oYQNcLZjHgBojT6cW68yAgZ19letYu+Hxd0rE0veI1XznSSst1X5lwnxhPbVdwjDRIomRw==",
 | 
					            "integrity": "sha512-beu6o6QY4hJAgL1E8RaXNC071G4Kso2MGmJskCFQhRhg8VOH/FDbC8soP8NHN7e/Hdphwp8G8cE6OBzC8o41ZA==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/types": "8.34.0",
 | 
					                "@typescript-eslint/types": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/visitor-keys": "8.34.0"
 | 
					                "@typescript-eslint/visitor-keys": "8.34.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
@ -6936,9 +6935,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/tsconfig-utils": {
 | 
					        "node_modules/@typescript-eslint/tsconfig-utils": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-+W9VYHKFIzA5cBeooqQxqNriAP0QeQ7xTiDuIOr71hzgffm3EL2hxwWBIIj4GuofIbKxGNarpKqIq6Q6YrShOA==",
 | 
					            "integrity": "sha512-K4Sjdo4/xF9NEeA2khOb7Y5nY6NSXBnod87uniVYW9kHP+hNlDV8trUSFeynA2uxWam4gIWgWoygPrv9VMWrYg==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
@ -6953,14 +6952,14 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/type-utils": {
 | 
					        "node_modules/@typescript-eslint/type-utils": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-n7zSmOcUVhcRYC75W2pnPpbO1iwhJY3NLoHEtbJwJSNlVAZuwqu05zY3f3s2SDWWDSo9FdN5szqc73DCtDObAg==",
 | 
					            "integrity": "sha512-Tv7tCCr6e5m8hP4+xFugcrwTOucB8lshffJ6zf1mF1TbU67R+ntCc6DzLNKM+s/uzDyv8gLq7tufaAhIBYeV8g==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/typescript-estree": "8.34.0",
 | 
					                "@typescript-eslint/typescript-estree": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/utils": "8.34.0",
 | 
					                "@typescript-eslint/utils": "8.34.1",
 | 
				
			||||||
                "debug": "^4.3.4",
 | 
					                "debug": "^4.3.4",
 | 
				
			||||||
                "ts-api-utils": "^2.1.0"
 | 
					                "ts-api-utils": "^2.1.0"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@ -6977,9 +6976,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/types": {
 | 
					        "node_modules/@typescript-eslint/types": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-9V24k/paICYPniajHfJ4cuAWETnt7Ssy+R0Rbcqo5sSFr3QEZ/8TSoUi9XeXVBGXCaLtwTOKSLGcInCAvyZeMA==",
 | 
					            "integrity": "sha512-rjLVbmE7HR18kDsjNIZQHxmv9RZwlgzavryL5Lnj2ujIRTeXlKtILHgRNmQ3j4daw7zd+mQgy+uyt6Zo6I0IGA==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
@ -6991,16 +6990,16 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/typescript-estree": {
 | 
					        "node_modules/@typescript-eslint/typescript-estree": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-rOi4KZxI7E0+BMqG7emPSK1bB4RICCpF7QD3KCLXn9ZvWoESsOMlHyZPAHyG04ujVplPaHbmEvs34m+wjgtVtg==",
 | 
					            "integrity": "sha512-rjCNqqYPuMUF5ODD+hWBNmOitjBWghkGKJg6hiCHzUvXRy6rK22Jd3rwbP2Xi+R7oYVvIKhokHVhH41BxPV5mA==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/project-service": "8.34.0",
 | 
					                "@typescript-eslint/project-service": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/tsconfig-utils": "8.34.0",
 | 
					                "@typescript-eslint/tsconfig-utils": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/types": "8.34.0",
 | 
					                "@typescript-eslint/types": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/visitor-keys": "8.34.0",
 | 
					                "@typescript-eslint/visitor-keys": "8.34.1",
 | 
				
			||||||
                "debug": "^4.3.4",
 | 
					                "debug": "^4.3.4",
 | 
				
			||||||
                "fast-glob": "^3.3.2",
 | 
					                "fast-glob": "^3.3.2",
 | 
				
			||||||
                "is-glob": "^4.0.3",
 | 
					                "is-glob": "^4.0.3",
 | 
				
			||||||
@ -7020,9 +7019,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
 | 
					        "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
 | 
				
			||||||
            "version": "2.0.1",
 | 
					            "version": "2.0.2",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
 | 
				
			||||||
            "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
 | 
					            "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
@ -7046,16 +7045,16 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/utils": {
 | 
					        "node_modules/@typescript-eslint/utils": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-8L4tWatGchV9A1cKbjaavS6mwYwp39jql8xUmIIKJdm+qiaeHy5KMKlBrf30akXAWBzn2SqKsNOtSENWUwg7XQ==",
 | 
					            "integrity": "sha512-mqOwUdZ3KjtGk7xJJnLbHxTuWVn3GO2WZZuM+Slhkun4+qthLdXx32C8xIXbO1kfCECb3jIs3eoxK3eryk7aoQ==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@eslint-community/eslint-utils": "^4.7.0",
 | 
					                "@eslint-community/eslint-utils": "^4.7.0",
 | 
				
			||||||
                "@typescript-eslint/scope-manager": "8.34.0",
 | 
					                "@typescript-eslint/scope-manager": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/types": "8.34.0",
 | 
					                "@typescript-eslint/types": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/typescript-estree": "8.34.0"
 | 
					                "@typescript-eslint/typescript-estree": "8.34.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
@ -7070,14 +7069,14 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/@typescript-eslint/visitor-keys": {
 | 
					        "node_modules/@typescript-eslint/visitor-keys": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-qHV7pW7E85A0x6qyrFn+O+q1k1p3tQCsqIZ1KZ5ESLXY57aTvUd3/a4rdPTeXisvhXn2VQG0VSKUqs8KHF2zcA==",
 | 
					            "integrity": "sha512-xoh5rJ+tgsRKoXnkBPFRLZ7rjKM0AfVbC68UZ/ECXoDbfggb9RbEySN359acY1vS3qZ0jVTVWzbtfapwm5ztxw==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/types": "8.34.0",
 | 
					                "@typescript-eslint/types": "8.34.1",
 | 
				
			||||||
                "eslint-visitor-keys": "^4.2.0"
 | 
					                "eslint-visitor-keys": "^4.2.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
@ -7291,9 +7290,10 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/acorn": {
 | 
					        "node_modules/acorn": {
 | 
				
			||||||
            "version": "8.14.0",
 | 
					            "version": "8.15.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
 | 
					            "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
 | 
				
			||||||
 | 
					            "license": "MIT",
 | 
				
			||||||
            "bin": {
 | 
					            "bin": {
 | 
				
			||||||
                "acorn": "bin/acorn"
 | 
					                "acorn": "bin/acorn"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@ -12218,19 +12218,19 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/eslint": {
 | 
					        "node_modules/eslint": {
 | 
				
			||||||
            "version": "9.28.0",
 | 
					            "version": "9.29.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
 | 
					            "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
 | 
				
			||||||
            "devOptional": true,
 | 
					            "devOptional": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@eslint-community/eslint-utils": "^4.2.0",
 | 
					                "@eslint-community/eslint-utils": "^4.2.0",
 | 
				
			||||||
                "@eslint-community/regexpp": "^4.12.1",
 | 
					                "@eslint-community/regexpp": "^4.12.1",
 | 
				
			||||||
                "@eslint/config-array": "^0.20.0",
 | 
					                "@eslint/config-array": "^0.20.1",
 | 
				
			||||||
                "@eslint/config-helpers": "^0.2.1",
 | 
					                "@eslint/config-helpers": "^0.2.1",
 | 
				
			||||||
                "@eslint/core": "^0.14.0",
 | 
					                "@eslint/core": "^0.14.0",
 | 
				
			||||||
                "@eslint/eslintrc": "^3.3.1",
 | 
					                "@eslint/eslintrc": "^3.3.1",
 | 
				
			||||||
                "@eslint/js": "9.28.0",
 | 
					                "@eslint/js": "9.29.0",
 | 
				
			||||||
                "@eslint/plugin-kit": "^0.3.1",
 | 
					                "@eslint/plugin-kit": "^0.3.1",
 | 
				
			||||||
                "@humanfs/node": "^0.16.6",
 | 
					                "@humanfs/node": "^0.16.6",
 | 
				
			||||||
                "@humanwhocodes/module-importer": "^1.0.1",
 | 
					                "@humanwhocodes/module-importer": "^1.0.1",
 | 
				
			||||||
@ -12242,9 +12242,9 @@
 | 
				
			|||||||
                "cross-spawn": "^7.0.6",
 | 
					                "cross-spawn": "^7.0.6",
 | 
				
			||||||
                "debug": "^4.3.2",
 | 
					                "debug": "^4.3.2",
 | 
				
			||||||
                "escape-string-regexp": "^4.0.0",
 | 
					                "escape-string-regexp": "^4.0.0",
 | 
				
			||||||
                "eslint-scope": "^8.3.0",
 | 
					                "eslint-scope": "^8.4.0",
 | 
				
			||||||
                "eslint-visitor-keys": "^4.2.0",
 | 
					                "eslint-visitor-keys": "^4.2.1",
 | 
				
			||||||
                "espree": "^10.3.0",
 | 
					                "espree": "^10.4.0",
 | 
				
			||||||
                "esquery": "^1.5.0",
 | 
					                "esquery": "^1.5.0",
 | 
				
			||||||
                "esutils": "^2.0.2",
 | 
					                "esutils": "^2.0.2",
 | 
				
			||||||
                "fast-deep-equal": "^3.1.3",
 | 
					                "fast-deep-equal": "^3.1.3",
 | 
				
			||||||
@ -12558,9 +12558,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/eslint/node_modules/eslint-scope": {
 | 
					        "node_modules/eslint/node_modules/eslint-scope": {
 | 
				
			||||||
            "version": "8.3.0",
 | 
					            "version": "8.4.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
 | 
					            "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
 | 
				
			||||||
            "devOptional": true,
 | 
					            "devOptional": true,
 | 
				
			||||||
            "license": "BSD-2-Clause",
 | 
					            "license": "BSD-2-Clause",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
@ -12575,9 +12575,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/eslint/node_modules/eslint-visitor-keys": {
 | 
					        "node_modules/eslint/node_modules/eslint-visitor-keys": {
 | 
				
			||||||
            "version": "4.2.0",
 | 
					            "version": "4.2.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
 | 
					            "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
 | 
				
			||||||
            "devOptional": true,
 | 
					            "devOptional": true,
 | 
				
			||||||
            "license": "Apache-2.0",
 | 
					            "license": "Apache-2.0",
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
@ -12706,15 +12706,15 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/espree": {
 | 
					        "node_modules/espree": {
 | 
				
			||||||
            "version": "10.3.0",
 | 
					            "version": "10.4.0",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
 | 
				
			||||||
            "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
 | 
					            "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
 | 
				
			||||||
            "devOptional": true,
 | 
					            "devOptional": true,
 | 
				
			||||||
            "license": "BSD-2-Clause",
 | 
					            "license": "BSD-2-Clause",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "acorn": "^8.14.0",
 | 
					                "acorn": "^8.15.0",
 | 
				
			||||||
                "acorn-jsx": "^5.3.2",
 | 
					                "acorn-jsx": "^5.3.2",
 | 
				
			||||||
                "eslint-visitor-keys": "^4.2.0"
 | 
					                "eslint-visitor-keys": "^4.2.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
@ -12724,9 +12724,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/espree/node_modules/eslint-visitor-keys": {
 | 
					        "node_modules/espree/node_modules/eslint-visitor-keys": {
 | 
				
			||||||
            "version": "4.2.0",
 | 
					            "version": "4.2.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
 | 
					            "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
 | 
				
			||||||
            "devOptional": true,
 | 
					            "devOptional": true,
 | 
				
			||||||
            "license": "Apache-2.0",
 | 
					            "license": "Apache-2.0",
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
@ -20672,9 +20672,9 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/postcss": {
 | 
					        "node_modules/postcss": {
 | 
				
			||||||
            "version": "8.5.5",
 | 
					            "version": "8.5.6",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.5.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
 | 
				
			||||||
            "integrity": "sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==",
 | 
					            "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
 | 
				
			||||||
            "funding": [
 | 
					            "funding": [
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    "type": "opencollective",
 | 
					                    "type": "opencollective",
 | 
				
			||||||
@ -26387,15 +26387,15 @@
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "node_modules/typescript-eslint": {
 | 
					        "node_modules/typescript-eslint": {
 | 
				
			||||||
            "version": "8.34.0",
 | 
					            "version": "8.34.1",
 | 
				
			||||||
            "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.0.tgz",
 | 
					            "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.34.1.tgz",
 | 
				
			||||||
            "integrity": "sha512-MRpfN7uYjTrTGigFCt8sRyNqJFhjN0WwZecldaqhWm+wy0gaRt8Edb/3cuUy0zdq2opJWT6iXINKAtewnDOltQ==",
 | 
					            "integrity": "sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==",
 | 
				
			||||||
            "dev": true,
 | 
					            "dev": true,
 | 
				
			||||||
            "license": "MIT",
 | 
					            "license": "MIT",
 | 
				
			||||||
            "dependencies": {
 | 
					            "dependencies": {
 | 
				
			||||||
                "@typescript-eslint/eslint-plugin": "8.34.0",
 | 
					                "@typescript-eslint/eslint-plugin": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/parser": "8.34.0",
 | 
					                "@typescript-eslint/parser": "8.34.1",
 | 
				
			||||||
                "@typescript-eslint/utils": "8.34.0"
 | 
					                "@typescript-eslint/utils": "8.34.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "engines": {
 | 
					            "engines": {
 | 
				
			||||||
                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
					                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
 | 
				
			||||||
 | 
				
			|||||||
@ -37,7 +37,7 @@
 | 
				
			|||||||
        "clsx": "^2.1.1",
 | 
					        "clsx": "^2.1.1",
 | 
				
			||||||
        "docusaurus-plugin-openapi-docs": "^4.4.0",
 | 
					        "docusaurus-plugin-openapi-docs": "^4.4.0",
 | 
				
			||||||
        "docusaurus-theme-openapi-docs": "^4.4.0",
 | 
					        "docusaurus-theme-openapi-docs": "^4.4.0",
 | 
				
			||||||
        "postcss": "^8.5.5",
 | 
					        "postcss": "^8.5.6",
 | 
				
			||||||
        "prism-react-renderer": "^2.4.1",
 | 
					        "prism-react-renderer": "^2.4.1",
 | 
				
			||||||
        "react": "^18.3.1",
 | 
					        "react": "^18.3.1",
 | 
				
			||||||
        "react-before-after-slider-component": "^1.1.8",
 | 
					        "react-before-after-slider-component": "^1.1.8",
 | 
				
			||||||
@ -50,26 +50,26 @@
 | 
				
			|||||||
        "@docusaurus/module-type-aliases": "^3.7.0",
 | 
					        "@docusaurus/module-type-aliases": "^3.7.0",
 | 
				
			||||||
        "@docusaurus/tsconfig": "^3.7.0",
 | 
					        "@docusaurus/tsconfig": "^3.7.0",
 | 
				
			||||||
        "@docusaurus/types": "^3.7.0",
 | 
					        "@docusaurus/types": "^3.7.0",
 | 
				
			||||||
        "@eslint/js": "^9.28.0",
 | 
					        "@eslint/js": "^9.29.0",
 | 
				
			||||||
        "@goauthentik/eslint-config": "^1.0.5",
 | 
					        "@goauthentik/eslint-config": "^1.0.5",
 | 
				
			||||||
        "@goauthentik/prettier-config": "^1.0.5",
 | 
					        "@goauthentik/prettier-config": "^1.0.5",
 | 
				
			||||||
        "@goauthentik/tsconfig": "^1.0.4",
 | 
					        "@goauthentik/tsconfig": "^1.0.4",
 | 
				
			||||||
        "@trivago/prettier-plugin-sort-imports": "^5.2.2",
 | 
					        "@trivago/prettier-plugin-sort-imports": "^5.2.2",
 | 
				
			||||||
        "@types/lodash": "^4.17.17",
 | 
					        "@types/lodash": "^4.17.18",
 | 
				
			||||||
        "@types/node": "^24.0.1",
 | 
					        "@types/node": "^24.0.3",
 | 
				
			||||||
        "@types/postman-collection": "^3.5.11",
 | 
					        "@types/postman-collection": "^3.5.11",
 | 
				
			||||||
        "@types/react": "^18.3.22",
 | 
					        "@types/react": "^18.3.22",
 | 
				
			||||||
        "@types/semver": "^7.7.0",
 | 
					        "@types/semver": "^7.7.0",
 | 
				
			||||||
        "@typescript-eslint/eslint-plugin": "^8.34.0",
 | 
					        "@typescript-eslint/eslint-plugin": "^8.34.1",
 | 
				
			||||||
        "@typescript-eslint/parser": "^8.34.0",
 | 
					        "@typescript-eslint/parser": "^8.34.1",
 | 
				
			||||||
        "cross-env": "^7.0.3",
 | 
					        "cross-env": "^7.0.3",
 | 
				
			||||||
        "eslint": "^9.28.0",
 | 
					        "eslint": "^9.29.0",
 | 
				
			||||||
        "fast-glob": "^3.3.3",
 | 
					        "fast-glob": "^3.3.3",
 | 
				
			||||||
        "npm-run-all": "^4.1.5",
 | 
					        "npm-run-all": "^4.1.5",
 | 
				
			||||||
        "prettier": "^3.5.3",
 | 
					        "prettier": "^3.5.3",
 | 
				
			||||||
        "prettier-plugin-packagejson": "^2.5.15",
 | 
					        "prettier-plugin-packagejson": "^2.5.15",
 | 
				
			||||||
        "typescript": "^5.8.3",
 | 
					        "typescript": "^5.8.3",
 | 
				
			||||||
        "typescript-eslint": "^8.34.0"
 | 
					        "typescript-eslint": "^8.34.1"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "optionalDependencies": {
 | 
					    "optionalDependencies": {
 | 
				
			||||||
        "@rspack/binding-darwin-arm64": "1.3.15",
 | 
					        "@rspack/binding-darwin-arm64": "1.3.15",
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user