Compare commits

..

15 Commits

Author SHA1 Message Date
b5e0577569 Fixes indentation on text block 2025-05-08 12:11:30 +01:00
121f2c609d website/integrations: update paperless ngx instructions to include correct scopes (#14424)
* Update Paperless NGX instructions to include correct scopes

`openid` scope is required for Paperless NGX

Signed-off-by: Jim Shank <jimshank@gmail.com>

* Update website/integrations/services/paperless-ngx/index.mdx

Signed-off-by: Dewi Roberts <dewi@goauthentik.io>

---------

Signed-off-by: Jim Shank <jimshank@gmail.com>
Signed-off-by: Dewi Roberts <dewi@goauthentik.io>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-05-08 08:55:30 +00:00
365affc28e website/docs: configuration sessions are now stored by default in the database (#14425)
docs: configuration: sessions are now stored by default in the database

Signed-off-by: Dominic R <dominic@sdko.org>
2025-05-08 09:26:27 +01:00
f367822779 root: readme: use right contribution guide link (#14250)
wip

Signed-off-by: Dominic R <dominic@sdko.org>
2025-05-07 21:20:32 +00:00
848198125d website/integrations: add coder (#14385)
* init

Signed-off-by: Dominic R <dominic@sdko.org>

* init

Signed-off-by: Dominic R <dominic@sdko.org>

* wip

* what is happening to my lint today?

* Apply suggestions from code review

Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
Signed-off-by: Dominic R <dominic@sdko.org>

---------

Signed-off-by: Dominic R <dominic@sdko.org>
Co-authored-by: Dewi Roberts <dewi@goauthentik.io>
2025-05-07 20:04:34 +01:00
497ac5e3d0 website/integrations: improve grafana docs (#14408)
* Update index.mdx

Better reflected the stuff at https://github.com/goauthentik/authentik/issues/8673

Signed-off-by: andymarden <63465082+andymarden@users.noreply.github.com>

* Update website/integrations/services/grafana/index.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

* Update website/integrations/services/grafana/index.mdx

Co-authored-by: Dominic R <dominic@sdko.org>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>

---------

Signed-off-by: andymarden <63465082+andymarden@users.noreply.github.com>
Signed-off-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: Dominic R <dominic@sdko.org>
2025-05-07 12:33:42 -05:00
1773d4d681 core: bump geoip2 from 5.0.1 to v5.1.0 (#14417) 2025-05-07 19:25:14 +02:00
4edbb51939 core: bump boto3 from 1.38.7 to v1.38.10 (#14416) 2025-05-07 19:24:58 +02:00
c7e97ab48e core: bump maxminddb from 2.6.3 to v2.7.0 (#14420) 2025-05-07 19:24:44 +02:00
31f7faae1c core: bump azure-identity from 1.21.0 to v1.22.0 (#14415) 2025-05-07 19:24:31 +02:00
f5dae2ae92 core: bump google-auth from 2.39.0 to v2.40.1 (#14418) 2025-05-07 19:24:17 +02:00
2c043dba0b core: bump jsii from 1.111.0 to v1.112.0 (#14419) 2025-05-07 19:24:03 +02:00
bda10e5db1 core: bump pytest-timeout from 2.3.1 to v2.4.0 (#14421) 2025-05-07 19:23:49 +02:00
be9ae7d4f7 web: cleanup/loading attribute always true (#14288)
* web: Add InvalidationFlow to Radius Provider dialogues

## What

- Bugfix: adds the InvalidationFlow to the Radius Provider dialogues
  - Repairs: `{"invalidation_flow":["This field is required."]}` message, which was *not* propagated
    to the Notification.
- Nitpick: Pretties `?foo=${true}` expressions: `s/\?([^=]+)=\$\{true\}/\1/`

## Note

Yes, I know I'm going to have to do more magic when we harmonize the forms, and no, I didn't add the
Property Mappings to the wizard, and yes, I know I'm going to have pain with the *new* version of
the wizard. But this is a serious bug; you can't make Radius servers with *either* of the current
dialogues at the moment.

* This (temporary) change is needed to prevent the unit tests from failing.

\# What

\# Why

\# How

\# Designs

\# Test Steps

\# Other Notes

* Revert "This (temporary) change is needed to prevent the unit tests from failing."

This reverts commit dddde09be5.

* web: remove Lit syntax from always true attributes

## What

Replaces instances of `?loading=${true}` and `?loading="${true}"` with `loading`

## Why

The Lit syntax is completely unnecessary when the attribute's state is constant, and it's a few
(just a few) extra CPU cycles for Lit to process that.

More to the point, it annoys me.

## How

```
$ perl -pi.bak -e 's/\?loading=\$\{true\}/loading/' $(rg -l '\?loading=\$\{true\}')
$ find . -name '*.bak' -exec rm {} \;
$ perl -pi.bak -e 's/\?loading="\$\{true\}"/loading/' $(rg -l '\?loading="\$\{true\}"')
$ find . -name '*.bak' -exec rm {} \;
```

* Prettier had opinions

* Trigger Build
2025-05-06 08:49:48 -07:00
b4a6189bfa core: bump selenium from 4.31.0 to v4.32.0 (#14394)
* core: bump selenium from 4.31.0 to v4.32.0

* deal with selenium breaking stuff on minor versions

https://github.com/SeleniumHQ/selenium/pull/15641
Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-05-06 16:53:20 +02:00
32 changed files with 196 additions and 501 deletions

View File

@ -42,4 +42,4 @@ See [SECURITY.md](SECURITY.md)
## Adoption and Contributions
Your organization uses authentik? We'd love to add your logo to the readme and our website! Email us @ hello@goauthentik.io or open a GitHub Issue/PR! For more information on how to contribute to authentik, please refer to our [CONTRIBUTING.md file](./CONTRIBUTING.md).
Your organization uses authentik? We'd love to add your logo to the readme and our website! Email us @ hello@goauthentik.io or open a GitHub Issue/PR! For more information on how to contribute to authentik, please refer to our [contribution guide](https://docs.goauthentik.io/docs/developer-docs?utm_source=github).

View File

@ -26,6 +26,7 @@ from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, TimeoutException, WebDriverException
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.remote.command import Command
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.wait import WebDriverWait
@ -197,7 +198,12 @@ class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
super().tearDown()
if IS_CI:
print("::group::Browser logs")
for line in self.driver.get_log("browser"):
# Very verbose way to get browser logs
# https://github.com/SeleniumHQ/selenium/pull/15641
# for some reason this removes the `get_log` API from Remote Webdriver
# and only keeps it on the local Chrome web driver, even when using
# a remote chrome driver...? (nvm the fact this was released as a minor version)
for line in self.driver.execute(Command.GET_LOG, {"type": "browser"})["value"]:
print(line["message"])
if IS_CI:
print("::endgroup::")

76
uv.lock generated
View File

@ -461,7 +461,7 @@ wheels = [
[[package]]
name = "azure-identity"
version = "1.21.0"
version = "1.22.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "azure-core" },
@ -470,9 +470,9 @@ dependencies = [
{ name = "msal-extensions" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b5/a1/f1a683672e7a88ea0e3119f57b6c7843ed52650fdcac8bfa66ed84e86e40/azure_identity-1.21.0.tar.gz", hash = "sha256:ea22ce6e6b0f429bc1b8d9212d5b9f9877bd4c82f1724bfa910760612c07a9a6", size = 266445, upload-time = "2025-03-11T20:53:07.463Z" }
sdist = { url = "https://files.pythonhosted.org/packages/58/8e/1b5916f5e1696bf05b009cf7d41383cea54aa8536d4a4f6f88cca15eb6a4/azure_identity-1.22.0.tar.gz", hash = "sha256:c8f5ef23e5295c2fa300c984dd9f5e1fe43503fc25c121c37ff6a15e39b800b9", size = 263346, upload-time = "2025-05-06T20:22:24.13Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3d/9f/1f9f3ef4f49729ee207a712a5971a9ca747f2ca47d9cbf13cf6953e3478a/azure_identity-1.21.0-py3-none-any.whl", hash = "sha256:258ea6325537352440f71b35c3dffe9d240eae4a5126c1b7ce5efd5766bd9fd9", size = 189190, upload-time = "2025-03-11T20:53:09.197Z" },
{ url = "https://files.pythonhosted.org/packages/06/1a/6f13d7f95f68f37303c0e00e011d498e4524e70d354b2e11ef5ae89e0ce0/azure_identity-1.22.0-py3-none-any.whl", hash = "sha256:26d6c63f2ca453c77c3e74be8613941ad074e05d0c8be135247573752c249ad8", size = 185524, upload-time = "2025-05-06T20:22:25.991Z" },
]
[[package]]
@ -571,30 +571,30 @@ wheels = [
[[package]]
name = "boto3"
version = "1.38.8"
version = "1.38.10"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "botocore" },
{ name = "jmespath" },
{ name = "s3transfer" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b1/8e/bf339382eaff15b3575d23b2b6f06769765001234c2ccaafa50a20931379/boto3-1.38.8.tar.gz", hash = "sha256:6bbc75bb51be9c5a33d07a4adf13d133c60f77b7c47bef1c46fda90b1297a867", size = 111798, upload-time = "2025-05-03T00:18:45.139Z" }
sdist = { url = "https://files.pythonhosted.org/packages/5f/26/c4a2f1c64efb5ae6b47b94cb543282ab5770aa2c4562aba6934af628cf76/boto3-1.38.10.tar.gz", hash = "sha256:af4c78a3faa1a56cbaeb9e06cd5580772138be519fc6e740b81db586d5d1910c", size = 111837, upload-time = "2025-05-06T19:29:55.088Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/84/d9/1bd6c2a6c3d3bf1d8b0be52c39230bd1e14bb55b7ecc04f42fcb68b27343/boto3-1.38.8-py3-none-any.whl", hash = "sha256:f3a4d79f499f567d327d2d8846d02ad18244d2927f88858a42a2438f52d9a0ef", size = 139899, upload-time = "2025-05-03T00:18:42.787Z" },
{ url = "https://files.pythonhosted.org/packages/2f/fe/2b69dcdd433c32ba80b36eabfe799e8c3e0b08ff3e0fc06bc2e1cc065a19/boto3-1.38.10-py3-none-any.whl", hash = "sha256:26113a47d549bc3c46dbf56c8ab74f272c3da55df23e2c460fcf3c6c64d54dce", size = 139911, upload-time = "2025-05-06T19:29:51.823Z" },
]
[[package]]
name = "botocore"
version = "1.38.8"
version = "1.38.10"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "jmespath" },
{ name = "python-dateutil" },
{ name = "urllib3" },
]
sdist = { url = "https://files.pythonhosted.org/packages/1e/18/1ec9220e180106d8055365a9bb4926db9840211c65f5fd70a5a90b0873cf/botocore-1.38.8.tar.gz", hash = "sha256:68d739300cc94232373517b27c5570de6ae6d809a2db644f30219f5c8e0371ce", size = 13871026, upload-time = "2025-05-03T00:18:32.427Z" }
sdist = { url = "https://files.pythonhosted.org/packages/c0/18/c03b763c831e269d76a7c0fcba53802f99bf68f8d4530af672ae96a6d343/botocore-1.38.10.tar.gz", hash = "sha256:c531c13803e0fad5b395c5ccab4c11ac88acfccde71c9b998df6fa841392a8fc", size = 13881598, upload-time = "2025-05-06T19:29:41.315Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b4/66/e5a314d1e868cd35ec5c5d11360387c2a85e8d408f084616337f1a282c61/botocore-1.38.8-py3-none-any.whl", hash = "sha256:f6ae08a56fe94e18d2aa223611a3b5e94123315d0cb3cb85764b029b2326c710", size = 13531917, upload-time = "2025-05-03T00:18:26.389Z" },
{ url = "https://files.pythonhosted.org/packages/f9/92/2c522e277c95d35b4b83bff6a3839875d91b0d835a93545828a7046013c4/botocore-1.38.10-py3-none-any.whl", hash = "sha256:5244454bb9e8fbb6510145d1554e82fd243e8583507d83077ecf4f8efb66cb46", size = 13539530, upload-time = "2025-05-06T19:29:35.384Z" },
]
[[package]]
@ -1354,16 +1354,16 @@ wheels = [
[[package]]
name = "geoip2"
version = "5.0.1"
version = "5.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
{ name = "maxminddb" },
{ name = "requests" },
]
sdist = { url = "https://files.pythonhosted.org/packages/17/d7/21cfa1072b8ec5937c6af0cf8b624b4be9b44a7ca82f4335900df5482076/geoip2-5.0.1.tar.gz", hash = "sha256:90af8b6d3687f3bef251f2708ad017b30d627d1144c0040eabc4c9017a807d86", size = 175854, upload-time = "2025-01-28T23:22:04.689Z" }
sdist = { url = "https://files.pythonhosted.org/packages/0f/5f/902835f485d1c423aca9097a0e91925d6a706049f64e678ec781b168734d/geoip2-5.1.0.tar.gz", hash = "sha256:ee3f87f0ce9325eb6484fe18cbd9771a03d0a2bad1dd156fa3584fafa562d39a", size = 268166, upload-time = "2025-05-05T19:40:29.202Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/0f/6c/4f17beb65444cd0b8e602c2ea64ef1ec8ff32e1aa8c6a3be3fad7113b947/geoip2-5.0.1-py3-none-any.whl", hash = "sha256:128b7c9e6b55fb66178428a9400bd4f8b011cf64f147b1ed9e3a4766e61a9b78", size = 28064, upload-time = "2025-01-28T23:22:01.662Z" },
{ url = "https://files.pythonhosted.org/packages/eb/43/aa9a10d0c971d0a0e353111a97913357f9271fb9a9867ec1053f79ca61be/geoip2-5.1.0-py3-none-any.whl", hash = "sha256:445a058995ad5bb3e665ae716413298d4383b1fb38d372ad59b9b405f6b0ca19", size = 27691, upload-time = "2025-05-05T19:40:26.082Z" },
]
[[package]]
@ -1412,16 +1412,16 @@ wheels = [
[[package]]
name = "google-auth"
version = "2.39.0"
version = "2.40.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cachetools" },
{ name = "pyasn1-modules" },
{ name = "rsa" },
]
sdist = { url = "https://files.pythonhosted.org/packages/cb/8e/8f45c9a32f73e786e954b8f9761c61422955d23c45d1e8c347f9b4b59e8e/google_auth-2.39.0.tar.gz", hash = "sha256:73222d43cdc35a3aeacbfdcaf73142a97839f10de930550d89ebfe1d0a00cde7", size = 274834, upload-time = "2025-04-14T17:44:49.402Z" }
sdist = { url = "https://files.pythonhosted.org/packages/94/a5/38c21d0e731bb716cffcf987bd9a3555cb95877ab4b616cfb96939933f20/google_auth-2.40.1.tar.gz", hash = "sha256:58f0e8416a9814c1d86c9b7f6acf6816b51aba167b2c76821965271bac275540", size = 280975, upload-time = "2025-05-07T01:04:55.3Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ce/12/ad37a1ef86006d0a0117fc06a4a00bd461c775356b534b425f00dde208ea/google_auth-2.39.0-py2.py3-none-any.whl", hash = "sha256:0150b6711e97fb9f52fe599f55648950cc4540015565d8fbb31be2ad6e1548a2", size = 212319, upload-time = "2025-04-14T17:44:47.699Z" },
{ url = "https://files.pythonhosted.org/packages/a1/b1/1272c6e80847ba5349f5ccb7574596393d1e222543f5003cb810865c3575/google_auth-2.40.1-py2.py3-none-any.whl", hash = "sha256:ed4cae4f5c46b41bae1d19c036e06f6c371926e97b19e816fc854eff811974ee", size = 216101, upload-time = "2025-05-07T01:04:53.612Z" },
]
[[package]]
@ -1680,7 +1680,7 @@ wheels = [
[[package]]
name = "jsii"
version = "1.111.0"
version = "1.112.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
@ -1691,9 +1691,9 @@ dependencies = [
{ name = "typeguard" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/29/e0/f1edbe7adb75c58ef13f4b24a8f2521cc3f7f5bd79751d071900065cf0a7/jsii-1.111.0.tar.gz", hash = "sha256:db523ab9b6575c84d6ed8779cdbdc739abd48a7cb0723b66beb84c1a9dc31c7c", size = 624365, upload-time = "2025-04-02T16:35:49.643Z" }
sdist = { url = "https://files.pythonhosted.org/packages/ad/3e/270b5236035fc7bb2cdd7f55ea25f85489d35d971870cbec32c3d9e99d7f/jsii-1.112.0.tar.gz", hash = "sha256:6b7d19f361c2565b76828ecbe8cbed8b8d6028a82aa98a46b206a4ee5083157e", size = 624533, upload-time = "2025-05-07T14:45:52.574Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3c/8a/d3a80a0b0ecb2c175eacbe48542695213ef4315b2e6bd62bafd244c06ae0/jsii-1.111.0-py3-none-any.whl", hash = "sha256:3084e31173e73d2eefee678c8ee31aa49428830509043057a421a4c0dde94434", size = 600503, upload-time = "2025-04-02T16:35:48.153Z" },
{ url = "https://files.pythonhosted.org/packages/44/af/8554b632e2b82f37a7422782aba5db2a1fbff4887faa7ec850818def8407/jsii-1.112.0-py3-none-any.whl", hash = "sha256:6510c223074d9b206fd0570849a791e4d9ecfff7ffe68428de73870cea9f55a1", size = 600681, upload-time = "2025-05-07T14:45:51.136Z" },
]
[[package]]
@ -1881,20 +1881,24 @@ wheels = [
[[package]]
name = "maxminddb"
version = "2.6.3"
version = "2.7.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/57/ae/422ec0f3b6a40f23de9477c42fce90126a3994dd51d06b50582973c0088e/maxminddb-2.6.3.tar.gz", hash = "sha256:d2c3806baa7aa047aa1bac7419e7e353db435f88f09d51106a84dbacf645d254", size = 181376, upload-time = "2025-01-09T16:12:13.7Z" }
sdist = { url = "https://files.pythonhosted.org/packages/d1/10/7a7cf5219b74b19ea1834b43256e114564e8a845f447446ac821e1b9951e/maxminddb-2.7.0.tar.gz", hash = "sha256:23a715ed3b3aed07adae4beeed06c51fd582137b5ae13d3c6e5ca4890f70ebbf", size = 196583, upload-time = "2025-05-05T19:31:43.957Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/e3/a3218d7cd35c930a08f7d7301334f9c85aa0a28dbac3f50e3d43f3d70734/maxminddb-2.6.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9580b2cd017185db07baacd9d629ca01f3fe6f236528681c88a0209725376e9c", size = 35235, upload-time = "2025-01-09T16:10:57.614Z" },
{ url = "https://files.pythonhosted.org/packages/85/40/11f23d1c1f6654618d87e995f56a789f00c1c07d5c986f9b14d81f04f90c/maxminddb-2.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:47828bed767b82c219ba7aa65f0cb03d7f7443d7270259ce931e133a40691d34", size = 35021, upload-time = "2025-01-09T16:10:58.692Z" },
{ url = "https://files.pythonhosted.org/packages/68/7e/883adcb107fb45916328ecb40f980cc598dbcc7dfd2ccc871851c40836d6/maxminddb-2.6.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77112cb1a2e381de42c443d1bf222c58b9da203183bb2008dd370c3d2a587a4e", size = 90068, upload-time = "2025-01-09T16:10:59.874Z" },
{ url = "https://files.pythonhosted.org/packages/2c/87/b57cf9ef4cf8b076f3b25df949b57c7b3ee0f4543f1f76f445afd313b96b/maxminddb-2.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:448d062e95242e3088df85fe7ed3f2890a9f4aea924bde336e9ff5d2337ca5fd", size = 89506, upload-time = "2025-01-09T16:11:01.057Z" },
{ url = "https://files.pythonhosted.org/packages/ff/f8/cf746032f267ee25bd32f70d71a63e857fec91e19a0907db885bdbb7b0c1/maxminddb-2.6.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a59d72bf373c61da156fd43e2be6da802f68370a50a2205de84ee76916e05f9f", size = 87612, upload-time = "2025-01-09T16:11:02.362Z" },
{ url = "https://files.pythonhosted.org/packages/c0/9e/ff5c93e8e589c1544cad2a457c1b7e4169a256c8655928266a9de6f21cac/maxminddb-2.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e867852037a8a26a24cfcf31b697dce63d488e1617af244c2895568d8f6c7a31", size = 92310, upload-time = "2025-01-09T16:11:03.619Z" },
{ url = "https://files.pythonhosted.org/packages/99/44/56ed56377ba8c99f7eb3101479c063d46f18e5f0a9070432d74a2ed15f82/maxminddb-2.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5a1586260eac831d61c2665b26ca1ae3ad00caca57c8031346767f4527025311", size = 91227, upload-time = "2025-01-09T16:11:04.943Z" },
{ url = "https://files.pythonhosted.org/packages/9b/58/cdb1a7c18a1946ad006657b52cb499e489d2b28a62490fd5aee14b356a55/maxminddb-2.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6eb23f842a72ab3096f9f9b1c292f4feb55a8d758567cb6d77637c2257a3187c", size = 92126, upload-time = "2025-01-09T16:11:06.149Z" },
{ url = "https://files.pythonhosted.org/packages/39/94/4b37ffa77f8921a549805a62ce62f6fa453ea3c59c0dfcd584770fc59a8c/maxminddb-2.6.3-cp313-cp313-win32.whl", hash = "sha256:acf46e20709a27d2b519669888e3f53a37bc4204b98a0c690664c48ff8cb1364", size = 34751, upload-time = "2025-01-09T16:11:09.017Z" },
{ url = "https://files.pythonhosted.org/packages/1e/af/638811134e1a33cf75c2d2be1b0b9b90dd1f43216a4ef1f24e223f646b46/maxminddb-2.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:3015afb00e6168837938dbe5fda40ace37442c22b292ccee27c1690fbf6078ed", size = 36790, upload-time = "2025-01-09T16:11:10.093Z" },
{ url = "https://files.pythonhosted.org/packages/8f/0e/68a558e11e8a2aaeb1b28be27c784052dcccd780175fa9e3d2693274e8d6/maxminddb-2.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2328575e2d2ab6179acf93c09745e9af10eb92aaa305cb5bd0f7c307d0dd398e", size = 35328, upload-time = "2025-05-05T19:30:35.134Z" },
{ url = "https://files.pythonhosted.org/packages/75/ff/2c98dda0d0aaa09dbe9a4030bd9ab056e0bf6c6559215e34185e2fd62d50/maxminddb-2.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c4f71a72f3dbdc2abd58c36ad0ad4bd936781354feee8538614d2170223675f0", size = 35098, upload-time = "2025-05-05T19:30:36.259Z" },
{ url = "https://files.pythonhosted.org/packages/9a/cb/99d1650daa24a9acb55c81412fcefa5d95b7e80a872876a902e14f33ec4d/maxminddb-2.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:566e7ea8296ad126a24df52e6c37382dc9660c414ceea4c4c687bbca2d522c28", size = 90193, upload-time = "2025-05-05T19:30:37.325Z" },
{ url = "https://files.pythonhosted.org/packages/c0/15/53ceb43e1e1e7493a66fb9a3b2d3248198316d2dbe746c585591276f1aad/maxminddb-2.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c10d94df0d5ea22873a5dc1af24d8972de0a22841dbd90a7e450f66a6f11ed21", size = 94695, upload-time = "2025-05-05T19:30:38.528Z" },
{ url = "https://files.pythonhosted.org/packages/2c/d7/e26d168d85e2503232d5df2a847641024afd11405fd5132816728cc9e399/maxminddb-2.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7f0e9a4db3c986f208dd4359e9d9e776e28ce8aae540da6f1a733fae3bb67ac", size = 91306, upload-time = "2025-05-05T19:30:40.078Z" },
{ url = "https://files.pythonhosted.org/packages/b5/b5/4bb9330ee29efb0c515cb8c6c500f367021c163ebb81380789e6ac846f8b/maxminddb-2.7.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef41949246035af8cb5970bee2e94bbc894203312fd6fb55cbd4fe30c6e44374", size = 89620, upload-time = "2025-05-05T19:30:41.279Z" },
{ url = "https://files.pythonhosted.org/packages/72/e5/1335e42615b57fd821a6c606119cb4babd85bc88839f8dbae0b5bb082d04/maxminddb-2.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:531be1066697b57928bce2ac9cb7e705b8cebdfa2e42dfbebc92b75fc53ad22f", size = 87751, upload-time = "2025-05-05T19:30:42.464Z" },
{ url = "https://files.pythonhosted.org/packages/b2/9a/af47d3f7a15a49be61315f29bb0e232c1f5040f3afc685509cee1ebdaef7/maxminddb-2.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:265e938c12628fceb71665e28bfca206ee9d8ae6ac18282cbfc544753ccc8b9b", size = 93328, upload-time = "2025-05-05T19:30:43.697Z" },
{ url = "https://files.pythonhosted.org/packages/2f/43/ecda2cc5a7ffae034692374401f97c3ef8fe15f22826ae2784b38ecf0cfd/maxminddb-2.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7b101cf6b79db4c046c9c9b157bb9730308074749c442f50d52a7a0e5d765357", size = 91701, upload-time = "2025-05-05T19:30:44.83Z" },
{ url = "https://files.pythonhosted.org/packages/3c/14/8edd17bdeaddd9d7d138008d6fc14baacdda418a5346d09215d14870dfd2/maxminddb-2.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:faecf825f812d54e1cb053e75358656b280af1ea4b6f53b3f1a98c3f9fa41a46", size = 98466, upload-time = "2025-05-05T19:30:46.041Z" },
{ url = "https://files.pythonhosted.org/packages/d4/6f/cefabf7868b5406f4df04c3f4cb95dc802c1ad1b05f26046a4584a235268/maxminddb-2.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:dd266b3060bb6b6b05009b04ca93787fab0a00f16638827d34bab50cfdf68dd4", size = 96255, upload-time = "2025-05-05T19:30:47.785Z" },
{ url = "https://files.pythonhosted.org/packages/6f/4a/f604c942dc9d3e755601831ee101198d3090c0dfa5485e2aaf3245075bf3/maxminddb-2.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f30bdd4c618c372c0f4f981f2241aad8e3ab9c361bb1d299f213e9a4c2a3fd8", size = 92190, upload-time = "2025-05-05T19:30:49.052Z" },
{ url = "https://files.pythonhosted.org/packages/ba/6f/563058bc28704b24fa04830acc40abca03debcaa2a12195d8269b490475b/maxminddb-2.7.0-cp313-cp313-win32.whl", hash = "sha256:023f23654b38345965cab3e33465a4b82edb2250ba7c6db5c175a872645c35c5", size = 34699, upload-time = "2025-05-05T19:30:50.202Z" },
{ url = "https://files.pythonhosted.org/packages/e8/84/33e0389d97ca9bc7e902c1f4a74e626349043c942ba0b6458fa96cbea0a8/maxminddb-2.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:f81d678ab25d4867f95fb44cce3c67f6157d25dc8846191fd4eb0e38f49a263f", size = 36723, upload-time = "2025-05-05T19:30:51.799Z" },
]
[[package]]
@ -2666,14 +2670,14 @@ wheels = [
[[package]]
name = "pytest-timeout"
version = "2.3.1"
version = "2.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/93/0d/04719abc7a4bdb3a7a1f968f24b0f5253d698c9cc94975330e9d3145befb/pytest-timeout-2.3.1.tar.gz", hash = "sha256:12397729125c6ecbdaca01035b9e5239d4db97352320af155b3f5de1ba5165d9", size = 17697, upload-time = "2024-03-07T21:04:01.069Z" }
sdist = { url = "https://files.pythonhosted.org/packages/ac/82/4c9ecabab13363e72d880f2fb504c5f750433b2b6f16e99f4ec21ada284c/pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a", size = 17973, upload-time = "2025-05-05T19:44:34.99Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/03/27/14af9ef8321f5edc7527e47def2a21d8118c6f329a9342cc61387a0c0599/pytest_timeout-2.3.1-py3-none-any.whl", hash = "sha256:68188cb703edfc6a18fad98dc25a3c61e9f24d644b0b70f33af545219fc7813e", size = 14148, upload-time = "2024-03-07T21:03:58.764Z" },
{ url = "https://files.pythonhosted.org/packages/fa/b6/3127540ecdf1464a00e5a01ee60a1b09175f6913f0644ac748494d9c4b21/pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2", size = 14382, upload-time = "2025-05-05T19:44:33.502Z" },
]
[[package]]
@ -2919,7 +2923,7 @@ wheels = [
[[package]]
name = "selenium"
version = "4.31.0"
version = "4.32.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "certifi" },
@ -2929,9 +2933,9 @@ dependencies = [
{ name = "urllib3", extra = ["socks"] },
{ name = "websocket-client" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e0/bf/642cce8b5a9edad8e4880fdefbeb24f69bec2086b1121c63f883c412b797/selenium-4.31.0.tar.gz", hash = "sha256:441cffc436a2e6659fe3cfb012692435652efd38b0d368d16f661a5db47825f5", size = 855418, upload-time = "2025-04-05T00:43:06.447Z" }
sdist = { url = "https://files.pythonhosted.org/packages/54/2d/fafffe946099033ccf22bf89e12eede14c1d3c5936110c5f6f2b9830722c/selenium-4.32.0.tar.gz", hash = "sha256:b9509bef4056f4083772abb1ae19ff57247d617a29255384b26be6956615b206", size = 870997, upload-time = "2025-05-02T20:35:27.325Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/32/53/212db779d2481b0a8428365960596f8d5a4d482ae12c441d0507fd54aaf2/selenium-4.31.0-py3-none-any.whl", hash = "sha256:7b8b8d5e424d7133cb7aa656263b19ac505ec26d65c0f921a696e7e2c5ccd95b", size = 9350584, upload-time = "2025-04-05T00:43:04.04Z" },
{ url = "https://files.pythonhosted.org/packages/ea/37/d07ed9d13e571b2115d4ed6956d156c66816ceec0b03b2e463e80d09f572/selenium-4.32.0-py3-none-any.whl", hash = "sha256:c4d9613f8a45693d61530c9660560fadb52db7d730237bc788ddedf442391f97", size = 9369668, upload-time = "2025-05-02T20:35:24.726Z" },
]
[[package]]

View File

@ -113,8 +113,7 @@ export class ApplicationViewPage extends AKElement {
renderApp(): TemplateResult {
if (!this.application) {
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
</ak-empty-state>`;
return html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`;
}
return html`<ak-tabs>
${this.missingOutpost

View File

@ -42,7 +42,7 @@ export class ProviderViewPage extends AKElement {
renderProvider(): TemplateResult {
if (!this.provider) {
return html`<ak-empty-state ?loading=${true} ?fullHeight=${true}></ak-empty-state>`;
return html`<ak-empty-state loading ?fullHeight=${true}></ak-empty-state>`;
}
switch (this.provider?.component) {
case "ak-provider-saml-form":

View File

@ -432,7 +432,7 @@ export class OAuth2ProviderViewPage extends AKElement {
<div class="pf-c-card__body">
${this.preview
? html`<pre>${JSON.stringify(this.preview?.preview, null, 4)}</pre>`
: html` <ak-empty-state ?loading=${true}></ak-empty-state> `}
: html` <ak-empty-state loading></ak-empty-state> `}
</div>
</div>
</div>`;

View File

@ -502,7 +502,7 @@ export class SAMLProviderViewPage extends AKElement {
renderTabPreview(): TemplateResult {
if (!this.preview) {
return html`<ak-empty-state ?loading=${true}></ak-empty-state>`;
return html`<ak-empty-state loading></ak-empty-state>`;
}
return html` <div
class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter"

View File

@ -34,7 +34,7 @@ export class SourceViewPage extends AKElement {
renderSource(): TemplateResult {
if (!this.source) {
return html`<ak-empty-state ?loading=${true} ?fullHeight=${true}></ak-empty-state>`;
return html`<ak-empty-state loading ?fullHeight=${true}></ak-empty-state>`;
}
switch (this.source?.component) {
case "ak-source-kerberos-form":

View File

@ -83,7 +83,7 @@ export class Diagram extends AKElement {
}
});
if (!this.diagram) {
return html`<ak-empty-state ?loading=${true}></ak-empty-state>`;
return html`<ak-empty-state loading></ak-empty-state>`;
}
return html`${until(
mermaid.render("graph", this.diagram).then((r) => {

View File

@ -230,9 +230,7 @@ export abstract class AKChart<T> extends AKElement {
<p slot="body">${pluckErrorDetail(this.error)}</p>
</ak-empty-state>
`
: html`${this.chart
? html``
: html`<ak-empty-state ?loading="${true}"></ak-empty-state>`}`}
: html`${this.chart ? html`` : html`<ak-empty-state loading></ak-empty-state>`}`}
${this.centerText ? html` <span>${this.centerText}</span> ` : html``}
<canvas style="${this.chart === undefined ? "display: none;" : ""}"></canvas>
</div>

View File

@ -71,7 +71,7 @@ export abstract class ModelForm<T, PKT extends string | number> extends Form<T>
renderVisible(): TemplateResult {
if ((this._instancePk && !this.instance) || !this._initialDataLoad) {
return html`<ak-empty-state ?loading=${true}></ak-empty-state>`;
return html`<ak-empty-state loading></ak-empty-state>`;
}
return super.renderVisible();
}

View File

@ -51,7 +51,7 @@ export class Route {
if (this.callback) {
return html`${until(
this.callback(args),
html`<ak-empty-state ?loading=${true}></ak-empty-state>`,
html`<ak-empty-state loading></ak-empty-state>`,
)}`;
}
if (this.element) {

View File

@ -121,7 +121,7 @@ export class SyncStatusCard extends AKElement {
renderSyncStatus(): TemplateResult {
if (this.loading) {
return html`<ak-empty-state ?loading=${true}></ak-empty-state>`;
return html`<ak-empty-state loading></ak-empty-state>`;
}
if (!this.syncState) {
return html`${msg("No sync status.")}`;

View File

@ -19,7 +19,7 @@ describe("ak-empty-state", () => {
});
it("should render the default loader", async () => {
render(html`<ak-empty-state ?loading=${true} header=${msg("Loading")}> </ak-empty-state>`);
render(html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`);
const empty = await $("ak-empty-state").$(">>>.pf-c-empty-state__icon");
await expect(empty).toExist();

View File

@ -139,8 +139,7 @@ export class UserSourceSettingsPage extends AKElement {
})}
`}
`
: html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
</ak-empty-state>`}
: html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`}
</ul>`;
}
}

View File

@ -24,8 +24,7 @@ export class SessionEnd extends BaseStage<SessionEndChallenge, unknown> {
render(): TemplateResult {
if (!this.challenge) {
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
</ak-empty-state>`;
return html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`;
}
return html`<header class="pf-c-login__main-header">
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>

View File

@ -102,7 +102,7 @@ export class LibraryPage extends AKElement {
}
loading() {
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}> </ak-empty-state>`;
return html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`;
}
running() {

View File

@ -173,8 +173,7 @@ export class UserSettingsFlowExecutor
level: MessageLevel.success,
message: msg("Successfully updated details"),
});
return html`<ak-empty-state ?loading=${true} header=${msg("Loading")}>
</ak-empty-state>`;
return html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`;
default:
console.debug(
`authentik/user/flows: unsupported stage type ${this.challenge.component}`,
@ -195,8 +194,7 @@ export class UserSettingsFlowExecutor
return html`<p>${msg("No settings flow configured.")}</p> `;
}
if (!this.challenge || this.loading) {
return html`<ak-empty-state ?loading=${true} header=${msg("Loading")}>
</ak-empty-state>`;
return html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`;
}
return html` ${this.renderChallenge()} `;
}

View File

@ -64,8 +64,7 @@ export class UserSettingsPromptStage extends PromptStage {
render(): TemplateResult {
if (!this.challenge) {
return html`<ak-empty-state ?loading="${true}" header=${msg("Loading")}>
</ak-empty-state>`;
return html`<ak-empty-state loading header=${msg("Loading")}> </ak-empty-state>`;
}
return html`<div class="pf-c-login__main-body">
<form

View File

@ -356,7 +356,7 @@ Defaults to `86400`.
### `AUTHENTIK_SESSION_STORAGE`:ak-version[2024.4]
Configure if the sessions are stored in the cache or the database. Defaults to `cache`. Allowed values are `cache` and `db`. Note that changing this value will invalidate all previous sessions.
Configure if the sessions are stored in the cache or the database. Defaults to `db`. Allowed values are `cache` and `db`. Note that changing this value will invalidate all previous sessions.
### `AUTHENTIK_SESSIONS__UNAUTHENTICATED_AGE`:ak-version[2025.4]

View File

@ -4,12 +4,9 @@
* @import * as Preset from "@docusaurus/preset-classic";
* @import * as OpenApiPlugin from "docusaurus-plugin-openapi-docs";
* @import { BuildUrlValues } from "remark-github";
* @import { ReleasesPluginOptions } from "./releases/plugin.mjs"
*/
import { createDocusaurusConfig } from "@goauthentik/docusaurus-config";
import { createRequire } from "node:module";
import * as path from "node:path";
import { fileURLToPath } from "node:url";
import remarkDirective from "remark-directive";
import remarkGithub, { defaultBuildUrl } from "remark-github";
@ -18,7 +15,6 @@ import remarkPreviewDirective from "./remark/preview-directive.mjs";
import remarkSupportDirective from "./remark/support-directive.mjs";
import remarkVersionDirective from "./remark/version-directive.mjs";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const require = createRequire(import.meta.url);
/**
@ -135,12 +131,6 @@ const config = createDocusaurusConfig({
],
],
plugins: [
[
"./releases/plugin.mjs",
/** @type {ReleasesPluginOptions} */ ({
docsDirectory: path.join(__dirname, "docs"),
}),
],
[
"@docusaurus/plugin-content-docs",
{

View File

@ -0,0 +1,62 @@
---
title: Integrate with Coder
sidebar_label: Coder
support_level: community
---
## What is Coder
> Coder is an open-source platform that provides browser-based cloud development environments, enabling developers and teams to securely write, edit, and manage code remotely without the need for local setup
>
> -- https://coder.com
## Preparation
The following placeholders are used in this guide:
- `coder.company` is the FQDN of your Coder installation.
- `authentik.company` is the FQDN of the authentik installation.
:::note
This documentation lists only the settings that you need to change from their default values. Be aware that any changes other than those explicitly mentioned in this guide could cause issues accessing your application.
:::
## authentik configuration
To support the integration of Coder with authentik, you need to create an application/provider pair in authentik.
### Create an application and provider in authentik
1. Log in to authentik as an admin, and open the authentik Admin interface.
2. Navigate to **Applications** > **Applications** and click **Create with Provider** to create an application and provider pair. (Alternatively you can first create a provider separately, then create the application and connect it with the provider.)
- **Application**: provide a descriptive name, an optional group for the type of application, the policy engine mode, and optional UI settings.
- **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type.
- **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations.
- Note the **Client ID**,**Client Secret**, and **slug** values because they will be required later.
- Set a `Strict` redirect URI to `https://coder.company/api/v2/users/oidc/callback`.
- Select any available signing key.
- **Configure Bindings** _(optional)_: you can 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.
## Coder configuration
To support the integration of Coder with authentik, add the following environment variables to your Coder deployment:
```yaml showLineNumbers
CODER_OIDC_ISSUER_URL=https://authentik.company/application/o/<application slug>/
CODER_OIDC_EMAIL_DOMAIN=acme.company,acme-corp.company
CODER_OIDC_CLIENT_ID=<Client ID from authentik>
CODER_OIDC_CLIENT_SECRET=<Client secret from authentik>
CODER_OIDC_SIGN_IN_TEXT=Log in with authentik
CODER_OIDC_ICON_URL=https://authentik.company/static/dist/assets/icons/icon.png
```
## Resources
- [Coder OIDC authentication documentatiom](https://coder.com/docs/admin/users/oidc-auth/)
## Configuration verification
To confirm that authentik is properly configured with Coder, log out and attempt to log back in by clicking **Log in with authentik**.

View File

@ -129,6 +129,8 @@ environment:
GF_AUTH_OAUTH_AUTO_LOGIN: "true"
# Optionally map user groups to Grafana roles
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH: "contains(groups, 'Grafana Admins') && 'Admin' || contains(groups, 'Grafana Editors') && 'Editor' || 'Viewer'"
# Required if Grafana is running behind a reverse proxy
GF_SERVER_ROOT_URL: "https://grafana.company"
```
</TabItem>
@ -194,7 +196,8 @@ For more information on group/role mappings, see [Grafana's docs](https://grafan
### Grafana Configuration Considerations
Make sure in your configuration that `root_url` is set correctly, otherwise your redirect url might get processed incorrectly. For example, if your grafana instance is running on the default configuration and is accessible behind a reverse proxy at `https://grafana.company`, your redirect url will end up looking like this, `https://grafana.company/`.
To ensure redirects work correctly in Grafana, make sure the `root_url` in your configuration accurately reflects how users access Grafana through your reverse proxy. For example, if your Grafana instance is behind a proxy and accessed at `https://grafana.company`, set `root_url` to `https://grafana.company`. This ensures that OAuth and other redirects use the correct URL, such as `https://grafana.company/login/generic_oauth`, instead of defaulting to something like `localhost:3000`.
If you get `user does not belong to org` error when trying to log into grafana for the first time via OAuth, check if you have an organization with the ID of `1`, if not, then you have to add the following to your grafana config:
```ini

View File

@ -36,6 +36,8 @@ To support the integration of Paperless-ngx with authentik, you need to create a
- Note the **Client ID**,**Client Secret**, and **slug** values because they will be required later.
- Set a `Strict` redirect URI to <kbd>https://<em>paperless.company</em>/accounts/oidc/authentik/login/callback/</kbd>.
- **Configure Bindings** _(optional)_: you can 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.
- **Advanced protocol settings**:
- **Selected Scopes**: Additionally select the `authentik default OAuth Mapping: OpenID 'openid'` scope.
3. Click **Submit** to save the new application and provider.

View File

@ -1,64 +0,0 @@
/**
* @file Docusaurus releases plugin.
*
* @import { LoadContext, Plugin } from "@docusaurus/types"
*/
import * as fs from "node:fs/promises";
import * as path from "node:path";
import { collectReleaseFiles } from "./utils.mjs";
const PLUGIN_NAME = "ak-releases-plugin";
const RELEASES_FILENAME = "releases.gen.json";
/**
* @typedef {object} ReleasesPluginOptions
* @property {string} docsDirectory The path to the documentation directory.
*/
/**
* @typedef {object} AKReleasesPluginData
* @property {string} publicPath The URL to the plugin's public directory.
* @property {string[]} releases The available versions of the documentation.
*/
/**
* @param {LoadContext} loadContext
* @param {ReleasesPluginOptions} options
* @returns {Promise<Plugin<AKReleasesPluginData>>}
*/
async function akReleasesPlugin(loadContext, { docsDirectory }) {
return {
name: PLUGIN_NAME,
async loadContent() {
console.log(`🚀 ${PLUGIN_NAME} loaded`);
const releases = collectReleaseFiles(docsDirectory).map((release) => release.name);
const outputPath = path.join(loadContext.siteDir, "static", RELEASES_FILENAME);
await fs.mkdir(path.dirname(outputPath), { recursive: true });
await fs.writeFile(outputPath, JSON.stringify(releases, null, 2), "utf-8");
console.log(`${RELEASES_FILENAME} generated`);
/**
* @type {AKReleasesPluginData}
*/
const content = {
releases,
publicPath: path.join("/", RELEASES_FILENAME),
};
return content;
},
contentLoaded({ content, actions }) {
const { setGlobalData } = actions;
setGlobalData(content);
},
};
}
export default akReleasesPlugin;

View File

@ -1,69 +0,0 @@
/**
* @file Docusaurus release utils.
*
* @import { SidebarItemConfig } from "@docusaurus/plugin-content-docs-types"
*/
import FastGlob from "fast-glob";
import * as path from "node:path";
import { coerce } from "semver";
/**
*
* @param {string} releasesParentDirectory
* @returns {FastGlob.Entry[]}
*/
export function collectReleaseFiles(releasesParentDirectory) {
const releaseFiles = FastGlob.sync("releases/**/v*.{md,mdx}", {
cwd: releasesParentDirectory,
onlyFiles: true,
objectMode: true,
})
.map((fileEntry) => {
return {
...fileEntry,
path: fileEntry.path.replace(/\.mdx?$/, ""),
name: fileEntry.name.replace(/^v/, "").replace(/\.mdx?$/, ""),
};
})
.sort((a, b) => {
const aSemVer = coerce(a.name);
const bSemVer = coerce(b.name);
if (aSemVer && bSemVer) {
return bSemVer.compare(aSemVer);
}
return b.name.localeCompare(a.name);
});
return releaseFiles;
}
export const SUPPORTED_RELEASE_COUNT = 3;
/**
*
* @param {FastGlob.Entry[]} releaseFiles
*/
export function createReleaseSidebarEntries(releaseFiles) {
/**
* @type {SidebarItemConfig[]}
*/
let sidebarEntries = releaseFiles.map((fileEntry) => {
return path.join(fileEntry.path);
});
if (releaseFiles.length > SUPPORTED_RELEASE_COUNT) {
// Then we add the rest of the releases as a category.
sidebarEntries = [
...sidebarEntries.slice(0, SUPPORTED_RELEASE_COUNT),
{
type: "category",
label: "Previous versions",
items: sidebarEntries.slice(SUPPORTED_RELEASE_COUNT),
},
];
}
return sidebarEntries;
}

View File

@ -3,20 +3,73 @@
*
* @import { SidebarItemConfig } from "@docusaurus/plugin-content-docs-types"
*/
import * as path from "node:path";
import { fileURLToPath } from "node:url";
import apiReference from "../docs/developer-docs/api/reference/sidebar";
import { collectReleaseFiles, createReleaseSidebarEntries } from "../releases/utils.mjs";
import { generateVersionDropdown } from "../src/utils.js";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const releases = collectReleaseFiles(path.join(__dirname, "..", "docs"));
/**
* @type {SidebarItemConfig[]}
*/
const releases = [
"releases/2025/v2025.4",
"releases/2025/v2025.2",
"releases/2024/v2024.12",
{
type: "category",
label: "Previous versions",
items: [
"releases/2024/v2024.10",
"releases/2024/v2024.8",
"releases/2024/v2024.6",
"releases/2024/v2024.4",
"releases/2024/v2024.2",
"releases/2023/v2023.10",
"releases/2023/v2023.8",
"releases/2023/v2023.6",
"releases/2023/v2023.5",
"releases/2023/v2023.4",
"releases/2023/v2023.3",
"releases/2023/v2023.2",
"releases/2023/v2023.1",
"releases/2022/v2022.12",
"releases/2022/v2022.11",
"releases/2022/v2022.10",
"releases/2022/v2022.9",
"releases/2022/v2022.8",
"releases/2022/v2022.7",
"releases/2022/v2022.6",
"releases/2022/v2022.5",
"releases/2022/v2022.4",
"releases/2022/v2022.2",
"releases/2022/v2022.1",
"releases/2021/v2021.12",
"releases/2021/v2021.10",
"releases/2021/v2021.9",
"releases/2021/v2021.8",
"releases/2021/v2021.7",
"releases/2021/v2021.6",
"releases/2021/v2021.5",
"releases/2021/v2021.4",
"releases/2021/v2021.3",
"releases/2021/v2021.2",
"releases/2021/v2021.1",
"releases/old/v0.14",
"releases/old/v0.13",
"releases/old/v0.12",
"releases/old/v0.11",
"releases/old/v0.10",
"releases/old/v0.9",
],
},
];
/**
* @type {SidebarItemConfig[]}
*/
const items = [
{
type: "html",
value: generateVersionDropdown(releases),
},
{
type: "doc",
id: "index",
@ -743,7 +796,7 @@ const items = [
slug: "releases",
description: "Release Notes for recent authentik versions",
},
items: createReleaseSidebarEntries(releases),
items: releases,
},
];

View File

@ -80,6 +80,7 @@ const items = [
"services/argocd/index",
"services/awx-tower/index",
"services/cloudflare-access/index",
"services/coder/index",
"services/globalprotect/index",
"services/harbor/index",
"services/hashicorp-vault/index",

View File

@ -1,231 +0,0 @@
import { usePluginData } from "@docusaurus/useGlobalData";
import useIsBrowser from "@docusaurus/useIsBrowser";
import type { AKReleasesPluginData } from "@site/releases/plugin.mjs";
import clsx from "clsx";
import React, { memo, useEffect, useMemo, useState } from "react";
import { coerce } from "semver";
import "./styles.css";
const ProductionURL = new URL("https://docs.goauthentik.io");
const LocalhostAliases: ReadonlySet<string> = new Set(["localhost", "127.0.0.1"]);
/**
* Given a semver, create the URL for the version.
*/
function createVersionURL(semver: string): string {
const subdomain = `version-${semver.replace(".", "-")}`;
return `https://${subdomain}.goauthentik.io`;
}
/**
* Predicate to determine if a hostname appears to be a prerelease origin.
*/
function isPrerelease(hostname: string | null): boolean {
if (!hostname) return false;
if (hostname === ProductionURL.hostname) return true;
if (hostname.endsWith(".netlify.app")) return true;
if (LocalhostAliases.has(hostname)) return true;
return false;
}
/**
* Given a hostname, parse the semver from the subdomain.
*/
function parseHostnameSemVer(hostname: string | null): string | null {
if (!hostname) return null;
const [, possibleSemVer] = hostname.match(/version-(.+)\.goauthentik\.io/) || [];
if (!possibleSemVer) return null;
const formattedSemVer = possibleSemVer.replace("-", ".");
if (!coerce(formattedSemVer)) return null;
return formattedSemVer;
}
interface VersionDropdownProps {
/**
* The hostname of the client.
*/
hostname: string | null;
/**
* The origin of the prerelease documentation.
*
* @format url
*/
prereleaseOrigin: string;
/**
* The available versions of the documentation.
*
* @format semver
*/
releases: string[];
}
/**
* A dropdown that shows the available versions of the documentation.
*/
const VersionDropdown = memo<VersionDropdownProps>(({ hostname, prereleaseOrigin, releases }) => {
const prerelease = isPrerelease(hostname);
const parsedSemVer = !prerelease ? parseHostnameSemVer(hostname) : null;
const currentLabel = parsedSemVer || "Pre-Release";
const endIndex = parsedSemVer ? releases.indexOf(parsedSemVer) : -1;
const visibleReleases = releases.slice(0, endIndex === -1 ? 3 : endIndex + 3);
return (
<li className="navbar__item dropdown dropdown--hoverable dropdown--right ak-version-selector">
<div
aria-haspopup="true"
aria-expanded="false"
role="button"
className="navbar__link menu__link"
>
Version: {currentLabel}
</div>
<ul className="dropdown__menu menu__list-item--collapsed">
{!prerelease ? (
<li>
<a
href={prereleaseOrigin}
target="_blank"
rel="noopener noreferrer"
className="dropdown__link menu__link"
>
Pre-Release
</a>
</li>
) : null}
{visibleReleases.map((semVer, idx) => {
let label = semVer;
if (idx === 0) {
label += " (Current Release)";
}
return (
<li key={idx}>
<a
href={createVersionURL(semVer)}
target="_blank"
rel="noopener noreferrer"
className={clsx("dropdown__link menu__link", {
"menu__link--active": semVer === currentLabel,
})}
>
{label}
</a>
</li>
);
})}
</ul>
</li>
);
});
interface VersionPickerLoaderProps {
pluginData: AKReleasesPluginData;
}
/**
* A data-fetching component that loads available versions of the documentation.
*
* @see {@linkcode VersionPicker} for the component.
* @see {@linkcode AKReleasesPluginData} for the plugin data.
* @client
*/
const VersionPickerLoader: React.FC<VersionPickerLoaderProps> = ({ pluginData }) => {
const [releases, setReleases] = useState(pluginData.releases);
const browser = useIsBrowser();
const prereleaseOrigin = useMemo(() => {
if (browser && LocalhostAliases.has(window.location.hostname)) {
return window.location.origin;
}
return ProductionURL.href;
}, [browser]);
const hostname = useMemo(() => {
if (!browser) return null;
const searchParams = new URLSearchParams(window.location.search);
// Query parameter used for debugging.
// Note that this doesn't synchronize with Docusaurus's router state.
const subdomain = searchParams.get("version");
if (subdomain) return subdomain;
return window.location.hostname;
}, [browser]);
useEffect(() => {
if (!browser || !prereleaseOrigin) return;
const controller = new AbortController();
const updateURL = new URL(pluginData.publicPath, prereleaseOrigin);
fetch(updateURL, {
signal: controller.signal,
})
.then((response) => {
if (!response.ok) {
throw new Error(`Failed to fetch new releases: ${response.status}`);
}
return response.json();
})
.then((data: unknown) => {
// We're extra cautious here to be ready if the API shape ever changes.
if (!data) throw new Error("Failed to parse releases");
if (!Array.isArray(data)) throw new Error("Releases must be an array");
if (!data.every((item) => typeof item === "string"))
throw new Error("Releases must be an array of strings");
setReleases(data);
})
.catch((error) => {
console.warn(`Failed to fetch new releases: ${error}`);
});
return () => controller.abort("unmount");
}, [browser, prereleaseOrigin]);
return (
<VersionDropdown
hostname={hostname}
prereleaseOrigin={prereleaseOrigin}
releases={releases}
/>
);
};
/**
* A component that shows the available versions of the documentation.
*
* @see {@linkcode VersionPickerLoader} for the data-fetching component.
*/
export const VersionPicker: React.FC = () => {
const pluginData = usePluginData("ak-releases-plugin", undefined, {
failfast: true,
}) as AKReleasesPluginData;
if (!pluginData.releases.length) return null;
return <VersionPickerLoader pluginData={pluginData} />;
};

View File

@ -1,27 +0,0 @@
.theme-doc-sidebar-menu .dropdown.ak-version-selector {
--ak-version-selector-padding: calc(var(--ifm-spacing-vertical) / 2);
width: calc(100% - (var(--ifm-spacing-horizontal) / 2));
border-block-end: var(--ifm-hr-height) solid var(--ifm-toc-border-color);
padding-block-start: calc(var(--ak-version-selector-padding) / 2);
padding-block-end: var(--ak-version-selector-padding);
margin-block-end: var(--ak-version-selector-padding);
.navbar__link.menu__link {
display: flex;
width: 100%;
justify-content: space-between;
font-weight: var(--ifm-font-weight-semibold);
&::after {
color: var(--ifm-color-emphasis-400);
filter: var(--ifm-menu-link-sublist-icon-filter);
}
}
.dropdown__menu {
background: var(--ifm-dropdown-background-color);
box-shadow: var(--ifm-global-shadow-lw);
border: 1px solid var(--ifm-color-emphasis-200);
}
}

View File

@ -1,24 +0,0 @@
import {
DocSidebarItemsExpandedStateProvider,
useVisibleSidebarItems,
} from "@docusaurus/plugin-content-docs/client";
import { VersionPicker } from "@site/src/components/VersionPicker/index";
import DocSidebarItem from "@theme/DocSidebarItem";
import type { Props as DocSidebarItemsProps } from "@theme/DocSidebarItems";
import { memo } from "react";
const DocSidebarItems: React.FC<DocSidebarItemsProps> = ({ items, ...props }) => {
const visibleItems = useVisibleSidebarItems(items, props.activePath);
const includeVersionPicker = props.level === 1 && props.activePath.startsWith("/docs");
return (
<DocSidebarItemsExpandedStateProvider>
{includeVersionPicker ? <VersionPicker /> : null}
{visibleItems.map((item, index) => (
<DocSidebarItem key={index} item={item} index={index} {...props} />
))}
</DocSidebarItemsExpandedStateProvider>
);
};
export default memo(DocSidebarItems);

View File

@ -21,9 +21,6 @@ declare module "@docusaurus/plugin-content-docs/src/sidebars/types" {
}
declare module "@docusaurus/plugin-content-docs/client" {
export * from "@docusaurus/plugin-content-docs/lib/client/docSidebarItemsExpandedState.js";
export * from "@docusaurus/plugin-content-docs/lib/client/docsUtils.js";
import { DocContextValue as BaseDocContextValue } from "@docusaurus/plugin-content-docs/lib/client/doc.js";
import { DocFrontMatter as BaseDocFrontMatter } from "@docusaurus/plugin-content-docs";