Compare commits

..

1 Commits

Author SHA1 Message Date
Dominic R
ca1844ae70 website/docs: clarify OAuth2 provider overview 2026-05-07 21:25:04 -04:00
1403 changed files with 2745 additions and 3189 deletions

View File

@@ -25,7 +25,7 @@ runs:
if: ${{ contains(inputs.dependencies, 'system') || contains(inputs.dependencies, 'python') }}
uses: gerlero/apt-install@f4fa5265092af9e750549565d28c99aec7189639
with:
packages: libpq-dev openssl libxmlsec1-dev pkg-config gettext libclang-dev libkadm5clnt-mit12 libkadm5clnt7t64-heimdal libkrb5-dev krb5-kdc krb5-user krb5-admin-server
packages: libpq-dev openssl libxmlsec1-dev pkg-config gettext krb5-multidev libkrb5-dev heimdal-multidev libclang-dev krb5-kdc krb5-user krb5-admin-server
update: true
upgrade: false
install-recommends: false
@@ -52,19 +52,19 @@ runs:
run: uv sync --all-extras --dev --locked
- name: Setup rust (stable)
if: ${{ contains(inputs.dependencies, 'rust') && !contains(inputs.dependencies, 'rust-nightly') }}
uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1
uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 # v1
with:
rustflags: ""
- name: Setup rust (nightly)
if: ${{ contains(inputs.dependencies, 'rust-nightly') }}
uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1
uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 # v1
with:
toolchain: nightly
components: rustfmt
rustflags: ""
- name: Setup rust dependencies
if: ${{ contains(inputs.dependencies, 'rust') }}
uses: taiki-e/install-action@3fa6878dc4ae603f73960271565a082bf196ab96 # v2
uses: taiki-e/install-action@711e1c3275189d76dcc4d34ddea63bf96ac49090 # v2
with:
tool: cargo-deny cargo-machete cargo-llvm-cov nextest
- name: Setup node (web)

View File

@@ -28,10 +28,10 @@ jobs:
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Initialize CodeQL
uses: github/codeql-action/init@v4.35.3
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v4.35.3
uses: github/codeql-action/autobuild@v4
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4.35.3
uses: github/codeql-action/analyze@v4

View File

@@ -5,7 +5,7 @@ on:
workflow_dispatch:
inputs:
next_version:
description: Next version (for example, if you're currently releasing 2026.5, then enter 2026.8)
description: Next major version (for example, if releasing 2042.2, this is 2042.4)
required: true
type: string
@@ -68,14 +68,10 @@ jobs:
token: ${{ steps.generate_token.outputs.token }}
- name: Setup authentik env
uses: ./.github/actions/setup
with:
dependencies: "system,python,go,node,runtime,rust-nightly"
- name: Run migrations
run: make migrate
- name: Bump version
run: "make bump version=${{ inputs.next_version }}.0-rc1"
- name: Re-generate API Clients
run: make gen
- name: Create pull request
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v7
with:

View File

@@ -191,7 +191,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5
- uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # v6.1.1
- uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
with:
role-to-assume: "arn:aws:iam::016170277896:role/github_goauthentik_authentik"
aws-region: ${{ env.AWS_REGION }}

View File

@@ -82,14 +82,10 @@ jobs:
token: "${{ steps.app-token.outputs.token }}"
- name: Setup authentik env
uses: ./.github/actions/setup
with:
dependencies: "system,python,go,node,runtime,rust-nightly"
- name: Run migrations
run: make migrate
- name: Bump version
run: "make bump version=${{ inputs.version }}"
- name: Re-generate API Clients
run: make gen
- name: Commit and push
run: |
# ID from https://api.github.com/users/authentik-automation[bot]

36
Cargo.lock generated
View File

@@ -171,7 +171,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "authentik"
version = "2026.8.0-rc1"
version = "2026.5.0-rc1"
dependencies = [
"arc-swap",
"argh",
@@ -196,7 +196,7 @@ dependencies = [
[[package]]
name = "authentik-axum"
version = "2026.8.0-rc1"
version = "2026.5.0-rc1"
dependencies = [
"authentik-common",
"axum",
@@ -216,7 +216,7 @@ dependencies = [
[[package]]
name = "authentik-client"
version = "2026.8.0-rc1"
version = "2026.5.0-rc1"
dependencies = [
"aws-lc-rs",
"reqwest",
@@ -232,7 +232,7 @@ dependencies = [
[[package]]
name = "authentik-common"
version = "2026.8.0-rc1"
version = "2026.5.0-rc1"
dependencies = [
"arc-swap",
"authentik-client",
@@ -1744,6 +1744,16 @@ dependencies = [
"serde",
]
[[package]]
name = "iri-string"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb"
dependencies = [
"memchr",
"serde",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
@@ -3193,9 +3203,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "sentry"
version = "0.48.1"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b93b3e19f45495ddd41d8222a152c48c84f6ba45abe9c69e2527e9cdea29bb5b"
checksum = "e8ac94aab850a23d7507307cc505332ed2bafd36c65930dfc5c43610f9e9b477"
dependencies = [
"cfg_aliases",
"httpdate",
@@ -3390,9 +3400,9 @@ dependencies = [
[[package]]
name = "serde_with"
version = "3.19.0"
version = "3.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f05839ce67618e14a09b286535c0d9c94e85ef25469b0e13cb4f844e5593eb19"
checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f"
dependencies = [
"base64 0.22.1",
"chrono",
@@ -3924,9 +3934,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.52.2"
version = "1.52.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "110a78583f19d5cdb2c5ccf321d1290344e71313c6c37d43520d386027d18386"
checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6"
dependencies = [
"bytes",
"libc",
@@ -4072,21 +4082,21 @@ dependencies = [
[[package]]
name = "tower-http"
version = "0.6.10"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51"
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
dependencies = [
"bitflags 2.11.0",
"bytes",
"futures-util",
"http",
"http-body",
"iri-string",
"pin-project-lite",
"tokio",
"tower",
"tower-layer",
"tower-service",
"url",
]
[[package]]

View File

@@ -8,7 +8,7 @@ members = [
resolver = "3"
[workspace.package]
version = "2026.8.0-rc1"
version = "2026.5.0-rc1"
authors = ["authentik Team <hello@goauthentik.io>"]
description = "Making authentication simple."
edition = "2024"
@@ -67,7 +67,7 @@ reqwest-middleware = { version = "= 0.5.1", features = [
"rustls",
] }
rustls = { version = "= 0.23.40", features = ["fips"] }
sentry = { version = "= 0.48.1", default-features = false, features = [
sentry = { version = "= 0.48.0", default-features = false, features = [
"backtrace",
"contexts",
"debug-images",
@@ -80,7 +80,7 @@ sentry = { version = "= 0.48.1", default-features = false, features = [
serde = { version = "= 1.0.228", features = ["derive"] }
serde_json = "= 1.0.149"
serde_repr = "= 0.1.20"
serde_with = { version = "= 3.19.0", default-features = false, features = [
serde_with = { version = "= 3.18.0", default-features = false, features = [
"base64",
] }
sqlx = { version = "= 0.8.6", default-features = false, features = [
@@ -97,12 +97,12 @@ sqlx = { version = "= 0.8.6", default-features = false, features = [
tempfile = "= 3.27.0"
thiserror = "= 2.0.18"
time = { version = "= 0.3.47", features = ["macros"] }
tokio = { version = "= 1.52.2", features = ["full", "tracing"] }
tokio = { version = "= 1.52.1", features = ["full", "tracing"] }
tokio-retry2 = "= 0.9.1"
tokio-rustls = "= 0.26.4"
tokio-util = { version = "= 0.7.18", features = ["full"] }
tower = "= 0.5.3"
tower-http = { version = "= 0.6.10", features = ["timeout"] }
tower-http = { version = "= 0.6.8", features = ["timeout"] }
tracing = "= 0.1.44"
tracing-error = "= 0.2.1"
tracing-subscriber = { version = "= 0.3.23", features = [
@@ -115,9 +115,9 @@ url = "= 2.5.8"
uuid = { version = "= 1.23.1", features = ["serde", "v4"] }
which = "= 8.0.2"
ak-axum = { package = "authentik-axum", version = "2026.8.0-rc1", path = "./packages/ak-axum" }
ak-client = { package = "authentik-client", version = "2026.8.0-rc1", path = "./packages/client-rust" }
ak-common = { package = "authentik-common", version = "2026.8.0-rc1", path = "./packages/ak-common", default-features = false }
ak-axum = { package = "authentik-axum", version = "2026.5.0-rc1", path = "./packages/ak-axum" }
ak-client = { package = "authentik-client", version = "2026.5.0-rc1", path = "./packages/client-rust" }
ak-common = { package = "authentik-common", version = "2026.5.0-rc1", path = "./packages/ak-common", default-features = false }
[workspace.lints.rust]
ambiguous_negative_literals = "warn"

View File

@@ -160,7 +160,7 @@ endif
$(eval current_version := $(shell cat ${PWD}/internal/constants/VERSION))
$(SED_INPLACE) 's/^version = ".*"/version = "$(version)"/' ${PWD}/pyproject.toml
$(SED_INPLACE) 's/^VERSION = ".*"/VERSION = "$(version)"/' ${PWD}/authentik/__init__.py
$(SED_INPLACE) "s/version = \"${current_version}\"/version = \"$(version)\"/" ${PWD}/Cargo.toml ${PWD}/Cargo.lock
$(SED_INPLACE) "s/version = \"${current_version}\"/version = \"$(version)\"" ${PWD}/Cargo.toml ${PWD}/Cargo.lock
$(MAKE) gen-build gen-compose aws-cfn
$(SED_INPLACE) "s/\"${current_version}\"/\"$(version)\"/" ${PWD}/package.json ${PWD}/package-lock.json ${PWD}/web/package.json ${PWD}/web/package-lock.json
echo -n $(version) > ${PWD}/internal/constants/VERSION

View File

@@ -3,7 +3,7 @@
from functools import lru_cache
from os import environ
VERSION = "2026.8.0-rc1"
VERSION = "2026.5.0-rc1"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@@ -217,7 +217,10 @@ class BlueprintInstanceViewSet(UsedByMixin, ModelViewSet):
@extend_schema(
request={"multipart/form-data": BlueprintUploadSerializer},
responses={200: BlueprintImportResultSerializer},
responses={
204: BlueprintImportResultSerializer,
400: BlueprintImportResultSerializer,
},
)
@action(url_path="import", detail=False, methods=["POST"], parser_classes=(MultiPartParser,))
@validate(
@@ -244,13 +247,21 @@ class BlueprintInstanceViewSet(UsedByMixin, ModelViewSet):
import_response = self.BlueprintImportResultSerializer(
data={
"logs": [LogEventSerializer(log).data for log in logs],
"success": valid,
"logs": [],
"success": False,
}
)
import_response.is_valid(raise_exception=True)
if valid:
import_response.initial_data["success"] = importer.apply()
import_response.is_valid()
import_response.initial_data["logs"] = [LogEventSerializer(log).data for log in logs]
import_response.initial_data["success"] = valid
import_response.is_valid()
if not valid:
return Response(data=import_response.initial_data, status=200)
successful = importer.apply()
import_response.initial_data["success"] = successful
import_response.is_valid()
if not successful:
return Response(data=import_response.initial_data, status=200)
return Response(data=import_response.initial_data, status=200)

View File

@@ -31,7 +31,7 @@ entries:
slug: "%(uid)s-source"
attrs:
name: "%(uid)s-source"
provider_type: entraid
provider_type: azuread
consumer_key: "%(uid)s"
consumer_secret: "%(uid)s"
icon: https://goauthentik.io/img/icon.png

View File

@@ -3,7 +3,6 @@
from json import dumps, loads
from tempfile import NamedTemporaryFile, mkdtemp
from django.core.files.uploadedfile import SimpleUploadedFile
from django.urls import reverse
from rest_framework.test import APITestCase
from yaml import dump
@@ -142,20 +141,6 @@ class TestBlueprintsV1API(APITestCase):
)
self.assertEqual(res.status_code, 200)
def test_api_import_invalid_blueprint_returns_result_payload(self):
"""Invalid blueprint content returns a result payload instead of a 400 response."""
file = SimpleUploadedFile("invalid-blueprint.yaml", b'{"version": 3}')
res = self.client.post(
reverse("authentik_api:blueprintinstance-import-"),
data={"file": file},
format="multipart",
)
self.assertEqual(res.status_code, 200)
self.assertFalse(res.json()["success"])
self.assertGreater(len(res.json()["logs"]), 0)
def test_api_import_unknown_path(self):
"""Path not in available blueprints is rejected (covers api.py:56)."""
res = self.client.post(

View File

@@ -11,9 +11,7 @@ from authentik.events.models import NotificationRule
class NotificationRuleSerializer(ModelSerializer):
"""NotificationRule Serializer"""
destination_group_obj = GroupSerializer(
read_only=True, source="destination_group", required=False, allow_null=True
)
destination_group_obj = GroupSerializer(read_only=True, source="destination_group")
class Meta:
model = NotificationRule

View File

@@ -7,6 +7,13 @@ from authentik.lib.config import CONFIG, ENV_PREFIX
from authentik.lib.utils.time import fqdn_rand
from authentik.tasks.schedules.common import ScheduleSpec
# TODO: Deprecated metric - remove in 2024.2 or later
GAUGE_TASKS = Gauge(
"authentik_system_tasks",
"System tasks and their status",
["tenant", "task_name", "task_uid", "status"],
)
SYSTEM_TASK_TIME = Histogram(
"authentik_system_tasks_time_seconds",
"Runtime of system tasks",

View File

@@ -49,6 +49,15 @@ class LogEventSerializer(PassiveSerializer):
event = CharField()
attributes = DictField()
# TODO(2024.6?): This is a migration helper to return a correct API response for logs that
# have been saved in an older format (mostly just list[str] with just the messages)
def to_representation(self, instance):
if isinstance(instance, str):
instance = LogEvent(instance, "", "")
elif isinstance(instance, list):
instance = [LogEvent(x, "", "") for x in instance]
return super().to_representation(instance)
@contextmanager
def capture_logs(log_default_output=True) -> Generator[list[LogEvent]]:

View File

@@ -61,11 +61,6 @@ class SAMLProviderSerializer(ProviderSerializer):
url_download_metadata = SerializerMethodField()
url_issuer = SerializerMethodField()
# Unified SAML endpoint (primary)
url_unified = SerializerMethodField()
url_unified_init = SerializerMethodField()
# Legacy endpoints (for backward compatibility)
url_sso_post = SerializerMethodField()
url_sso_redirect = SerializerMethodField()
url_sso_init = SerializerMethodField()
@@ -102,21 +97,6 @@ class SAMLProviderSerializer(ProviderSerializer):
if "request" not in self._context:
return DEFAULT_ISSUER
request: HttpRequest = self._context["request"]._request
try:
return request.build_absolute_uri(
reverse(
"authentik_providers_saml:metadata-download",
kwargs={"application_slug": instance.application.slug},
)
)
except Provider.application.RelatedObjectDoesNotExist:
return DEFAULT_ISSUER
def get_url_unified(self, instance: SAMLProvider) -> str:
"""Get unified SAML endpoint URL (handles SSO and SLO)"""
if "request" not in self._context:
return ""
request: HttpRequest = self._context["request"]._request
try:
return request.build_absolute_uri(
reverse(
@@ -125,22 +105,7 @@ class SAMLProviderSerializer(ProviderSerializer):
)
)
except Provider.application.RelatedObjectDoesNotExist:
return "-"
def get_url_unified_init(self, instance: SAMLProvider) -> str:
"""Get IdP-initiated SAML URL"""
if "request" not in self._context:
return ""
request: HttpRequest = self._context["request"]._request
try:
return request.build_absolute_uri(
reverse(
"authentik_providers_saml:init",
kwargs={"application_slug": instance.application.slug},
)
)
except Provider.application.RelatedObjectDoesNotExist:
return "-"
return DEFAULT_ISSUER
def get_url_sso_post(self, instance: SAMLProvider) -> str:
"""Get SSO Post URL"""
@@ -278,8 +243,6 @@ class SAMLProviderSerializer(ProviderSerializer):
"default_name_id_policy",
"url_download_metadata",
"url_issuer",
"url_unified",
"url_unified_init",
"url_sso_post",
"url_sso_redirect",
"url_sso_init",

View File

@@ -241,7 +241,7 @@ class SAMLProvider(Provider):
"""Use IDP-Initiated SAML flow as launch URL"""
try:
return reverse(
"authentik_providers_saml:init",
"authentik_providers_saml:sso-init",
kwargs={"application_slug": self.application.slug},
)
except Provider.application.RelatedObjectDoesNotExist:

View File

@@ -147,7 +147,7 @@ class AssertionProcessor:
return self.http_request.build_absolute_uri(
reverse(
"authentik_providers_saml:metadata-download",
"authentik_providers_saml:base",
kwargs={"application_slug": self.provider.application.slug},
)
)

View File

@@ -48,7 +48,7 @@ class MetadataProcessor:
return self.http_request.build_absolute_uri(
reverse(
"authentik_providers_saml:metadata-download",
"authentik_providers_saml:base",
kwargs={"application_slug": self.provider.application.slug},
)
)
@@ -81,35 +81,54 @@ class MetadataProcessor:
element.text = name_id_format
yield element
def _get_unified_url(self) -> str:
"""Get the unified SAML endpoint URL"""
return self.http_request.build_absolute_uri(
reverse(
"authentik_providers_saml:base",
kwargs={"application_slug": self.provider.application.slug},
)
)
def get_sso_bindings(self) -> Iterator[Element]:
"""Get all SSO Bindings - both point to unified endpoint"""
unified_url = self._get_unified_url()
for binding in [SAML_BINDING_REDIRECT, SAML_BINDING_POST]:
"""Get all Bindings supported"""
binding_url_map = {
(SAML_BINDING_REDIRECT, "SingleSignOnService"): self.http_request.build_absolute_uri(
reverse(
"authentik_providers_saml:sso-redirect",
kwargs={"application_slug": self.provider.application.slug},
)
),
(SAML_BINDING_POST, "SingleSignOnService"): self.http_request.build_absolute_uri(
reverse(
"authentik_providers_saml:sso-post",
kwargs={"application_slug": self.provider.application.slug},
)
),
}
for binding_svc, url in binding_url_map.items():
binding, svc = binding_svc
if self.force_binding and self.force_binding != binding:
continue
element = Element(f"{{{NS_SAML_METADATA}}}SingleSignOnService")
element = Element(f"{{{NS_SAML_METADATA}}}{svc}")
element.attrib["Binding"] = binding
element.attrib["Location"] = unified_url
element.attrib["Location"] = url
yield element
def get_slo_bindings(self) -> Iterator[Element]:
"""Get all SLO Bindings - both point to unified endpoint"""
unified_url = self._get_unified_url()
for binding in [SAML_BINDING_REDIRECT, SAML_BINDING_POST]:
"""Get all Bindings supported"""
binding_url_map = {
(SAML_BINDING_REDIRECT, "SingleLogoutService"): self.http_request.build_absolute_uri(
reverse(
"authentik_providers_saml:slo-redirect",
kwargs={"application_slug": self.provider.application.slug},
)
),
(SAML_BINDING_POST, "SingleLogoutService"): self.http_request.build_absolute_uri(
reverse(
"authentik_providers_saml:slo-post",
kwargs={"application_slug": self.provider.application.slug},
)
),
}
for binding_svc, url in binding_url_map.items():
binding, svc = binding_svc
if self.force_binding and self.force_binding != binding:
continue
element = Element(f"{{{NS_SAML_METADATA}}}SingleLogoutService")
element = Element(f"{{{NS_SAML_METADATA}}}{svc}")
element.attrib["Binding"] = binding
element.attrib["Location"] = unified_url
element.attrib["Location"] = url
yield element
def _prepare_signature(self, entity_descriptor: _Element):

View File

@@ -4,26 +4,19 @@ from django.urls import path
from authentik.providers.saml.api.property_mappings import SAMLPropertyMappingViewSet
from authentik.providers.saml.api.providers import SAMLProviderViewSet
from authentik.providers.saml.views import metadata, sso, unified
from authentik.providers.saml.views import metadata, sso
from authentik.providers.saml.views.sp_slo import (
SPInitiatedSLOBindingPOSTView,
SPInitiatedSLOBindingRedirectView,
)
urlpatterns = [
# Unified Endpoint - handles SSO and SLO based on message type
# Base path for Issuer/Entity ID
path(
"<slug:application_slug>/",
unified.SAMLUnifiedView.as_view(),
sso.SAMLSSOBindingRedirectView.as_view(),
name="base",
),
# IdP-initiated
path(
"<slug:application_slug>/init/",
sso.SAMLSSOBindingInitView.as_view(),
name="init",
),
# LEGACY Endpoints (backward compatibility)
# SSO Bindings
path(
"<slug:application_slug>/sso/binding/redirect/",

View File

@@ -1,118 +0,0 @@
"""Unified SAML endpoint - handles SSO and SLO based on message type"""
from base64 import b64decode
from defusedxml.lxml import fromstring
from django.http import HttpRequest, HttpResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.clickjacking import xframe_options_sameorigin
from django.views.decorators.csrf import csrf_exempt
from structlog.stdlib import get_logger
from authentik.common.saml.constants import NS_MAP
from authentik.flows.views.executor import SESSION_KEY_POST
from authentik.lib.views import bad_request_message
from authentik.providers.saml.utils.encoding import decode_base64_and_inflate
from authentik.providers.saml.views.flows import (
REQUEST_KEY_SAML_REQUEST,
REQUEST_KEY_SAML_RESPONSE,
)
from authentik.providers.saml.views.sp_slo import (
SPInitiatedSLOBindingPOSTView,
SPInitiatedSLOBindingRedirectView,
)
from authentik.providers.saml.views.sso import (
SAMLSSOBindingPOSTView,
SAMLSSOBindingRedirectView,
)
LOGGER = get_logger()
# SAML message type constants
SAML_MESSAGE_TYPE_AUTHN_REQUEST = "AuthnRequest"
SAML_MESSAGE_TYPE_LOGOUT_REQUEST = "LogoutRequest"
def detect_saml_message_type(saml_request: str, is_post_binding: bool) -> str | None:
"""Parse SAML request to determine if AuthnRequest or LogoutRequest."""
try:
if is_post_binding:
decoded_xml = b64decode(saml_request.encode())
else:
decoded_xml = decode_base64_and_inflate(saml_request)
root = fromstring(decoded_xml)
if len(root.xpath("//samlp:AuthnRequest", namespaces=NS_MAP)):
return SAML_MESSAGE_TYPE_AUTHN_REQUEST
if len(root.xpath("//samlp:LogoutRequest", namespaces=NS_MAP)):
return SAML_MESSAGE_TYPE_LOGOUT_REQUEST
return None
except Exception: # noqa: BLE001
return None
@method_decorator(xframe_options_sameorigin, name="dispatch")
@method_decorator(csrf_exempt, name="dispatch")
class SAMLUnifiedView(View):
"""Unified SAML endpoint - handles SSO and SLO based on message type.
The operation type is determined by parsing
the incoming SAML message:
- AuthnRequest -> SSO flow (delegates to SAMLSSOBindingRedirectView/POSTView)
- LogoutRequest -> SLO flow (delegates to SPInitiatedSLOBindingRedirectView/POSTView)
- LogoutResponse -> SLO completion (delegates to SPInitiatedSLOBindingRedirectView/POSTView)
"""
def dispatch(self, request: HttpRequest, application_slug: str) -> HttpResponse:
"""Route the request based on SAML message type."""
# ak user was not logged in, redirected to login, and is back w POST payload in session
if SESSION_KEY_POST in request.session:
return self._delegate_to_sso(request, application_slug, is_post_binding=True)
# Determine binding from HTTP method
is_post_binding = request.method == "POST"
data = request.POST if is_post_binding else request.GET
# LogoutResponse - delegate to SLO view (handles it in dispatch)
if REQUEST_KEY_SAML_RESPONSE in data:
return self._delegate_to_slo(request, application_slug, is_post_binding)
# Check for SAML request
if REQUEST_KEY_SAML_REQUEST not in data:
LOGGER.info("SAML payload missing")
return bad_request_message(request, "The SAML request payload is missing.")
# Detect message type and delegate
saml_request = data[REQUEST_KEY_SAML_REQUEST]
message_type = detect_saml_message_type(saml_request, is_post_binding)
if message_type == SAML_MESSAGE_TYPE_AUTHN_REQUEST:
return self._delegate_to_sso(request, application_slug, is_post_binding)
elif message_type == SAML_MESSAGE_TYPE_LOGOUT_REQUEST:
return self._delegate_to_slo(request, application_slug, is_post_binding)
else:
LOGGER.warning("Unknown SAML message type", message_type=message_type)
return bad_request_message(
request, f"Unsupported SAML message type: {message_type or 'unknown'}"
)
def _delegate_to_sso(
self, request: HttpRequest, application_slug: str, is_post_binding: bool
) -> HttpResponse:
"""Delegate to the appropriate SSO view."""
if is_post_binding:
view = SAMLSSOBindingPOSTView.as_view()
else:
view = SAMLSSOBindingRedirectView.as_view()
return view(request, application_slug=application_slug)
def _delegate_to_slo(
self, request: HttpRequest, application_slug: str, is_post_binding: bool
) -> HttpResponse:
"""Delegate to the appropriate SLO view."""
if is_post_binding:
view = SPInitiatedSLOBindingPOSTView.as_view()
else:
view = SPInitiatedSLOBindingRedirectView.as_view()
return view(request, application_slug=application_slug)

View File

@@ -10,6 +10,7 @@ LOGGER = get_logger()
AUTHENTIK_SOURCES_OAUTH_TYPES = [
"authentik.sources.oauth.types.apple",
"authentik.sources.oauth.types.azure_ad",
"authentik.sources.oauth.types.discord",
"authentik.sources.oauth.types.entra_id",
"authentik.sources.oauth.types.facebook",

View File

@@ -1,23 +0,0 @@
# Generated by Django 5.2.14 on 2026-05-09 19:01
from django.db import migrations
def migrate_azuread_to_entraid(apps, schema_editor):
OAuthSource = apps.get_model("authentik_sources_oauth", "OAuthSource")
db_alias = schema_editor.connection.alias
OAuthSource.objects.using(db_alias).filter(provider_type="azuread").update(
provider_type="entraid"
)
class Migration(migrations.Migration):
dependencies = [
("authentik_sources_oauth", "0013_useroauthsourceconnection_refresh_token"),
]
operations = [
migrations.RunPython(migrate_azuread_to_entraid, migrations.RunPython.noop),
]

View File

@@ -251,6 +251,17 @@ class GoogleOAuthSource(CreatableType, OAuthSource):
verbose_name_plural = _("Google OAuth Sources")
class AzureADOAuthSource(CreatableType, OAuthSource):
"""(Deprecated) Social Login using Azure AD."""
class Meta:
abstract = True
verbose_name = _("Azure AD OAuth Source")
verbose_name_plural = _("Azure AD OAuth Sources")
# TODO: When removing this, add a migration for OAuthSource that sets
# provider_type to `entraid` if it is currently `azuread`
class EntraIDOAuthSource(CreatableType, OAuthSource):
"""Social Login using Entra ID."""

View File

@@ -0,0 +1,17 @@
"""AzureAD OAuth2 Views"""
from authentik.sources.oauth.types.entra_id import EntraIDType
from authentik.sources.oauth.types.registry import registry
# TODO: When removing this, add a migration for OAuthSource that sets
# provider_type to `entraid` if it is currently `azuread`
@registry.register()
class AzureADType(EntraIDType):
"""Azure AD Type definition"""
verbose_name = "Azure AD"
name = "azuread"
urls_customizable = True

View File

@@ -19,30 +19,24 @@ from authentik.tenants.models import Tenant
class FlagJSONField(JSONDictField):
def to_internal_value(self, data: str):
flags = super().to_internal_value(data)
for flag in Flag.available(visibility="system", exclude_system=False):
flags[flag().key] = flag.get()
return flags
def to_representation(self, value: dict) -> dict:
"""Exclude any system flags that aren't modifiable"""
new_value = value.copy()
for flag in Flag.available(exclude_system=False):
_flag = flag()
# Exclude any system flags that aren't modifiable
if _flag.visibility == "system":
new_value.pop(_flag.key, None)
# Explicitly present unset flags as if they were set to default
if _flag.key not in value:
value[_flag.key] = _flag.default
return super().to_representation(new_value)
def run_validators(self, value: dict):
super().run_validators(value)
for flag in Flag.available():
for flag in Flag.available(exclude_system=False):
_flag = flag()
if _flag.key not in value:
continue
if _flag.visibility == "system":
value.pop(_flag.key, None)
continue
flag_value = value.get(_flag.key)
flag_type = get_args(_flag.__orig_bases__[0])[0]
if flag_value and not isinstance(flag_value, flag_type):

View File

@@ -85,30 +85,10 @@ class TestLocalSettingsAPI(APITestCase):
"flags": {"tenants_test_flag_sys": 123},
},
)
print(response.content)
self.assertEqual(response.status_code, 200)
self.tenant.refresh_from_db()
self.assertEqual(self.tenant.flags, {"setup": False, "tenants_test_flag_sys": False})
def test_settings_flags_system_empty_put(self):
"""Test settings API"""
self.tenant.flags = {}
self.tenant.save()
class _TestFlag(Flag[bool], key="tenants_test_flag_sys"):
default = False
visibility = "system"
self.client.force_login(self.local_admin)
response = self.client.patch(
reverse("authentik_api:tenant_settings"),
data={
"flags": {},
},
)
self.assertEqual(response.status_code, 200)
self.tenant.refresh_from_db()
self.assertEqual(self.tenant.flags, {"setup": False, "tenants_test_flag_sys": False})
self.assertEqual(self.tenant.flags, {})
def test_command(self):
self.tenant.flags = {}

View File

@@ -36,10 +36,14 @@ entries:
attrs:
order: 50
initial_value: |
actor_uuid = str(getattr(http_request.user, "pk", ""))
pending_user = user if getattr(user, "is_authenticated", False) else None
target_uuid = str(getattr(pending_user, "pk", ""))
is_self_service = not target_uuid or target_uuid == actor_uuid
target_uuid = (http_request.session.get("authentik/flows/get", {}) or {}).get("user_uuid")
current_user_uuid = str(getattr(user, "pk", "") or getattr(http_request.user, "pk", ""))
is_self_service = not target_uuid or target_uuid == current_user_uuid
pending_user = None
if target_uuid and not is_self_service:
from authentik.core.models import User
pending_user = User.objects.filter(pk=target_uuid).first()
if is_self_service:
return (
"<p><strong>You are about to lock down your own account.</strong></p>"
@@ -59,15 +63,14 @@ entries:
from django.utils.html import escape
if pending_user:
detail = pending_user.email or pending_user.name
user_html = f"<code>{escape(pending_user.username)}</code>"
if detail and detail != pending_user.username:
user_html = f"{user_html} ({escape(detail)})"
email = escape(pending_user.email or pending_user.name or "No email")
user_html = f"<p><code>{escape(pending_user.username)}</code> ({email})</p>"
else:
user_html = "the account selected when this one-time lockdown link was created"
user_html = "<p>the account selected when this one-time lockdown link was created</p>"
return (
f"<p><strong>You are about to lock down the following account:</strong> {user_html}</p>"
"<p><strong>You are about to lock down the following account:</strong></p>"
f"{user_html}"
"<p>This is an emergency action for cutting off access to the account right away. "
"It does not lock the administrator who opened this page.</p>"
"<p><strong>This will immediately:</strong></p>"
@@ -96,9 +99,9 @@ entries:
attrs:
order: 100
initial_value: |
actor_uuid = str(getattr(http_request.user, "pk", ""))
target_uuid = str(getattr(user, "pk", ""))
is_self_service = not target_uuid or target_uuid == actor_uuid
target_uuid = (http_request.session.get("authentik/flows/get", {}) or {}).get("user_uuid")
current_user_uuid = str(getattr(user, "pk", "") or getattr(http_request.user, "pk", ""))
is_self_service = not target_uuid or target_uuid == current_user_uuid
if is_self_service:
info = (
"Use this if you no longer trust your current password or sessions. "
@@ -131,9 +134,9 @@ entries:
attrs:
order: 200
placeholder: |
actor_uuid = str(getattr(http_request.user, "pk", ""))
target_uuid = str(getattr(user, "pk", ""))
is_self_service = not target_uuid or target_uuid == actor_uuid
target_uuid = (http_request.session.get("authentik/flows/get", {}) or {}).get("user_uuid")
current_user_uuid = str(getattr(user, "pk", "") or getattr(http_request.user, "pk", ""))
is_self_service = not target_uuid or target_uuid == current_user_uuid
if is_self_service:
return "Describe why you are locking your account..."
return "Describe why this account is being locked down..."
@@ -181,10 +184,14 @@ entries:
attrs:
order: 300
initial_value: |
target_uuid = (http_request.session.get("authentik/flows/get", {}) or {}).get("user_uuid")
from django.utils.html import escape
from authentik.core.models import User
if getattr(user, "is_authenticated", False):
return f"<p><code>{escape(user.username)}</code> has been locked down.</p>"
if target_uuid:
target = User.objects.filter(pk=target_uuid).first()
if target:
return f"<p><code>{escape(target.username)}</code> has been locked down.</p>"
return "<p>The selected account has been locked down.</p>"
initial_value_expression: true
@@ -214,9 +221,9 @@ entries:
attrs:
name: default-account-lockdown-admin-policy
expression: |
actor_uuid = str(getattr(request.http_request.user, "pk", ""))
target_uuid = str(getattr(request.user, "pk", ""))
return bool(target_uuid) and target_uuid != actor_uuid
target_uuid = (request.http_request.session.get("authentik/flows/get", {}) or {}).get("user_uuid")
current_user_uuid = str(getattr(request.user, "pk", "") or getattr(request.http_request.user, "pk", ""))
return bool(target_uuid) and target_uuid != current_user_uuid
identifiers:
name: default-account-lockdown-admin-policy
id: admin-policy

View File

@@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://goauthentik.io/blueprints/schema.json",
"type": "object",
"title": "authentik 2026.8.0-rc1 Blueprint schema",
"title": "authentik 2026.5.0-rc1 Blueprint schema",
"required": [
"version",
"entries"

14
go.mod
View File

@@ -7,10 +7,10 @@ require (
beryju.io/radius-eap v0.1.0
github.com/avast/retry-go/v4 v4.7.0
github.com/coreos/go-oidc/v3 v3.18.0
github.com/getsentry/sentry-go v0.46.2
github.com/getsentry/sentry-go v0.46.1
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
github.com/go-ldap/ldap/v3 v3.4.13
github.com/go-openapi/runtime v0.29.5
github.com/go-openapi/runtime v0.29.4
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/uuid v1.6.0
github.com/gorilla/handlers v1.5.2
@@ -57,7 +57,7 @@ require (
github.com/go-openapi/jsonreference v0.21.5 // indirect
github.com/go-openapi/loads v0.23.3 // indirect
github.com/go-openapi/spec v0.22.4 // indirect
github.com/go-openapi/strfmt v0.26.2 // indirect
github.com/go-openapi/strfmt v0.26.1 // indirect
github.com/go-openapi/swag/conv v0.26.0 // indirect
github.com/go-openapi/swag/fileutils v0.26.0 // indirect
github.com/go-openapi/swag/jsonname v0.25.5 // indirect
@@ -90,10 +90,10 @@ require (
go.opentelemetry.io/otel/trace v1.43.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.50.0 // indirect
golang.org/x/net v0.53.0 // indirect
golang.org/x/sys v0.43.0 // indirect
golang.org/x/text v0.36.0 // indirect
golang.org/x/crypto v0.49.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/text v0.35.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

36
go.sum
View File

@@ -20,8 +20,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/getsentry/sentry-go v0.46.2 h1:1jhYwrKGa3sIpo/y5iDNXS5wDoT7I1KNzMHrnK6ojns=
github.com/getsentry/sentry-go v0.46.2/go.mod h1:evVbw2qotNUdYG8KxXbAdjOQWWvWIwKxpjdZZIvcIPw=
github.com/getsentry/sentry-go v0.46.1 h1:mZyQFaQYkPxAdDG4HR8gDg6j4CnKYVWt4TF92N7i3XY=
github.com/getsentry/sentry-go v0.46.1/go.mod h1:evVbw2qotNUdYG8KxXbAdjOQWWvWIwKxpjdZZIvcIPw=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
@@ -51,12 +51,12 @@ github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe
github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw=
github.com/go-openapi/loads v0.23.3 h1:g5Xap1JfwKkUnZdn+S0L3SzBDpcTIYzZ5Qaag0YDkKQ=
github.com/go-openapi/loads v0.23.3/go.mod h1:NOH07zLajXo8y55hom0omlHWDVVvCwBM/S+csCK8LqA=
github.com/go-openapi/runtime v0.29.5 h1:uc5+/TtqLIfDBTUxnF3uppoGMt+9DzonwUWsviINlrY=
github.com/go-openapi/runtime v0.29.5/go.mod h1:D9IUbWccdYv+km8QwmAm90FZvDcQk47vP2Y7y5as/D8=
github.com/go-openapi/runtime v0.29.4 h1:k2lDxrGoSAJRdhFG2tONKMpkizY/4X1cciSdtzk4Jjo=
github.com/go-openapi/runtime v0.29.4/go.mod h1:K0k/2raY6oqXJnZAgWJB2i/12QKrhUKpZcH4PfV9P18=
github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ=
github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ=
github.com/go-openapi/strfmt v0.26.2 h1:ysjheCh4i1rmFEo2LanhELDNucNzfWTZhUDKgWWPaFM=
github.com/go-openapi/strfmt v0.26.2/go.mod h1:fXh1e449cyUn2NYuz+wb3wARBUdMl7qPEZwX00nqivY=
github.com/go-openapi/strfmt v0.26.1 h1:7zGCHji7zSYDC2tCXIusoxYQz/48jAf2q+sF6wXTG+c=
github.com/go-openapi/strfmt v0.26.1/go.mod h1:Zslk5VZPOISLwmWTMBIS7oiVFem1o1EI6zULY8Uer7Y=
github.com/go-openapi/swag/conv v0.26.0 h1:5yGGsPYI1ZCva93U0AoKi/iZrNhaJEjr324YVsiD89I=
github.com/go-openapi/swag/conv v0.26.0/go.mod h1:tpAmIL7X58VPnHHiSO4uE3jBeRamGsFsfdDeDtb5ECE=
github.com/go-openapi/swag/fileutils v0.26.0 h1:WJoPRvsA7QRiiWluowkLJa9jaYR7FCuxmDvnCgaRRxU=
@@ -77,10 +77,10 @@ github.com/go-openapi/swag/typeutils v0.26.0 h1:2kdEwdiNWy+JJdOvu5MA2IIg2SylWAFu
github.com/go-openapi/swag/typeutils v0.26.0/go.mod h1:oovDuIUvTrEHVMqWilQzKzV4YlSKgyZmFh7AlfABNVE=
github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ=
github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ=
github.com/go-openapi/testify/enable/yaml/v2 v2.5.0 h1:3hZD1fwydvCx/cc1R2uYNQirHqf2s6lqpKV3FcNTURA=
github.com/go-openapi/testify/enable/yaml/v2 v2.5.0/go.mod h1:TvDZKBH7ZbMaF3EqH2AwTvNQCmzyZq8K1agRjf1B+Nk=
github.com/go-openapi/testify/v2 v2.5.0 h1:UOCr63aAsMIDydZbZGqo5Ev01D4eydItRbekDuZMJLw=
github.com/go-openapi/testify/v2 v2.5.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
github.com/go-openapi/testify/enable/yaml/v2 v2.4.2 h1:5zRca5jw7lzVREKCZVNBpysDNBjj74rBh0N2BGQbSR0=
github.com/go-openapi/testify/enable/yaml/v2 v2.4.2/go.mod h1:XVevPw5hUXuV+5AkI1u1PeAm27EQVrhXTTCPAF85LmE=
github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4=
github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
github.com/go-openapi/validate v0.25.2 h1:12NsfLAwGegqbGWr2CnvT65X/Q2USJipmJ9b7xDJZz0=
github.com/go-openapi/validate v0.25.2/go.mod h1:Pgl1LpPPGFnZ+ys4/hTlDiRYQdI1ocKypgE+8Q8BLfY=
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
@@ -216,8 +216,8 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab h1:628ME69lBm9C6JY2wXhAph/yjN3jezx1z7BIDLUwxjo=
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -227,8 +227,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -245,8 +245,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -258,8 +258,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

View File

@@ -1 +1 @@
2026.8.0-rc1
2026.5.0-rc1

View File

@@ -38,10 +38,6 @@ function run_authentik {
echo cargo run -- "$@"
fi
;;
manage)
shift 1
echo python -m manage "$@"
;;
*)
echo "$@"
;;

View File

@@ -18,7 +18,7 @@ Parameters:
Description: authentik Docker image
AuthentikVersion:
Type: String
Default: 2026.8.0-rc1
Default: 2026.5.0-rc1
Description: authentik Docker image tag
AuthentikServerCPU:
Type: Number

View File

@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
# Stage: Build webui
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24-trixie-slim@sha256:4f2b45e32dc7d2caf66b6dbd59fac50e32f8077769efe0ef4d4c3f114672537d AS node-builder
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24-trixie-slim@sha256:735dd688da64d22ebd9dd374b3e7e5a874635668fd2a6ec20ca1f99264294086 AS node-builder
ARG GIT_BUILD_HASH
ENV GIT_BUILD_HASH=$GIT_BUILD_HASH
@@ -228,7 +228,8 @@ RUN apt-get update && \
# Required for runtime
apt-get install -y --no-install-recommends \
libpq5 libmaxminddb0 ca-certificates \
libkadm5clnt-mit12 libkadm5clnt7t64-heimdal \
krb5-multidev libkrb5-3 libkdb5-10 libkadm5clnt-mit12 \
heimdal-multidev libkadm5clnt7t64-heimdal \
libltdl7 libxslt1.1 && \
# Required for bootstrap & healtcheck
apt-get install -y --no-install-recommends runit && \

View File

@@ -31,7 +31,7 @@ services:
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.8.0-rc1}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.5.0-rc1}
ports:
- ${COMPOSE_PORT_HTTP:-9000}:9000
- ${COMPOSE_PORT_HTTPS:-9443}:9443
@@ -53,7 +53,7 @@ services:
AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.8.0-rc1}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2026.5.0-rc1}
restart: unless-stopped
shm_size: 512mb
user: root

Binary file not shown.

View File

@@ -25,9 +25,7 @@ Gravitee
HACS
Homarr
Informatique
Jellyseerr
Kimai
Kiota
Knoc
Knocknoc
Komodo
@@ -46,16 +44,13 @@ Organizr
Packagify
Palo
Papra
PhotoPrism
pfSense
phpipam
Planka
Plesk
PostHog
proftpd
Qube
Relatedly
Seerr
Sidero
snipeit
sonarqube
@@ -67,6 +62,7 @@ Vikunja
Wazuh
Wdio
Weixin
Kiota
Wekan
Xcreds
Zammad

Binary file not shown.

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@goauthentik/authentik",
"version": "2026.8.0-rc1",
"version": "2026.5.0-rc1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@goauthentik/authentik",
"version": "2026.8.0-rc1",
"version": "2026.5.0-rc1",
"dependencies": {
"@eslint/js": "^9.39.3",
"@goauthentik/eslint-config": "./packages/eslint-config",

View File

@@ -1,6 +1,6 @@
{
"name": "@goauthentik/authentik",
"version": "2026.8.0-rc1",
"version": "2026.5.0-rc1",
"private": true,
"scripts": {
"lint": "run-s lint:spellcheck lint:lockfile",

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/
@@ -41,7 +41,7 @@ var (
queryDescape = strings.NewReplacer("%5B", "[", "%5D", "]")
)
// APIClient manages communication with the authentik API v2026.8.0-rc1
// APIClient manages communication with the authentik API v2026.5.0-rc1
// In most cases there should be only one, shared, APIClient.
type APIClient struct {
cfg *Configuration

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

View File

@@ -3,7 +3,7 @@ authentik
Making authentication simple.
API version: 2026.8.0-rc1
API version: 2026.5.0-rc1
Contact: hello@goauthentik.io
*/

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