Compare commits
2 Commits
docusaurus
...
imports-fo
Author | SHA1 | Date | |
---|---|---|---|
dbd5ae90eb | |||
40363a2142 |
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 2025.6.3
|
||||
current_version = 2025.6.2
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
|
||||
|
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
@ -78,13 +78,13 @@ updates:
|
||||
patterns:
|
||||
- "@goauthentik/*"
|
||||
- package-ecosystem: npm
|
||||
directory: "/docs"
|
||||
directory: "/website"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
commit-message:
|
||||
prefix: "docs:"
|
||||
prefix: "website:"
|
||||
labels:
|
||||
- dependencies
|
||||
groups:
|
||||
|
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@ -31,4 +31,4 @@ If changes to the frontend have been made
|
||||
If applicable
|
||||
|
||||
- [ ] The documentation has been updated
|
||||
- [ ] The documentation has been formatted (`make docs`)
|
||||
- [ ] The documentation has been formatted (`make website`)
|
||||
|
@ -38,8 +38,6 @@ jobs:
|
||||
# Needed for attestation
|
||||
id-token: write
|
||||
attestations: write
|
||||
# Needed for checkout
|
||||
contents: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: docker/setup-qemu-action@v3.6.0
|
||||
|
83
.github/workflows/ci-api-docs.yml
vendored
83
.github/workflows/ci-api-docs.yml
vendored
@ -1,83 +0,0 @@
|
||||
name: authentik-ci-api-docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- next
|
||||
- version-*
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- version-*
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
command:
|
||||
- prettier-check
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install Dependencies
|
||||
working-directory: docs/
|
||||
run: npm ci
|
||||
- name: Lint
|
||||
working-directory: docs/
|
||||
run: npm run ${{ matrix.command }}
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: docs/package.json
|
||||
cache: "npm"
|
||||
cache-dependency-path: docs/package-lock.json
|
||||
- working-directory: docs/
|
||||
name: Install Dependencies
|
||||
run: npm ci
|
||||
- name: Build API Docs via Docusaurus
|
||||
working-directory: docs
|
||||
run: npm run build -w api
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: api-docs
|
||||
path: docs/api/build
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- lint
|
||||
- build
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: api-docs
|
||||
path: docs/api/build
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: docs/package.json
|
||||
cache: "npm"
|
||||
cache-dependency-path: docs/package-lock.json
|
||||
- working-directory: docs/
|
||||
name: Install Dependencies
|
||||
run: npm ci
|
||||
- name: Deploy Netlify (Production)
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
env:
|
||||
NETLIFY_SITE_ID: authentik-api-docs.netlify.app
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
working-directory: docs/api
|
||||
run: npx netlify deploy --no-build --prod
|
||||
|
||||
- name: Deploy Netlify (Preview)
|
||||
if: github.event_name == 'pull_request' || github.ref != 'refs/heads/main'
|
||||
env:
|
||||
NETLIFY_SITE_ID: authentik-api-docs.netlify.app
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
working-directory: docs/api
|
||||
run: npx netlify deploy --no-build --alias=deploy-preview-${{ github.event.number }}
|
1
.github/workflows/ci-main-daily.yml
vendored
1
.github/workflows/ci-main-daily.yml
vendored
@ -9,7 +9,6 @@ on:
|
||||
|
||||
jobs:
|
||||
test-container:
|
||||
if: ${{ github.repository != 'goauthentik/authentik-internal' }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
4
.github/workflows/ci-main.yml
vendored
4
.github/workflows/ci-main.yml
vendored
@ -247,13 +247,11 @@ jobs:
|
||||
# Needed for attestation
|
||||
id-token: write
|
||||
attestations: write
|
||||
# Needed for checkout
|
||||
contents: read
|
||||
needs: ci-core-mark
|
||||
uses: ./.github/workflows/_reusable-docker-build.yaml
|
||||
secrets: inherit
|
||||
with:
|
||||
image_name: ${{ github.repository == 'goauthentik/authentik-internal' && 'ghcr.io/goauthentik/internal-server' || 'ghcr.io/goauthentik/dev-server' }}
|
||||
image_name: ghcr.io/goauthentik/dev-server
|
||||
release: false
|
||||
pr-comment:
|
||||
needs:
|
||||
|
5
.github/workflows/ci-outpost.yml
vendored
5
.github/workflows/ci-outpost.yml
vendored
@ -24,8 +24,8 @@ jobs:
|
||||
run: |
|
||||
# Create folder structure for go embeds
|
||||
mkdir -p web/dist
|
||||
mkdir -p docs/help
|
||||
touch web/dist/test docs/help/test
|
||||
mkdir -p website/help
|
||||
touch web/dist/test website/help/test
|
||||
- name: Generate API
|
||||
run: make gen-client-go
|
||||
- name: golangci-lint
|
||||
@ -59,7 +59,6 @@ jobs:
|
||||
with:
|
||||
jobs: ${{ toJSON(needs) }}
|
||||
build-container:
|
||||
if: ${{ github.repository != 'goauthentik/authentik-internal' }}
|
||||
timeout-minutes: 120
|
||||
needs:
|
||||
- ci-outpost-mark
|
||||
|
@ -1,4 +1,4 @@
|
||||
name: authentik-ci-docs
|
||||
name: authentik-ci-website
|
||||
|
||||
on:
|
||||
push:
|
||||
@ -18,49 +18,51 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
command:
|
||||
- lint:lockfile
|
||||
- prettier-check
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
working-directory: docs/
|
||||
- working-directory: website/
|
||||
run: npm ci
|
||||
- name: Lint
|
||||
working-directory: docs/
|
||||
working-directory: website/
|
||||
run: npm run ${{ matrix.command }}
|
||||
build-topics:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: docs/package.json
|
||||
node-version-file: website/package.json
|
||||
cache: "npm"
|
||||
cache-dependency-path: docs/package-lock.json
|
||||
- working-directory: docs/
|
||||
name: Install Dependencies
|
||||
cache-dependency-path: website/package-lock.json
|
||||
- working-directory: website/
|
||||
run: npm ci
|
||||
- name: Build Documentation via Docusaurus
|
||||
working-directory: docs/
|
||||
run: npm run build
|
||||
build-integrations:
|
||||
- name: test
|
||||
working-directory: website/
|
||||
run: npm test
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
name: ${{ matrix.job }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- build
|
||||
- build:integrations
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: docs/package.json
|
||||
node-version-file: website/package.json
|
||||
cache: "npm"
|
||||
cache-dependency-path: docs/package-lock.json
|
||||
- working-directory: docs/
|
||||
name: Install Dependencies
|
||||
cache-dependency-path: website/package-lock.json
|
||||
- working-directory: website/
|
||||
run: npm ci
|
||||
- name: Build Integrations via Docusaurus
|
||||
working-directory: docs/
|
||||
run: npm run build -w integrations
|
||||
- name: build
|
||||
working-directory: website/
|
||||
run: npm run ${{ matrix.job }}
|
||||
build-container:
|
||||
if: ${{ github.repository != 'goauthentik/authentik-internal' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Needed to upload container images to ghcr.io
|
||||
@ -95,7 +97,7 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
tags: ${{ steps.ev.outputs.imageTags }}
|
||||
file: docs/Dockerfile
|
||||
file: website/Dockerfile
|
||||
push: ${{ steps.ev.outputs.shouldPush == 'true' }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
@ -108,16 +110,15 @@ jobs:
|
||||
subject-name: ${{ steps.ev.outputs.attestImageNames }}
|
||||
subject-digest: ${{ steps.push.outputs.digest }}
|
||||
push-to-registry: true
|
||||
ci-docs-mark:
|
||||
ci-website-mark:
|
||||
if: always()
|
||||
needs:
|
||||
- lint
|
||||
- build-topics
|
||||
- build-integrations
|
||||
- test
|
||||
- build
|
||||
- build-container
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: re-actors/alls-green@release/v1
|
||||
with:
|
||||
jobs: ${{ toJSON(needs) }}
|
||||
allowed-skips: ${{ github.repository == 'goauthentik/authentik-internal' && 'build-container' || '[]' }}
|
2
.github/workflows/release-publish.yml
vendored
2
.github/workflows/release-publish.yml
vendored
@ -52,7 +52,7 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
tags: ${{ steps.ev.outputs.imageTags }}
|
||||
file: docs/Dockerfile
|
||||
file: website/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
|
21
.github/workflows/repo-mirror-cleanup.yml
vendored
21
.github/workflows/repo-mirror-cleanup.yml
vendored
@ -1,21 +0,0 @@
|
||||
name: "authentik-repo-mirror-cleanup"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
to_internal:
|
||||
if: ${{ github.repository != 'goauthentik/authentik-internal' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- if: ${{ env.MIRROR_KEY != '' }}
|
||||
uses: BeryJu/repository-mirroring-action@5cf300935bc2e068f73ea69bcc411a8a997208eb
|
||||
with:
|
||||
target_repo_url: git@github.com:goauthentik/authentik-internal.git
|
||||
ssh_private_key: ${{ secrets.GH_MIRROR_KEY }}
|
||||
args: --tags --force --prune
|
||||
env:
|
||||
MIRROR_KEY: ${{ secrets.GH_MIRROR_KEY }}
|
9
.github/workflows/repo-mirror.yml
vendored
9
.github/workflows/repo-mirror.yml
vendored
@ -11,10 +11,11 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- if: ${{ env.MIRROR_KEY != '' }}
|
||||
uses: BeryJu/repository-mirroring-action@5cf300935bc2e068f73ea69bcc411a8a997208eb
|
||||
uses: pixta-dev/repository-mirroring-action@v1
|
||||
with:
|
||||
target_repo_url: git@github.com:goauthentik/authentik-internal.git
|
||||
ssh_private_key: ${{ secrets.GH_MIRROR_KEY }}
|
||||
args: --tags --force
|
||||
target_repo_url:
|
||||
git@github.com:goauthentik/authentik-internal.git
|
||||
ssh_private_key:
|
||||
${{ secrets.GH_MIRROR_KEY }}
|
||||
env:
|
||||
MIRROR_KEY: ${{ secrets.GH_MIRROR_KEY }}
|
||||
|
@ -16,7 +16,6 @@ env:
|
||||
|
||||
jobs:
|
||||
compile:
|
||||
if: ${{ github.repository != 'goauthentik/authentik-internal' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: generate_token
|
||||
|
@ -10,7 +10,7 @@ coverage
|
||||
dist
|
||||
out
|
||||
.docusaurus
|
||||
docs/api/reference
|
||||
website/docs/developer-docs/api/**/*
|
||||
|
||||
## Environment
|
||||
*.env
|
||||
|
44
.vscode/tasks.json
vendored
44
.vscode/tasks.json
vendored
@ -4,7 +4,12 @@
|
||||
{
|
||||
"label": "authentik/core: make",
|
||||
"command": "uv",
|
||||
"args": ["run", "make", "lint-fix", "lint"],
|
||||
"args": [
|
||||
"run",
|
||||
"make",
|
||||
"lint-fix",
|
||||
"lint"
|
||||
],
|
||||
"presentation": {
|
||||
"panel": "new"
|
||||
},
|
||||
@ -13,7 +18,11 @@
|
||||
{
|
||||
"label": "authentik/core: run",
|
||||
"command": "uv",
|
||||
"args": ["run", "ak", "server"],
|
||||
"args": [
|
||||
"run",
|
||||
"ak",
|
||||
"server"
|
||||
],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"panel": "dedicated",
|
||||
@ -23,13 +32,17 @@
|
||||
{
|
||||
"label": "authentik/web: make",
|
||||
"command": "make",
|
||||
"args": ["web"],
|
||||
"args": [
|
||||
"web"
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "authentik/web: watch",
|
||||
"command": "make",
|
||||
"args": ["web-watch"],
|
||||
"args": [
|
||||
"web-watch"
|
||||
],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"panel": "dedicated",
|
||||
@ -39,19 +52,26 @@
|
||||
{
|
||||
"label": "authentik: install",
|
||||
"command": "make",
|
||||
"args": ["install", "-j4"],
|
||||
"args": [
|
||||
"install",
|
||||
"-j4"
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "authentik/docs: make",
|
||||
"label": "authentik/website: make",
|
||||
"command": "make",
|
||||
"args": ["docs"],
|
||||
"args": [
|
||||
"website"
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "authentik/docs: watch",
|
||||
"label": "authentik/website: watch",
|
||||
"command": "make",
|
||||
"args": ["docs-watch"],
|
||||
"args": [
|
||||
"website-watch"
|
||||
],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"panel": "dedicated",
|
||||
@ -61,7 +81,11 @@
|
||||
{
|
||||
"label": "authentik/api: generate",
|
||||
"command": "uv",
|
||||
"args": ["run", "make", "gen"],
|
||||
"args": [
|
||||
"run",
|
||||
"make",
|
||||
"gen"
|
||||
],
|
||||
"group": "build"
|
||||
}
|
||||
]
|
||||
|
@ -32,8 +32,8 @@ tests/wdio/ @goauthentik/frontend
|
||||
locale/ @goauthentik/backend @goauthentik/frontend
|
||||
web/xliff/ @goauthentik/backend @goauthentik/frontend
|
||||
# Docs & Website
|
||||
docs/ @goauthentik/docs
|
||||
website/ @goauthentik/docs
|
||||
CODE_OF_CONDUCT.md @goauthentik/docs
|
||||
# Security
|
||||
SECURITY.md @goauthentik/security @goauthentik/docs
|
||||
docs/security/ @goauthentik/security @goauthentik/docs
|
||||
website/docs/security/ @goauthentik/security @goauthentik/docs
|
||||
|
@ -18,7 +18,7 @@ RUN --mount=type=bind,target=/work/web/package.json,src=./web/package.json \
|
||||
|
||||
COPY ./package.json /work
|
||||
COPY ./web /work/web/
|
||||
COPY ./docs /work/docs/
|
||||
COPY ./website /work/website/
|
||||
COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
|
||||
|
||||
RUN npm run build && \
|
||||
@ -75,7 +75,7 @@ RUN --mount=type=secret,id=GEOIPUPDATE_ACCOUNT_ID \
|
||||
/bin/sh -c "GEOIPUPDATE_LICENSE_KEY_FILE=/run/secrets/GEOIPUPDATE_LICENSE_KEY /usr/bin/entry.sh || echo 'Failed to get GeoIP database, disabling'; exit 0"
|
||||
|
||||
# Stage 4: Download uv
|
||||
FROM ghcr.io/astral-sh/uv:0.7.17 AS uv
|
||||
FROM ghcr.io/astral-sh/uv:0.7.15 AS uv
|
||||
# Stage 5: Base python image
|
||||
FROM ghcr.io/goauthentik/fips-python:3.13.5-slim-bookworm-fips AS python-base
|
||||
|
||||
|
2
LICENSE
2
LICENSE
@ -1,7 +1,7 @@
|
||||
Copyright (c) 2023 Jens Langhammer
|
||||
|
||||
Portions of this software are licensed as follows:
|
||||
* All content residing under the "docs/" directory of this repository is licensed under "Creative Commons: CC BY-SA 4.0 license".
|
||||
* All content residing under the "website/" directory of this repository is licensed under "Creative Commons: CC BY-SA 4.0 license".
|
||||
* All content that resides under the "authentik/enterprise/" directory of this repository, if that directory exists, is licensed under the license defined in "authentik/enterprise/LICENSE".
|
||||
* All client-side JavaScript (when served directly or after being compiled, arranged, augmented, or combined), is licensed under the "MIT Expat" license.
|
||||
* All third party components incorporated into the authentik are licensed under the original license provided by the owner of the applicable component.
|
||||
|
26
Makefile
26
Makefile
@ -1,4 +1,4 @@
|
||||
.PHONY: gen dev-reset all clean test web docs
|
||||
.PHONY: gen dev-reset all clean test web website
|
||||
|
||||
SHELL := /usr/bin/env bash
|
||||
.SHELLFLAGS += ${SHELLFLAGS} -e -o pipefail
|
||||
@ -70,10 +70,10 @@ core-i18n-extract:
|
||||
--ignore internal \
|
||||
--ignore ${GEN_API_TS} \
|
||||
--ignore ${GEN_API_GO} \
|
||||
--ignore docs \
|
||||
--ignore website \
|
||||
-l en
|
||||
|
||||
install: web-install docs-install core-install ## Install all requires dependencies for `web`, `docs` and `core`
|
||||
install: web-install website-install core-install ## Install all requires dependencies for `web`, `website` and `core`
|
||||
|
||||
dev-drop-db:
|
||||
dropdb -U ${pg_user} -h ${pg_host} ${pg_name}
|
||||
@ -221,22 +221,22 @@ web-i18n-extract:
|
||||
cd web && npm run extract-locales
|
||||
|
||||
#########################
|
||||
## Docs
|
||||
## Website
|
||||
#########################
|
||||
|
||||
docs: docs-lint-fix docs-build ## Automatically fix formatting issues in the Authentik docs source code, lint the code, and compile it
|
||||
website: website-lint-fix website-build ## Automatically fix formatting issues in the Authentik website/docs source code, lint the code, and compile it
|
||||
|
||||
docs-install:
|
||||
npm ci --prefix docs
|
||||
website-install:
|
||||
cd website && npm ci
|
||||
|
||||
docs-lint-fix: lint-codespell
|
||||
npm run prettier --prefix docs
|
||||
website-lint-fix: lint-codespell
|
||||
cd website && npm run prettier
|
||||
|
||||
docs-build:
|
||||
npm run build --prefix docs
|
||||
website-build:
|
||||
cd website && npm run build
|
||||
|
||||
docs-watch: ## Build and watch the documentation website, updating automatically
|
||||
npm run watch --prefix docs
|
||||
website-watch: ## Build and watch the documentation website, updating automatically
|
||||
cd website && npm run watch
|
||||
|
||||
#########################
|
||||
## Docker
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from os import environ
|
||||
|
||||
__version__ = "2025.6.3"
|
||||
__version__ = "2025.6.2"
|
||||
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@ from collections.abc import Callable
|
||||
from django.apps import apps
|
||||
from django.test import TestCase
|
||||
|
||||
from authentik.blueprints.v1.importer import is_model_allowed
|
||||
from authentik.lib.models import SerializerModel
|
||||
from authentik.providers.oauth2.models import RefreshToken
|
||||
|
||||
@ -21,13 +22,10 @@ def serializer_tester_factory(test_model: type[SerializerModel]) -> Callable:
|
||||
return
|
||||
model_class = test_model()
|
||||
self.assertTrue(isinstance(model_class, SerializerModel))
|
||||
# Models that have subclasses don't have to have a serializer
|
||||
if len(test_model.__subclasses__()) > 0:
|
||||
return
|
||||
self.assertIsNotNone(model_class.serializer)
|
||||
if model_class.serializer.Meta().model == RefreshToken:
|
||||
return
|
||||
self.assertTrue(issubclass(test_model, model_class.serializer.Meta().model))
|
||||
self.assertEqual(model_class.serializer.Meta().model, test_model)
|
||||
|
||||
return tester
|
||||
|
||||
@ -36,6 +34,6 @@ for app in apps.get_app_configs():
|
||||
if not app.label.startswith("authentik"):
|
||||
continue
|
||||
for model in app.get_models():
|
||||
if not issubclass(model, SerializerModel):
|
||||
if not is_model_allowed(model):
|
||||
continue
|
||||
setattr(TestModels, f"test_{app.label}_{model.__name__}", serializer_tester_factory(model))
|
||||
|
@ -1082,12 +1082,6 @@ class AuthenticatedSession(SerializerModel):
|
||||
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
@property
|
||||
def serializer(self) -> type[Serializer]:
|
||||
from authentik.core.api.authenticated_sessions import AuthenticatedSessionSerializer
|
||||
|
||||
return AuthenticatedSessionSerializer
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Authenticated Session")
|
||||
verbose_name_plural = _("Authenticated Sessions")
|
||||
|
@ -6,7 +6,7 @@ from djangoql.ast import Name
|
||||
from djangoql.exceptions import DjangoQLError
|
||||
from djangoql.queryset import apply_search
|
||||
from djangoql.schema import DjangoQLSchema
|
||||
from rest_framework.filters import BaseFilterBackend, SearchFilter
|
||||
from rest_framework.filters import SearchFilter
|
||||
from rest_framework.request import Request
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
@ -39,21 +39,19 @@ class BaseSchema(DjangoQLSchema):
|
||||
return super().resolve_name(name)
|
||||
|
||||
|
||||
class QLSearch(BaseFilterBackend):
|
||||
class QLSearch(SearchFilter):
|
||||
"""rest_framework search filter which uses DjangoQL"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._fallback = SearchFilter()
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
return apps.get_app_config("authentik_enterprise").enabled()
|
||||
|
||||
def get_search_terms(self, request: Request) -> str:
|
||||
"""Search terms are set by a ?search=... query parameter,
|
||||
and may be comma and/or whitespace delimited."""
|
||||
params = request.query_params.get("search", "")
|
||||
def get_search_terms(self, request) -> str:
|
||||
"""
|
||||
Search terms are set by a ?search=... query parameter,
|
||||
and may be comma and/or whitespace delimited.
|
||||
"""
|
||||
params = request.query_params.get(self.search_param, "")
|
||||
params = params.replace("\x00", "") # strip null characters
|
||||
return params
|
||||
|
||||
@ -72,9 +70,9 @@ class QLSearch(BaseFilterBackend):
|
||||
search_query = self.get_search_terms(request)
|
||||
schema = self.get_schema(request, view)
|
||||
if len(search_query) == 0 or not self.enabled:
|
||||
return self._fallback.filter_queryset(request, queryset, view)
|
||||
return super().filter_queryset(request, queryset, view)
|
||||
try:
|
||||
return apply_search(queryset, search_query, schema=schema)
|
||||
except DjangoQLError as exc:
|
||||
LOGGER.debug("Failed to parse search expression", exc=exc)
|
||||
return self._fallback.filter_queryset(request, queryset, view)
|
||||
return super().filter_queryset(request, queryset, view)
|
||||
|
@ -57,7 +57,7 @@ class QLTest(APITestCase):
|
||||
)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
content = loads(res.content)
|
||||
self.assertEqual(content["pagination"]["count"], 1)
|
||||
self.assertGreaterEqual(content["pagination"]["count"], 1)
|
||||
self.assertEqual(content["results"][0]["username"], self.user.username)
|
||||
|
||||
def test_search_json(self):
|
||||
|
@ -8,12 +8,12 @@
|
||||
# make gen-dev-config
|
||||
# ```
|
||||
#
|
||||
# You may edit the generated file to override the configuration below.
|
||||
# You may edit the generated file to override the configuration below.
|
||||
#
|
||||
# When making modifying the default configuration file,
|
||||
# When making modifying the default configuration file,
|
||||
# ensure that the corresponding documentation is updated to match.
|
||||
#
|
||||
# @see {@link ../../docs/topics/install-config/configuration/configuration.mdx Configuration documentation} for more information.
|
||||
# @see {@link ../../website/docs/install-config/configuration/configuration.mdx Configuration documentation} for more information.
|
||||
|
||||
postgresql:
|
||||
host: localhost
|
||||
|
@ -66,10 +66,7 @@ class RACClientConsumer(AsyncWebsocketConsumer):
|
||||
def init_outpost_connection(self):
|
||||
"""Initialize guac connection settings"""
|
||||
self.token = (
|
||||
ConnectionToken.filter_not_expired(
|
||||
token=self.scope["url_route"]["kwargs"]["token"],
|
||||
session__session__session_key=self.scope["session"].session_key,
|
||||
)
|
||||
ConnectionToken.filter_not_expired(token=self.scope["url_route"]["kwargs"]["token"])
|
||||
.select_related("endpoint", "provider", "session", "session__user")
|
||||
.first()
|
||||
)
|
||||
|
@ -87,22 +87,3 @@ class TestRACViews(APITestCase):
|
||||
)
|
||||
body = loads(flow_response.content)
|
||||
self.assertEqual(body["component"], "ak-stage-access-denied")
|
||||
|
||||
def test_different_session(self):
|
||||
"""Test request"""
|
||||
self.client.force_login(self.user)
|
||||
response = self.client.get(
|
||||
reverse(
|
||||
"authentik_providers_rac:start",
|
||||
kwargs={"app": self.app.slug, "endpoint": str(self.endpoint.pk)},
|
||||
)
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
flow_response = self.client.get(
|
||||
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug})
|
||||
)
|
||||
body = loads(flow_response.content)
|
||||
next_url = body["to"]
|
||||
self.client.logout()
|
||||
final_response = self.client.get(next_url)
|
||||
self.assertEqual(final_response.url, reverse("authentik_core:if-user"))
|
||||
|
@ -68,10 +68,7 @@ class RACInterface(InterfaceView):
|
||||
|
||||
def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse:
|
||||
# Early sanity check to ensure token still exists
|
||||
token = ConnectionToken.filter_not_expired(
|
||||
token=self.kwargs["token"],
|
||||
session__session__session_key=request.session.session_key,
|
||||
).first()
|
||||
token = ConnectionToken.filter_not_expired(token=self.kwargs["token"]).first()
|
||||
if not token:
|
||||
return redirect("authentik_core:if-user")
|
||||
self.token = token
|
||||
|
File diff suppressed because one or more lines are too long
@ -27,6 +27,7 @@
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<td>
|
||||
{% endblock %}
|
||||
|
||||
{% block sub_content %}
|
||||
|
@ -2,7 +2,7 @@
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"$id": "https://goauthentik.io/blueprints/schema.json",
|
||||
"type": "object",
|
||||
"title": "authentik 2025.6.3 Blueprint schema",
|
||||
"title": "authentik 2025.6.2 Blueprint schema",
|
||||
"required": [
|
||||
"version",
|
||||
"entries"
|
||||
|
@ -31,7 +31,7 @@ services:
|
||||
volumes:
|
||||
- redis:/data
|
||||
server:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.3}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
|
||||
restart: unless-stopped
|
||||
command: server
|
||||
environment:
|
||||
@ -55,7 +55,7 @@ services:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
worker:
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.3}
|
||||
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.6.2}
|
||||
restart: unless-stopped
|
||||
command: worker
|
||||
environment:
|
||||
|
@ -1,9 +0,0 @@
|
||||
[production]
|
||||
> 0.2%
|
||||
not dead
|
||||
not op_mini all
|
||||
|
||||
[development]
|
||||
last 1 chrome version
|
||||
last 1 firefox version
|
||||
last 1 safari version
|
@ -1,20 +0,0 @@
|
||||
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24-slim AS docs-builder
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
WORKDIR /work/docs
|
||||
|
||||
COPY ./docs/package.json ./docs/package-lock.json /work/docs/
|
||||
|
||||
RUN npm ci --include=dev
|
||||
|
||||
COPY ./docs /work/docs/
|
||||
COPY ./blueprints /work/blueprints/
|
||||
COPY ./schema.yml /work/
|
||||
COPY ./SECURITY.md /work/
|
||||
|
||||
RUN npm run build
|
||||
|
||||
FROM docker.io/library/nginx:1.29.0
|
||||
|
||||
COPY --from=docs-builder /work/docs/topics/build /usr/share/nginx/html
|
@ -1,18 +0,0 @@
|
||||
---
|
||||
title: Authentication
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
For any of the token-based methods, set the `Authorization` header to `Bearer <token>`.
|
||||
|
||||
### Session
|
||||
|
||||
When authenticating with a flow, you'll get an authenticated Session cookie, that can be used for authentication. Keep in mind that in this context, a CSRF header is also required.
|
||||
|
||||
### API Token
|
||||
|
||||
Users can create tokens to authenticate as any user with a static key, which can optionally be expiring and auto-rotate.
|
||||
|
||||
### JWT Token
|
||||
|
||||
OAuth2 clients can request the scope `goauthentik.io/api`, which allows their OAuth Access token to be used to authenticate to the API.
|
@ -1,15 +0,0 @@
|
||||
---
|
||||
title: API Client Overview
|
||||
---
|
||||
|
||||
import DocCardList from "@theme/DocCardList";
|
||||
|
||||
These API clients are officially supported and maintained.
|
||||
|
||||
:::info
|
||||
|
||||
These API clients are primarily built around creating/updating/deleting configuration objects in authentik, and in most cases can **not** be used to implemented SSO into your application.
|
||||
|
||||
:::
|
||||
|
||||
<DocCardList />
|
@ -1,17 +0,0 @@
|
||||
---
|
||||
title: Go API Client
|
||||
sidebar_label: Golang
|
||||
description: A Golang client for the authentik API.
|
||||
---
|
||||
|
||||
The [Go API client](https://pkg.go.dev/goauthentik.io/api/v3) is generated using the [OpenAPI Generator](https://openapi-generator.tech/) and the [OpenAPI v3 schema](https://docs.goauthentik.io/schema.yml).
|
||||
|
||||
```bash
|
||||
go get goauthentik.io/api/v3
|
||||
```
|
||||
|
||||
## Building the Go Client
|
||||
|
||||
The Go client is used by the Outpost to communicate with the backend authentik server. To build the go client, run `make gen-client-go`.
|
||||
|
||||
The generated files are stored in `/gen-go-api` in the root of the repository.
|
@ -1,33 +0,0 @@
|
||||
---
|
||||
title: Node.js API Client
|
||||
sidebar_label: Node.js
|
||||
description: A TypeScript client for the authentik API.
|
||||
---
|
||||
|
||||
The [Node.js API client](https://www.npmjs.com/package/@goauthentik/api) is generated using the [OpenAPI Generator](https://openapi-generator.tech/) and the [OpenAPI v3 schema](https://docs.goauthentik.io/schema.yml).
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @goauthentik/api
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { AdminApi, Configuration } from "@goauthentik/api";
|
||||
|
||||
const config = new Configuration({
|
||||
basePath: "authentik.company/api/v3",
|
||||
});
|
||||
|
||||
const status = await new AdminApi(DEFAULT_CONFIG).adminSystemRetrieve();
|
||||
```
|
||||
|
||||
## Building the Node.js Client
|
||||
|
||||
The web client is used by the web-interface and web-FlowExecutor to communicate with authentik. To build the client, run `make gen-client-ts`.
|
||||
|
||||
Since the client is normally distributed as an npm package, running `make gen-client-ts` will overwrite the locally installed client with the newly built one.
|
||||
|
||||
:::caution
|
||||
Running `npm i` in the `/web` folder after using `make gen-client-ts` will overwrite the custom client and revert to the upstream client.
|
||||
:::
|
@ -1,13 +0,0 @@
|
||||
---
|
||||
title: Python API Client
|
||||
sidebar_label: Python
|
||||
description: A Python client for the authentik API.
|
||||
---
|
||||
|
||||
The [Python API client](https://pypi.org/project/authentik-client/) is generated using the [OpenAPI Generator](https://openapi-generator.tech/) and the [OpenAPI v3 schema](https://docs.goauthentik.io/schema.yml).
|
||||
|
||||
```bash
|
||||
pip install authentik-client
|
||||
# Or
|
||||
uv pip install authentik-client
|
||||
```
|
@ -1 +0,0 @@
|
||||
module.exports = import("./docusaurus.config.esm.mjs").then(($) => $.default);
|
@ -1,161 +0,0 @@
|
||||
/**
|
||||
* @file Docusaurus config.
|
||||
*
|
||||
* @import { Config } from "@docusaurus/types";
|
||||
* @import { UserThemeConfig, UserThemeConfigExtra } from "@goauthentik/docusaurus-config";
|
||||
* @import { Options as DocsPluginOptions } from "@docusaurus/plugin-content-docs";
|
||||
* @import * as OpenApiPlugin from "docusaurus-plugin-openapi-docs";
|
||||
*/
|
||||
import { createDocusaurusConfig } from "@goauthentik/docusaurus-config";
|
||||
import { remarkLinkRewrite } from "@goauthentik/docusaurus-theme/remark";
|
||||
|
||||
import { GlobExcludeDefault } from "@docusaurus/utils";
|
||||
import { createApiPageMD } from "docusaurus-plugin-openapi-docs/lib/markdown/index.js";
|
||||
import { cp } from "node:fs/promises";
|
||||
import { createRequire } from "node:module";
|
||||
import { basename, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { gzip } from "pako";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
||||
|
||||
const rootStaticDirectory = resolve(__dirname, "..", "static");
|
||||
|
||||
//#region Copy static files
|
||||
|
||||
const authentikModulePath = resolve(__dirname, "..", "..");
|
||||
|
||||
const files = [
|
||||
resolve(authentikModulePath, "docker-compose.yml"),
|
||||
resolve(authentikModulePath, "schema.yml"),
|
||||
];
|
||||
|
||||
await Promise.all(
|
||||
files.map((file) => {
|
||||
const fileName = basename(file);
|
||||
const destPath = resolve(rootStaticDirectory, fileName);
|
||||
return cp(file, destPath, {
|
||||
recursive: true,
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Configuration
|
||||
|
||||
//#region Configuration
|
||||
|
||||
/**
|
||||
* Documentation site configuration for Docusaurus.
|
||||
* @satisfies {Partial<Config>}
|
||||
*/
|
||||
const config = {
|
||||
staticDirectories: [
|
||||
// ---
|
||||
"static",
|
||||
rootStaticDirectory,
|
||||
],
|
||||
|
||||
onBrokenAnchors: "ignore",
|
||||
onBrokenLinks: "ignore",
|
||||
onBrokenMarkdownLinks: "ignore",
|
||||
onDuplicateRoutes: "ignore",
|
||||
|
||||
themes: ["@docusaurus/theme-mermaid", "docusaurus-theme-openapi-docs"],
|
||||
|
||||
themeConfig: /** @type {UserThemeConfig & UserThemeConfigExtra} */ ({
|
||||
navbarReplacements: {
|
||||
DOCS_URL: "/",
|
||||
},
|
||||
docs: {
|
||||
sidebar: {
|
||||
hideable: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
plugins: [
|
||||
[
|
||||
"@docusaurus/theme-classic",
|
||||
{
|
||||
customCss: require.resolve("@goauthentik/docusaurus-config/css/index.css"),
|
||||
},
|
||||
],
|
||||
|
||||
//#region Docs Content Plugin
|
||||
|
||||
[
|
||||
"@docusaurus/plugin-content-docs",
|
||||
/** @type {DocsPluginOptions} */ ({
|
||||
showLastUpdateAuthor: false,
|
||||
showLastUpdateTime: false,
|
||||
numberPrefixParser: false,
|
||||
id: "docs",
|
||||
routeBasePath: "/",
|
||||
path: ".",
|
||||
exclude: [...GlobExcludeDefault],
|
||||
include: ["**/*.mdx", "**/*.md"],
|
||||
sidebarPath: "./sidebar.mjs",
|
||||
docItemComponent: "@theme/ApiItem",
|
||||
beforeDefaultRemarkPlugins: [
|
||||
remarkLinkRewrite([
|
||||
// ---
|
||||
["/integrations", "https://integrations.goauthentik.io"],
|
||||
["/docs", "https://docs.goauthentik.io"],
|
||||
]),
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region OpenAPI Docs Plugin
|
||||
[
|
||||
"docusaurus-plugin-openapi-docs",
|
||||
{
|
||||
id: "open-api-docs",
|
||||
docsPluginId: "docs",
|
||||
config: {
|
||||
authentik: /** @type {OpenApiPlugin.Options} */ ({
|
||||
specPath: resolve("..", "..", "schema.yml"),
|
||||
outputDir: "./reference",
|
||||
hideSendButton: true,
|
||||
disableCompression: true,
|
||||
sidebarOptions: {
|
||||
groupPathsBy: "tag",
|
||||
},
|
||||
template: "src/templates/api.mustache",
|
||||
markdownGenerators: {
|
||||
createApiPageMD: (pageData) => {
|
||||
const {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
info,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
postman,
|
||||
...coreAPI
|
||||
} = pageData.api;
|
||||
|
||||
return [
|
||||
createApiPageMD(pageData),
|
||||
`export const api = "${btoa(
|
||||
String.fromCharCode(
|
||||
...gzip(JSON.stringify(coreAPI), {
|
||||
level: 9,
|
||||
}),
|
||||
),
|
||||
)}";`,
|
||||
].join("\n");
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
//#endregion
|
||||
};
|
||||
|
||||
//#endregion
|
||||
|
||||
export default createDocusaurusConfig(config);
|
@ -1,11 +0,0 @@
|
||||
import { createRequire } from "node:module";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
try {
|
||||
require.resolve("#reference/sidebar");
|
||||
} catch (_error) {
|
||||
console.error(
|
||||
"\n⛔️ API Reference sidebar not found.\n\nRun `npm run build:api` to generate files.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
---
|
||||
title: API Overview
|
||||
sidebar_label: Overview
|
||||
---
|
||||
|
||||
Our API reference documentation is generated from the [OpenAPI v3 schema](https://docs.goauthentik.io/schema.yml).
|
||||
|
||||
You can also access your installation's own, instance-specific API Browser. Starting with 2021.3.5, every authentik instance has a built-in API browser, which can be accessed at <code>https://<em>authentik.company</em>/api/v3/</code>.
|
||||
|
||||
To generate an API client you can use the OpenAPI v3 schema at <code>https://<em>authentik.company</em>/api/v3/schema/</code>.
|
||||
|
||||
## Making schema changes
|
||||
|
||||
Some backend changes might require new/different fields or remove other fields. To create a new schema after changing a Serializer, run `make gen-build`.
|
||||
|
||||
This will update the `schema.yml` file in the root of the repository.
|
@ -1,30 +0,0 @@
|
||||
[[plugins]]
|
||||
package = "netlify-plugin-cache"
|
||||
|
||||
[plugins.inputs]
|
||||
paths = [".docusaurus", ".cache", 'node_modules/.cache']
|
||||
|
||||
[[plugins]]
|
||||
package = "netlify-plugin-debug-cache"
|
||||
|
||||
[build]
|
||||
base = "docs"
|
||||
package = "api"
|
||||
command = "npm run build -w api"
|
||||
publish = "api/build"
|
||||
|
||||
[dev]
|
||||
command = "npm start"
|
||||
targetPort = 3000
|
||||
publish = "api/build"
|
||||
|
||||
[context.production.environment]
|
||||
NODE_ENV = "production"
|
||||
|
||||
[context.dev.environment]
|
||||
NODE_ENV = "development"
|
||||
|
||||
[[headers]]
|
||||
for = "/*"
|
||||
[headers.values]
|
||||
X-Frame-Options = "DENY"
|
@ -1,24 +0,0 @@
|
||||
{
|
||||
"name": "@goauthentik/api-docs",
|
||||
"version": "0.0.0",
|
||||
"description": "API Documentation",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "run-s build:api build:types build:docusaurus",
|
||||
"build:api": "docusaurus gen-api-docs all",
|
||||
"build:docusaurus": "docusaurus build",
|
||||
"build:types": "tsc -b .",
|
||||
"deploy": "docusaurus deploy",
|
||||
"docusaurus": "docusaurus",
|
||||
"serve": "docusaurus serve",
|
||||
"start": "docusaurus start",
|
||||
"swizzle": "docusaurus swizzle"
|
||||
},
|
||||
"imports": {
|
||||
"#reference/sidebar": "./reference/sidebar.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@goauthentik/docusaurus-theme": "*"
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/**
|
||||
* @file Sidebar configuration for documentation entries.
|
||||
*
|
||||
* @import { SidebarItemConfig } from "@docusaurus/plugin-content-docs/src/sidebars/types.js"
|
||||
*/
|
||||
import "./ensure-reference-sidebar.mjs";
|
||||
|
||||
// No file extensions for Docusaurus's automatic resolution.
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore - Allows for project-wide type checking when partially building docs.
|
||||
import apiReference from "./reference/sidebar";
|
||||
|
||||
const DOCS_URL = process.env.DOCS_URL || "https://docs.goauthentik.io";
|
||||
|
||||
/**
|
||||
* @type {SidebarItemConfig}
|
||||
*/
|
||||
const sidebar = {
|
||||
reference: [
|
||||
{
|
||||
type: "link",
|
||||
label: "← Back to Developer Docs",
|
||||
href: new URL("/developer-docs", DOCS_URL).href,
|
||||
className: "navbar-sidebar__upwards",
|
||||
},
|
||||
{
|
||||
type: "doc",
|
||||
label: "API Overview",
|
||||
className: "api-overview",
|
||||
id: "index",
|
||||
},
|
||||
|
||||
{
|
||||
type: "category",
|
||||
label: "Clients",
|
||||
collapsed: false,
|
||||
collapsible: false,
|
||||
link: {
|
||||
type: "doc",
|
||||
id: "clients",
|
||||
},
|
||||
items: [
|
||||
{
|
||||
type: "autogenerated",
|
||||
dirName: "clients",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "API Reference",
|
||||
className: "api-reference",
|
||||
collapsed: false,
|
||||
collapsible: false,
|
||||
link: {
|
||||
type: "doc",
|
||||
id: apiReference[0].id,
|
||||
},
|
||||
|
||||
items: apiReference.slice(1),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default sidebar;
|
@ -1,25 +0,0 @@
|
||||
---
|
||||
id: {{{id}}}
|
||||
title: "{{{title}}}"
|
||||
description: "{{{frontMatter.description}}}"
|
||||
{{^api}}
|
||||
sidebar_label: Introduction
|
||||
sidebar_position: 0
|
||||
{{/api}}
|
||||
hide_title: true
|
||||
{{#api}}
|
||||
hide_table_of_contents: true
|
||||
{{/api}}
|
||||
{{#json}}
|
||||
api: true
|
||||
{{/json}}
|
||||
{{#api.method}}
|
||||
sidebar_class_name: "{{{api.method}}} api-method"
|
||||
{{/api.method}}
|
||||
{{#infoPath}}
|
||||
info_path: {{{infoPath}}}
|
||||
{{/infoPath}}
|
||||
hide_send_button: true
|
||||
---
|
||||
|
||||
{{{markdown}}}
|
@ -1,75 +0,0 @@
|
||||
import { useDoc } from "@docusaurus/plugin-content-docs/client";
|
||||
import { useWindowSize } from "@docusaurus/theme-common";
|
||||
import type { Props } from "@theme/ApiItem/Layout";
|
||||
import ContentVisibility from "@theme/ContentVisibility";
|
||||
import DocBreadcrumbs from "@theme/DocBreadcrumbs";
|
||||
import DocItemContent from "@theme/DocItem/Content";
|
||||
import DocItemFooter from "@theme/DocItem/Footer";
|
||||
import DocItemPaginator from "@theme/DocItem/Paginator";
|
||||
import DocItemTOCDesktop from "@theme/DocItem/TOC/Desktop";
|
||||
import DocItemTOCMobile from "@theme/DocItem/TOC/Mobile";
|
||||
import DocVersionBadge from "@theme/DocVersionBadge";
|
||||
import DocVersionBanner from "@theme/DocVersionBanner";
|
||||
import clsx from "clsx";
|
||||
import React, { type JSX } from "react";
|
||||
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
/**
|
||||
* Decide if the toc should be rendered, on mobile or desktop viewports
|
||||
*/
|
||||
function useDocTOC() {
|
||||
const { frontMatter, toc } = useDoc();
|
||||
const windowSize = useWindowSize();
|
||||
|
||||
const hidden = frontMatter.hide_table_of_contents;
|
||||
const canRender = !hidden && toc.length > 0;
|
||||
|
||||
const mobile = canRender ? <DocItemTOCMobile /> : undefined;
|
||||
|
||||
const desktop =
|
||||
canRender && (windowSize === "desktop" || windowSize === "ssr") ? (
|
||||
<DocItemTOCDesktop />
|
||||
) : undefined;
|
||||
|
||||
return {
|
||||
hidden,
|
||||
mobile,
|
||||
desktop,
|
||||
};
|
||||
}
|
||||
|
||||
export default function DocItemLayout({ children }: Props): JSX.Element {
|
||||
const docTOC = useDocTOC();
|
||||
const { metadata, frontMatter } = useDoc() as DocContextValue;
|
||||
const { api, schema } = frontMatter;
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
<div className={clsx("col", !docTOC.hidden && styles.docItemCol)}>
|
||||
<ContentVisibility metadata={metadata} />
|
||||
<DocVersionBanner />
|
||||
<div className={styles.docItemContainer}>
|
||||
<article>
|
||||
<DocBreadcrumbs />
|
||||
<DocVersionBadge />
|
||||
{docTOC.mobile}
|
||||
<DocItemContent>{children}</DocItemContent>
|
||||
<div className="row">
|
||||
<div className={clsx("col", api || schema ? "col--7" : "col--12")}>
|
||||
<DocItemFooter />
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<div className="row">
|
||||
<div className={clsx("col", api || schema ? "col--7" : "col--12")}>
|
||||
<DocItemPaginator />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{docTOC.desktop ? <div className="col col--3">{docTOC.desktop}</div> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
.docItemContainer header + *,
|
||||
.docItemContainer article > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 997px) {
|
||||
.docItemCol {
|
||||
max-width: 75% !important;
|
||||
}
|
||||
}
|
@ -1,245 +0,0 @@
|
||||
import BrowserOnly from "@docusaurus/BrowserOnly";
|
||||
import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment";
|
||||
import { DocProvider } from "@docusaurus/plugin-content-docs/client";
|
||||
import { HtmlClassNameProvider } from "@docusaurus/theme-common";
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
||||
import useIsBrowser from "@docusaurus/useIsBrowser";
|
||||
import type { ApiExplorerProps } from "@theme/APIExplorer";
|
||||
import { createAuth } from "@theme/ApiExplorer/Authorization/slice";
|
||||
import { createPersistanceMiddleware } from "@theme/ApiExplorer/persistanceMiddleware";
|
||||
import DocItemLayout from "@theme/ApiItem/Layout";
|
||||
import CodeBlock from "@theme/CodeBlock";
|
||||
import DocItemMetadata from "@theme/DocItem/Metadata";
|
||||
import SkeletonLoader from "@theme/SkeletonLoader";
|
||||
import clsx from "clsx";
|
||||
import { ParameterObject, ServerObject } from "docusaurus-plugin-openapi-docs/src/openapi/types";
|
||||
import type { ApiItem as ApiItemType } from "docusaurus-plugin-openapi-docs/src/types";
|
||||
import type { ThemeConfig } from "docusaurus-theme-openapi-docs/src/types";
|
||||
import { ungzip } from "pako";
|
||||
import React from "react";
|
||||
import { Provider } from "react-redux";
|
||||
|
||||
import { APIStore, createStoreWithState, createStoreWithoutState } from "./store";
|
||||
|
||||
let ApiExplorer: React.FC<ApiExplorerProps> = () => <div />;
|
||||
|
||||
if (ExecutionEnvironment.canUseDOM) {
|
||||
// @ts-expect-error - Dynamic import
|
||||
ApiExplorer = await import("@theme/ApiExplorer").then((mod) => mod.default);
|
||||
}
|
||||
|
||||
function base64ToUint8Array(base64: string) {
|
||||
const binary = atob(base64);
|
||||
const len = binary.length;
|
||||
const bytes = new Uint8Array(len);
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = binary.charCodeAt(i);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function decodeAPI(encodedAPI: string): ApiItemType | null {
|
||||
try {
|
||||
return JSON.parse(
|
||||
ungzip(base64ToUint8Array(encodedAPI), {
|
||||
to: "string",
|
||||
}),
|
||||
);
|
||||
} catch (_error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
interface APIItemSchemeProps {
|
||||
content: PropDocContent;
|
||||
}
|
||||
|
||||
const APIItemScheme: React.FC<APIItemSchemeProps> = (props) => {
|
||||
const MDXComponent = props.content;
|
||||
const docHtmlClassName = `docs-doc-id-${props.content.metadata.id}`;
|
||||
|
||||
const { frontMatter } = MDXComponent;
|
||||
const { sample } = frontMatter;
|
||||
|
||||
return (
|
||||
<DocProvider content={props.content}>
|
||||
<HtmlClassNameProvider className={docHtmlClassName}>
|
||||
<DocItemMetadata />
|
||||
<DocItemLayout>
|
||||
<div className={clsx("row", "theme-api-markdown")}>
|
||||
<div className="col col--7 openapi-left-panel__container schema">
|
||||
<MDXComponent />
|
||||
</div>
|
||||
<div className="col col--5 openapi-right-panel__container">
|
||||
{sample ? (
|
||||
<CodeBlock language="json" title={`${frontMatter.title}`}>
|
||||
{JSON.stringify(sample, null, 2)}
|
||||
</CodeBlock>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</DocItemLayout>
|
||||
</HtmlClassNameProvider>
|
||||
</DocProvider>
|
||||
);
|
||||
};
|
||||
|
||||
interface APIItemAPIProps {
|
||||
content: PropDocContent;
|
||||
api: ApiItemType;
|
||||
}
|
||||
|
||||
const APIItemAPI: React.FC<APIItemAPIProps> = ({ content: MDXComponent, api }) => {
|
||||
const docHtmlClassName = `docs-doc-id-${MDXComponent.metadata.id}`;
|
||||
|
||||
const frontMatter = MDXComponent.frontMatter;
|
||||
|
||||
const { siteConfig } = useDocusaurusContext();
|
||||
const themeConfig = siteConfig.themeConfig as ThemeConfig;
|
||||
const options = themeConfig.api;
|
||||
const isBrowser = useIsBrowser();
|
||||
|
||||
// Regex for 2XX status
|
||||
const statusRegex = new RegExp("(20[0-9]|2[1-9][0-9])");
|
||||
|
||||
let store: APIStore;
|
||||
const persistanceMiddleware = createPersistanceMiddleware(options);
|
||||
|
||||
// Init store for SSR
|
||||
if (!isBrowser) {
|
||||
store = createStoreWithoutState({}, [persistanceMiddleware]);
|
||||
} else {
|
||||
// Init store for CSR to hydrate components
|
||||
// Create list of only 2XX response content types to create request samples from
|
||||
const acceptArrayInit: string[][] = [];
|
||||
for (const [code, content] of Object.entries(api.responses ?? [])) {
|
||||
if (statusRegex.test(code)) {
|
||||
acceptArrayInit.push(Object.keys(content.content ?? {}));
|
||||
}
|
||||
}
|
||||
const acceptArray = acceptArrayInit.flat();
|
||||
|
||||
const content = api.requestBody?.content ?? {};
|
||||
const contentTypeArray = Object.keys(content);
|
||||
const servers = api.servers ?? [];
|
||||
const params = {
|
||||
path: [] as ParameterObject[],
|
||||
query: [] as ParameterObject[],
|
||||
header: [] as ParameterObject[],
|
||||
cookie: [] as ParameterObject[],
|
||||
};
|
||||
|
||||
api.parameters?.forEach((param: { in: "path" | "query" | "header" | "cookie" }) => {
|
||||
const paramType = param.in;
|
||||
const paramsArray: ParameterObject[] = params[paramType];
|
||||
paramsArray.push(param as ParameterObject);
|
||||
});
|
||||
|
||||
const auth = createAuth({
|
||||
security: api.security,
|
||||
securitySchemes: api.securitySchemes,
|
||||
options,
|
||||
});
|
||||
|
||||
const server = window?.sessionStorage.getItem("server");
|
||||
const serverObject = (JSON.parse(server!) as ServerObject) ?? {};
|
||||
|
||||
store = createStoreWithState(
|
||||
{
|
||||
accept: {
|
||||
value: acceptArray[0],
|
||||
options: acceptArray,
|
||||
},
|
||||
contentType: {
|
||||
value: contentTypeArray[0],
|
||||
options: contentTypeArray,
|
||||
},
|
||||
server: {
|
||||
value: serverObject.url ? serverObject : undefined,
|
||||
options: servers,
|
||||
},
|
||||
response: { value: undefined },
|
||||
body: { type: "empty" },
|
||||
params,
|
||||
auth,
|
||||
},
|
||||
[persistanceMiddleware],
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<DocProvider content={MDXComponent}>
|
||||
<HtmlClassNameProvider className={docHtmlClassName}>
|
||||
<DocItemMetadata />
|
||||
<DocItemLayout>
|
||||
<Provider store={store}>
|
||||
<div className={clsx("row", "theme-api-markdown")}>
|
||||
<div className="col col--7 openapi-left-panel__container">
|
||||
<MDXComponent />
|
||||
</div>
|
||||
<div className="col col--5 openapi-right-panel__container">
|
||||
<BrowserOnly fallback={<SkeletonLoader size="lg" />}>
|
||||
{() => {
|
||||
return (
|
||||
<ApiExplorer
|
||||
item={api}
|
||||
infoPath={frontMatter.info_path}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</BrowserOnly>
|
||||
</div>
|
||||
</div>
|
||||
</Provider>
|
||||
</DocItemLayout>
|
||||
</HtmlClassNameProvider>
|
||||
</DocProvider>
|
||||
);
|
||||
};
|
||||
|
||||
interface APIItemProps {
|
||||
content: PropDocContent;
|
||||
}
|
||||
|
||||
const ApiItem: React.FC<APIItemProps> = ({ content: MDXComponent }) => {
|
||||
const frontMatter = MDXComponent.frontMatter;
|
||||
|
||||
if (frontMatter.schema) {
|
||||
return <APIItemScheme content={MDXComponent} />;
|
||||
}
|
||||
|
||||
if (!MDXComponent.api) {
|
||||
// Non-API docs
|
||||
return (
|
||||
<DocProvider content={MDXComponent}>
|
||||
<HtmlClassNameProvider className={`docs-doc-id-${MDXComponent.metadata.id}`}>
|
||||
<DocItemMetadata />
|
||||
<DocItemLayout>
|
||||
<div className="row">
|
||||
<div className="col col--12 markdown">
|
||||
<MDXComponent />
|
||||
</div>
|
||||
</div>
|
||||
</DocItemLayout>
|
||||
</HtmlClassNameProvider>
|
||||
</DocProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BrowserOnly fallback={<SkeletonLoader size="lg" />}>
|
||||
{() => {
|
||||
const api = decodeAPI(MDXComponent.api!);
|
||||
|
||||
if (!api) {
|
||||
console.error("Failed to decode API", frontMatter);
|
||||
throw new Error("Failed to decode API");
|
||||
}
|
||||
|
||||
return <APIItemAPI content={MDXComponent} api={api} />;
|
||||
}}
|
||||
</BrowserOnly>
|
||||
);
|
||||
};
|
||||
|
||||
export default ApiItem;
|
@ -1,44 +0,0 @@
|
||||
import { combineReducers, configureStore } from "@reduxjs/toolkit";
|
||||
import { Middleware } from "@reduxjs/toolkit";
|
||||
import accept from "@theme/ApiExplorer/Accept/slice";
|
||||
import auth from "@theme/ApiExplorer/Authorization/slice";
|
||||
import body from "@theme/ApiExplorer/Body/slice";
|
||||
import contentType from "@theme/ApiExplorer/ContentType/slice";
|
||||
import params from "@theme/ApiExplorer/ParamOptions/slice";
|
||||
import response from "@theme/ApiExplorer/Response/slice";
|
||||
import server from "@theme/ApiExplorer/Server/slice";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
accept,
|
||||
contentType,
|
||||
response,
|
||||
server,
|
||||
body,
|
||||
params,
|
||||
auth,
|
||||
});
|
||||
|
||||
export type RootState = ReturnType<typeof rootReducer>;
|
||||
|
||||
export function createStoreWithState(preloadedState: RootState, middlewares: Middleware[]) {
|
||||
return configureStore({
|
||||
reducer: rootReducer,
|
||||
preloadedState,
|
||||
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(...middlewares),
|
||||
});
|
||||
}
|
||||
|
||||
export type APIStore = ReturnType<typeof createStoreWithState>;
|
||||
|
||||
export function createStoreWithoutState(
|
||||
preloadedState: Partial<RootState>,
|
||||
middlewares: Middleware[],
|
||||
) {
|
||||
return configureStore({
|
||||
reducer: rootReducer,
|
||||
preloadedState,
|
||||
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(...middlewares),
|
||||
});
|
||||
}
|
||||
|
||||
export type AppDispatch = ReturnType<typeof createStoreWithState>["dispatch"];
|
@ -1,70 +0,0 @@
|
||||
import Link from "@docusaurus/Link";
|
||||
import isInternalUrl from "@docusaurus/isInternalUrl";
|
||||
import { isActiveSidebarItem } from "@docusaurus/plugin-content-docs/client";
|
||||
import { ThemeClassNames } from "@docusaurus/theme-common";
|
||||
import type { Props } from "@theme/DocSidebarItem/Link";
|
||||
import IconExternalLink from "@theme/Icon/ExternalLink";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
import "./styles.css";
|
||||
|
||||
const docsURL = new URL(process.env.DOCS_URL || "https://docs.goauthentik.io");
|
||||
function isInternalUrlOrDocsUrl(url: string) {
|
||||
if (isInternalUrl(url)) return true;
|
||||
|
||||
const inputURL = new URL(url);
|
||||
|
||||
return inputURL.origin === docsURL.origin;
|
||||
}
|
||||
|
||||
const DocSidebarItemLink: React.FC<Props> = ({
|
||||
item,
|
||||
onItemClick,
|
||||
activePath,
|
||||
level,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
index,
|
||||
...props
|
||||
}) => {
|
||||
const { href, label, className, autoAddBaseUrl } = item;
|
||||
const isActive = isActiveSidebarItem(item, activePath);
|
||||
const internalLink = isInternalUrlOrDocsUrl(href);
|
||||
|
||||
return (
|
||||
<li
|
||||
className={clsx(
|
||||
ThemeClassNames.docs.docSidebarItemLink,
|
||||
ThemeClassNames.docs.docSidebarItemLinkLevel(level),
|
||||
"menu__list-item",
|
||||
className,
|
||||
)}
|
||||
key={label}
|
||||
>
|
||||
<Link
|
||||
className={clsx("menu__link", {
|
||||
"menu__link--external": !internalLink,
|
||||
"menu__link--active": isActive,
|
||||
})}
|
||||
autoAddBaseUrl={autoAddBaseUrl}
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
to={href}
|
||||
{...(internalLink && {
|
||||
onClick: onItemClick ? () => onItemClick(item) : undefined,
|
||||
})}
|
||||
{...props}
|
||||
>
|
||||
{item.className?.includes("api-method") ? (
|
||||
<div className="badge-container">
|
||||
<span role="img" className="badge method" />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{label}
|
||||
{!internalLink && <IconExternalLink />}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocSidebarItemLink;
|
@ -1,127 +0,0 @@
|
||||
.theme-layout-main {
|
||||
--doc-sidebar-width: 400px;
|
||||
}
|
||||
|
||||
.navbar-sidebar__upwards {
|
||||
.menu__link {
|
||||
font-size: var(--ifm-h6-font-size);
|
||||
font-weight: var(--ifm-font-weight-bold);
|
||||
color: var(--ifm-color-info-light);
|
||||
padding-block: calc(var(--ifm-spacing-vertical) / 1.5);
|
||||
}
|
||||
}
|
||||
|
||||
.theme-doc-sidebar-item-category.api-reference {
|
||||
> .menu__list-item-collapsible {
|
||||
font-weight: 900;
|
||||
font-size: var(--ifm-h3-font-size);
|
||||
}
|
||||
|
||||
.menu__list {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.theme-doc-sidebar-item-category-level-2 .menu__list-item-collapsible {
|
||||
font-size: var(--ifm-h4-font-size);
|
||||
font-weight: bold;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
|
||||
.menu__link.menu__link--external {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.menu__list-item.api-method {
|
||||
.badge-container {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
> .menu__link {
|
||||
--menu-border-width: 2px;
|
||||
|
||||
color: var(--menu-item-contrast-foreground, red);
|
||||
background-color: var(--menu-item-background-color, transparent);
|
||||
flex-flow: column;
|
||||
font-family: var(--ifm-font-family-monospace);
|
||||
font-weight: 600;
|
||||
gap: 0.25em;
|
||||
padding-inline-end: 0.25em;
|
||||
word-break: break-all;
|
||||
align-items: start;
|
||||
border-radius: 0;
|
||||
margin-inline-end: calc(var(--ifm-menu-link-padding-horizontal) / 2);
|
||||
font-size: var(--ifm-h6-font-size);
|
||||
letter-spacing: 0.015em;
|
||||
text-rendering: optimizelegibility;
|
||||
position: relative;
|
||||
box-shadow: var(--ifm-global-shadow-lw);
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: var(--menu-border-width);
|
||||
height: 100%;
|
||||
display: block;
|
||||
z-index: 1;
|
||||
background-color: var(--ifm-badge-color, var(--ifm-color-primary));
|
||||
content: "";
|
||||
transition: width 0.2s var(--ifm-transition-timing-default);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.menu__link--active {
|
||||
--menu-border-width: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
&.get {
|
||||
--method-label: "GET";
|
||||
--menu-item-contrast-foreground: var(--ifm-color-content);
|
||||
--menu-item-background-color: var(--ifm-card-background-color);
|
||||
--ifm-badge-color: var(--ifm-color-primary-light);
|
||||
}
|
||||
|
||||
&.post {
|
||||
--method-label: "POST";
|
||||
--menu-item-contrast-foreground: var(--ifm-color-success-contrast-foreground);
|
||||
--menu-item-background-color: var(--ifm-color-success-contrast-background);
|
||||
--ifm-badge-color: var(--ifm-color-success-lightest);
|
||||
}
|
||||
|
||||
&.put {
|
||||
--method-label: "PUT";
|
||||
--menu-item-contrast-foreground: var(--ifm-color-info-contrast-foreground);
|
||||
--menu-item-background-color: var(--ifm-color-info-contrast-background);
|
||||
--ifm-badge-color: var(--ifm-color-info-lightest);
|
||||
}
|
||||
|
||||
&.patch {
|
||||
--method-label: "PATCH";
|
||||
--menu-item-contrast-foreground: var(--ifm-color-warning-contrast-foreground);
|
||||
--menu-item-background-color: var(--ifm-color-warning-contrast-background);
|
||||
--ifm-badge-color: var(--ifm-color-warning-lightest);
|
||||
}
|
||||
|
||||
&.delete {
|
||||
--method-label: "DELETE";
|
||||
--menu-item-contrast-foreground: var(--ifm-color-danger-contrast-foreground);
|
||||
--menu-item-background-color: var(--ifm-color-danger-contrast-background);
|
||||
--ifm-badge-color: var(--ifm-color-danger-lightest);
|
||||
}
|
||||
}
|
||||
|
||||
.badge.method {
|
||||
position: relative;
|
||||
flex: 0 0 auto;
|
||||
user-select: none;
|
||||
|
||||
&::before {
|
||||
content: var(--method-label, "METHOD");
|
||||
display: block;
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"references": [
|
||||
{
|
||||
"path": "../docusaurus-theme"
|
||||
}
|
||||
]
|
||||
}
|
37
docs/api/types/api-plugin.d.ts
vendored
37
docs/api/types/api-plugin.d.ts
vendored
@ -1,37 +0,0 @@
|
||||
/// <reference types="docusaurus-theme-openapi-docs" />
|
||||
/// <reference types="docusaurus-plugin-openapi-docs" />
|
||||
|
||||
declare module "@docusaurus/plugin-content-docs/src/sidebars/types" {
|
||||
export * from "@docusaurus/plugin-content-docs/src/sidebars/types.ts";
|
||||
}
|
||||
|
||||
declare module "@theme/RequestSchema";
|
||||
declare module "@theme/ParamsDetails";
|
||||
declare module "@theme/StatusCodes";
|
||||
declare module "@theme/OperationTabs";
|
||||
|
||||
declare module "@theme/SkeletonLoader" {
|
||||
import { FC } from "react";
|
||||
|
||||
const SkeletonLoader: FC<{ size: "sm" | "md" | "lg" }>;
|
||||
export default SkeletonLoader;
|
||||
}
|
||||
|
||||
declare module "@theme/APIExplorer" {
|
||||
import { FC } from "react";
|
||||
|
||||
export interface ApiExplorerProps {
|
||||
item: unknown;
|
||||
infoPath: unknown;
|
||||
}
|
||||
|
||||
const ApiExplorer: FC<ApiExplorerProps>;
|
||||
export default ApiExplorer;
|
||||
}
|
||||
|
||||
declare module "@theme/ApiExplorer/persistanceMiddleware" {
|
||||
import { Middleware } from "@reduxjs/toolkit";
|
||||
import type { ThemeConfig } from "docusaurus-theme-openapi-docs/src/types";
|
||||
|
||||
export const createPersistanceMiddleware: (options: ThemeConfig["api"]) => Middleware;
|
||||
}
|
34
docs/api/types/globals.d.ts
vendored
34
docs/api/types/globals.d.ts
vendored
@ -1,34 +0,0 @@
|
||||
/**
|
||||
* @file Supplemental type definitions for Docusaurus.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Docusaurus uses an unconventional module resolution strategy, which can lead to
|
||||
* issues when using TypeScript.
|
||||
*
|
||||
* The types in this file are intended to expose less visible types to TypeScript's
|
||||
* project references, allowing for better type checking and autocompletion.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
||||
/// <reference types="@docusaurus/plugin-content-docs" />
|
||||
/// <reference types="@docusaurus/theme-classic" />
|
||||
import type { PropDocContent as BasePropDocContent } from "@docusaurus/plugin-content-docs";
|
||||
import type { DocContextValue as BaseDocContextValue } from "@docusaurus/plugin-content-docs/client";
|
||||
|
||||
declare global {
|
||||
export interface APIDocFrontMatter {
|
||||
readonly info_path?: string;
|
||||
readonly api?: string;
|
||||
readonly schema?: boolean;
|
||||
readonly sample?: unknown;
|
||||
}
|
||||
|
||||
export interface PropDocContent extends BasePropDocContent {
|
||||
readonly api?: string;
|
||||
frontMatter: APIDocFrontMatter & BasePropDocContent["frontMatter"];
|
||||
}
|
||||
|
||||
export interface DocContextValue extends BaseDocContextValue {
|
||||
frontMatter: APIDocFrontMatter & BasePropDocContent["frontMatter"];
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
import {
|
||||
createVersionURL,
|
||||
isPrerelease,
|
||||
parseHostnameSemVer,
|
||||
} from "#components/VersionPicker/utils.ts";
|
||||
|
||||
import clsx from "clsx";
|
||||
import React, { memo } from "react";
|
||||
|
||||
import "./styles.css";
|
||||
|
||||
export 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.
|
||||
*/
|
||||
export 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) => {
|
||||
const label = semVer;
|
||||
|
||||
// TODO: Flesh this out after we settle on versioning strategy.
|
||||
// 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>
|
||||
);
|
||||
},
|
||||
);
|
@ -1,76 +0,0 @@
|
||||
import { VersionDropdown } from "#components/VersionPicker/VersionDropdown.tsx";
|
||||
import { LocalhostAliases, ProductionURL, useHostname } from "#components/VersionPicker/utils.ts";
|
||||
|
||||
import { AKReleasesPluginData } from "@goauthentik/docusaurus-theme/releases/plugin";
|
||||
|
||||
import useIsBrowser from "@docusaurus/useIsBrowser";
|
||||
import React, { useEffect, useMemo, useState } from "react";
|
||||
|
||||
export 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
|
||||
*/
|
||||
export const VersionPickerLoader: React.FC<VersionPickerLoaderProps> = ({ pluginData }) => {
|
||||
const [releases, setReleases] = useState(pluginData.releases);
|
||||
|
||||
const browser = useIsBrowser();
|
||||
const hostname = useHostname();
|
||||
|
||||
const prereleaseOrigin = useMemo(() => {
|
||||
if (browser && LocalhostAliases.has(window.location.hostname)) {
|
||||
return window.location.origin;
|
||||
}
|
||||
|
||||
return ProductionURL.href;
|
||||
}, [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}`);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line consistent-return
|
||||
return () => controller.abort("unmount");
|
||||
}, [browser, pluginData.publicPath, prereleaseOrigin]);
|
||||
|
||||
return (
|
||||
<VersionDropdown
|
||||
hostname={hostname}
|
||||
prereleaseOrigin={prereleaseOrigin}
|
||||
releases={releases}
|
||||
/>
|
||||
);
|
||||
};
|
@ -1,32 +0,0 @@
|
||||
import { VersionDropdown } from "#components/VersionPicker/VersionDropdown.tsx";
|
||||
import { useHostname, usePrereleaseOrigin } from "#components/VersionPicker/utils.ts";
|
||||
|
||||
import { AKReleasesPluginData } from "@goauthentik/docusaurus-theme/releases/plugin";
|
||||
|
||||
import { usePluginData } from "@docusaurus/useGlobalData";
|
||||
|
||||
/**
|
||||
* A component that shows the available versions of the documentation.
|
||||
*
|
||||
* @see {@linkcode VersionPickerLoader} for the data-fetching component.
|
||||
*/
|
||||
export const VersionPicker: React.FC = () => {
|
||||
const hostname = useHostname();
|
||||
const prereleaseOrigin = usePrereleaseOrigin();
|
||||
|
||||
const pluginData = usePluginData("ak-releases-plugin", undefined) as
|
||||
| AKReleasesPluginData
|
||||
| undefined;
|
||||
|
||||
if (!pluginData?.releases.length) return null;
|
||||
|
||||
// return <VersionPickerLoader pluginData={pluginData} />;
|
||||
|
||||
return (
|
||||
<VersionDropdown
|
||||
hostname={hostname}
|
||||
prereleaseOrigin={prereleaseOrigin}
|
||||
releases={pluginData.releases}
|
||||
/>
|
||||
);
|
||||
};
|
@ -1,33 +0,0 @@
|
||||
.theme-doc-sidebar-menu {
|
||||
--ak-version-selector-padding: calc(var(--ifm-spacing-vertical) / 2);
|
||||
|
||||
.dropdown.ak-version-selector {
|
||||
width: calc(100% - (var(--ifm-spacing-horizontal) / 2));
|
||||
border-block-end: var(--ifm-hr-height) solid var(--ifm-color-emphasis-200);
|
||||
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);
|
||||
|
||||
&:has(+ .navbar-sidebar__upwards) {
|
||||
margin-block-end: 0;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
import useIsBrowser from "@docusaurus/useIsBrowser";
|
||||
import { useMemo } from "react";
|
||||
import { coerce } from "semver";
|
||||
|
||||
export const ProductionURL = new URL("https://docs.goauthentik.io");
|
||||
|
||||
export const LocalhostAliases: ReadonlySet<string> = new Set(["localhost", "127.0.0.1"]);
|
||||
|
||||
/**
|
||||
* Given a semver, create the URL for the version.
|
||||
*/
|
||||
export 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.
|
||||
*/
|
||||
export 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.
|
||||
*/
|
||||
export 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;
|
||||
}
|
||||
|
||||
export function useHostname() {
|
||||
const browser = useIsBrowser();
|
||||
|
||||
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]);
|
||||
|
||||
return hostname;
|
||||
}
|
||||
|
||||
export function usePrereleaseOrigin() {
|
||||
const browser = useIsBrowser();
|
||||
|
||||
const prereleaseOrigin = useMemo(() => {
|
||||
if (browser && LocalhostAliases.has(window.location.hostname)) {
|
||||
return window.location.origin;
|
||||
}
|
||||
|
||||
return ProductionURL.href;
|
||||
}, [browser]);
|
||||
|
||||
return prereleaseOrigin;
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
/**
|
||||
* @file Docusaurus config.
|
||||
*
|
||||
* @import { Config } from "@docusaurus/types";
|
||||
* @import { UserThemeConfig, UserThemeConfigExtra } from "@goauthentik/docusaurus-config";
|
||||
* @import { Options as DocsPluginOptions } from "@docusaurus/plugin-content-docs";
|
||||
* @import { BuildUrlValues } from "remark-github";
|
||||
*/
|
||||
import {
|
||||
remarkEnterpriseDirective,
|
||||
remarkPreviewDirective,
|
||||
remarkSupportDirective,
|
||||
remarkVersionDirective,
|
||||
} from "#remark";
|
||||
|
||||
import remarkNPM2Yarn from "@docusaurus/remark-plugin-npm2yarn";
|
||||
import remarkDirective from "remark-directive";
|
||||
import remarkGithub, { defaultBuildUrl } from "remark-github";
|
||||
|
||||
//#region Common configuration
|
||||
|
||||
/**
|
||||
* @satisfies {DocsPluginOptions}
|
||||
*/
|
||||
export const CommonDocsPluginOptions = {
|
||||
id: "docs",
|
||||
routeBasePath: "/",
|
||||
path: "docs",
|
||||
sidebarPath: "./docs/sidebar.mjs",
|
||||
showLastUpdateTime: false,
|
||||
editUrl: "https://github.com/goauthentik/authentik/edit/main/docs/",
|
||||
|
||||
//#region Docs Plugins
|
||||
|
||||
beforeDefaultRemarkPlugins: [
|
||||
remarkDirective,
|
||||
remarkVersionDirective,
|
||||
remarkEnterpriseDirective,
|
||||
remarkPreviewDirective,
|
||||
remarkSupportDirective,
|
||||
],
|
||||
|
||||
remarkPlugins: [
|
||||
[remarkNPM2Yarn, { sync: true }],
|
||||
[
|
||||
remarkGithub,
|
||||
{
|
||||
repository: "goauthentik/authentik",
|
||||
/**
|
||||
* @param {BuildUrlValues} values
|
||||
*/
|
||||
buildUrl: (values) => {
|
||||
// Only replace issues and PR links
|
||||
return values.type === "issue" || values.type === "mention"
|
||||
? defaultBuildUrl(values)
|
||||
: false;
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* Documentation site configuration for Docusaurus.
|
||||
* @satisfies {Partial<Config>}
|
||||
*/
|
||||
export const CommonConfig = {
|
||||
themes: ["@docusaurus/theme-mermaid"],
|
||||
themeConfig: /** @type {UserThemeConfig & UserThemeConfigExtra} */ ({
|
||||
algolia: {
|
||||
appId: "36ROD0O0FV",
|
||||
apiKey: "727db511300ca9aec5425645bbbddfb5",
|
||||
indexName: "goauthentik",
|
||||
},
|
||||
}),
|
||||
plugins: [
|
||||
[
|
||||
"@docusaurus/plugin-google-gtag",
|
||||
{
|
||||
trackingID: ["G-9MVR9WZFZH"],
|
||||
anonymizeIP: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
@ -1,3 +0,0 @@
|
||||
import { createESLintPackageConfig } from "@goauthentik/eslint-config";
|
||||
|
||||
export default createESLintPackageConfig();
|
@ -1,21 +0,0 @@
|
||||
/**
|
||||
* @file Docusaurus theme plugin.
|
||||
* @import { Plugin } from "@docusaurus/types";
|
||||
*/
|
||||
|
||||
/**
|
||||
* @returns {Plugin<void>}
|
||||
*/
|
||||
export default function docusaurusThemeAuthentik() {
|
||||
return {
|
||||
name: "docusaurus-theme-authentik",
|
||||
|
||||
getThemePath() {
|
||||
return "./theme";
|
||||
},
|
||||
|
||||
getTypeScriptThemePath() {
|
||||
return "./theme";
|
||||
},
|
||||
};
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "@goauthentik/docusaurus-theme",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": "./index.js",
|
||||
"./config": "./config.js",
|
||||
"./remark": "./remark/index.mjs",
|
||||
"./components/*": "./components/*",
|
||||
"./releases/plugin": "./releases/plugin.mjs",
|
||||
"./releases/utils": "./releases/utils.mjs"
|
||||
},
|
||||
"imports": {
|
||||
"#remark": "./remark/index.mjs",
|
||||
"#remark/*": "./remark/*",
|
||||
"#components/*": "./components/*",
|
||||
"#hooks/*": "./hooks/*",
|
||||
"#theme/*": "./theme/*"
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
/**
|
||||
* @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;
|
@ -1,69 +0,0 @@
|
||||
/**
|
||||
* @file Docusaurus release utils.
|
||||
*
|
||||
* @import { SidebarItemConfig } from "@docusaurus/plugin-content-docs/src/sidebars/types.js"
|
||||
*/
|
||||
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;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
export * from "./enterprise-directive.mjs";
|
||||
export * from "./link-rewrite-directive.mjs";
|
||||
export * from "./preview-directive.mjs";
|
||||
export * from "./support-directive.mjs";
|
||||
export * from "./version-directive.mjs";
|
@ -1,35 +0,0 @@
|
||||
/**
|
||||
* @import { Root } from "mdast";
|
||||
*/
|
||||
import { SKIP, visit } from "unist-util-visit";
|
||||
|
||||
/**
|
||||
* @typedef {[pattern: string | RegExp, replacement: string]} Rewrite
|
||||
*/
|
||||
|
||||
/**
|
||||
* Remark plugin to transform relative links to docs to absolute URLs
|
||||
* @param {Iterable<[string, string]>} rewrites Map of urls to rewrite where the key is the prefix to check for and the value is the domain to add
|
||||
*/
|
||||
export function remarkLinkRewrite(rewrites) {
|
||||
const map = new Map(rewrites);
|
||||
|
||||
return () => {
|
||||
/**
|
||||
* @param {Root} tree The MDAST tree to transform.
|
||||
*/
|
||||
return (tree) => {
|
||||
visit(tree, "link", (node) => {
|
||||
for (const [pattern, replacement] of map) {
|
||||
if (!node.url.startsWith(pattern)) continue;
|
||||
|
||||
node.url = node.url.replace(pattern, replacement);
|
||||
}
|
||||
|
||||
return SKIP;
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export default remarkLinkRewrite;
|
@ -1,26 +0,0 @@
|
||||
/// <reference types="@docusaurus/plugin-content-docs" />
|
||||
import { VersionPicker } from "#components/VersionPicker/index.tsx";
|
||||
|
||||
import {
|
||||
DocSidebarItemsExpandedStateProvider,
|
||||
useVisibleSidebarItems,
|
||||
} from "@docusaurus/plugin-content-docs/client";
|
||||
import DocSidebarItem from "@theme/DocSidebarItem";
|
||||
import type { Props as DocSidebarItemsProps } from "@theme/DocSidebarItems";
|
||||
import { memo } from "react";
|
||||
|
||||
const DocSidebarItems = ({ items, ...props }: DocSidebarItemsProps): JSX.Element => {
|
||||
const visibleItems = useVisibleSidebarItems(items, props.activePath);
|
||||
const includeVersionPicker = props.level === 1 && !props.activePath.startsWith("/integrations");
|
||||
|
||||
return (
|
||||
<DocSidebarItemsExpandedStateProvider>
|
||||
{includeVersionPicker ? <VersionPicker /> : null}
|
||||
{visibleItems.map((item, index) => (
|
||||
<DocSidebarItem key={index} item={item} index={index} {...props} />
|
||||
))}
|
||||
</DocSidebarItemsExpandedStateProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(DocSidebarItems);
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json"
|
||||
}
|
44
docs/docusaurus-theme/types/globals.d.ts
vendored
44
docs/docusaurus-theme/types/globals.d.ts
vendored
@ -1,44 +0,0 @@
|
||||
/**
|
||||
* @file Supplemental type definitions for Docusaurus.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Docusaurus uses an unconventional module resolution strategy, which can lead to
|
||||
* issues when using TypeScript.
|
||||
*
|
||||
* The types in this file are intended to expose less visible types to TypeScript's
|
||||
* project references, allowing for better type checking and autocompletion.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
||||
/// <reference types="@docusaurus/plugin-content-docs" />
|
||||
/// <reference types="@docusaurus/theme-classic" />
|
||||
import type { PropDocContent as BasePropDocContent } from "@docusaurus/plugin-content-docs";
|
||||
import type { DocContextValue as BaseDocContextValue } from "@docusaurus/plugin-content-docs/client";
|
||||
|
||||
declare global {
|
||||
/**
|
||||
* @monkeypatch
|
||||
*/
|
||||
export interface DocFrontMatter {
|
||||
support_level?: string;
|
||||
authentik_version?: string;
|
||||
authentik_preview: boolean;
|
||||
authentik_enterprise: boolean;
|
||||
}
|
||||
|
||||
export interface APIDocFrontMatter {
|
||||
readonly info_path?: string;
|
||||
readonly api?: string;
|
||||
readonly schema?: boolean;
|
||||
readonly sample?: unknown;
|
||||
}
|
||||
|
||||
export interface PropDocContent extends BasePropDocContent {
|
||||
readonly api?: string;
|
||||
frontMatter: APIDocFrontMatter & BasePropDocContent["frontMatter"];
|
||||
}
|
||||
|
||||
export interface DocContextValue extends BaseDocContextValue {
|
||||
frontMatter: DocFrontMatter & APIDocFrontMatter & BasePropDocContent["frontMatter"];
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import { DefaultIgnorePatterns, createESLintPackageConfig } from "@goauthentik/eslint-config";
|
||||
|
||||
export default createESLintPackageConfig({
|
||||
ignorePatterns: [
|
||||
// ---
|
||||
...DefaultIgnorePatterns,
|
||||
"**/.docusaurus/",
|
||||
"**/build",
|
||||
"**/reference",
|
||||
],
|
||||
});
|
@ -1,7 +0,0 @@
|
||||
.theme-doc-sidebar-item-category-level-1 .menu__list-item-collapsible {
|
||||
border-top: 0.5px solid;
|
||||
border-top-color: var(--ifm-category-color, var(--ifm-menu-color-background-active));
|
||||
border-radius: 0;
|
||||
font-weight: 600;
|
||||
padding-block: 0.25em;
|
||||
}
|
@ -1 +0,0 @@
|
||||
module.exports = import("./docusaurus.config.esm.mjs").then(($) => $.default);
|
@ -1,87 +0,0 @@
|
||||
/**
|
||||
* @file Docusaurus Integrations config.
|
||||
*
|
||||
* @import { Config } from "@docusaurus/types";
|
||||
* @import { UserThemeConfig, UserThemeConfigExtra } from "@goauthentik/docusaurus-config";
|
||||
* @import { Options as DocsPluginOptions } from "@docusaurus/plugin-content-docs";
|
||||
*/
|
||||
import { createDocusaurusConfig } from "@goauthentik/docusaurus-config";
|
||||
import { CommonConfig, CommonDocsPluginOptions } from "@goauthentik/docusaurus-theme/config";
|
||||
import { remarkLinkRewrite } from "@goauthentik/docusaurus-theme/remark";
|
||||
|
||||
import { GlobExcludeDefault } from "@docusaurus/utils";
|
||||
import { deepmerge } from "deepmerge-ts";
|
||||
import { createRequire } from "node:module";
|
||||
import { resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
||||
|
||||
//#region Configuration
|
||||
|
||||
/**
|
||||
* Documentation site configuration for Docusaurus.
|
||||
* @satisfies {Partial<Config>}
|
||||
*/
|
||||
const config = {
|
||||
staticDirectories: [
|
||||
// ---
|
||||
resolve(__dirname, "..", "static"),
|
||||
"static",
|
||||
],
|
||||
|
||||
themes: ["@goauthentik/docusaurus-theme"],
|
||||
|
||||
themeConfig: /** @type {UserThemeConfig & UserThemeConfigExtra} */ ({
|
||||
navbarReplacements: {
|
||||
INTEGRATIONS_URL: "/",
|
||||
},
|
||||
algolia: {
|
||||
externalUrlRegex: /^(?:https?:\/\/)(integrations|api).?(goauthentik.io)/.source,
|
||||
},
|
||||
}),
|
||||
|
||||
plugins: [
|
||||
[
|
||||
"@docusaurus/theme-classic",
|
||||
{
|
||||
customCss: [
|
||||
"./custom.css",
|
||||
require.resolve("@goauthentik/docusaurus-config/css/index.css"),
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
//#region Documentation
|
||||
[
|
||||
"@docusaurus/plugin-content-docs",
|
||||
deepmerge(
|
||||
CommonDocsPluginOptions,
|
||||
/** @type {DocsPluginOptions} */ ({
|
||||
id: "docs",
|
||||
routeBasePath: "/",
|
||||
path: ".",
|
||||
exclude: [...GlobExcludeDefault],
|
||||
include: ["**/*.mdx", "**/*.md"],
|
||||
sidebarPath: "./sidebar.mjs",
|
||||
showLastUpdateTime: false,
|
||||
editUrl:
|
||||
"https://github.com/goauthentik/authentik/edit/main/docs/topics/integrations/",
|
||||
|
||||
//#region Docs Plugins
|
||||
|
||||
beforeDefaultRemarkPlugins: [
|
||||
remarkLinkRewrite([
|
||||
// ---
|
||||
["/api", "https://api.goauthentik.io"],
|
||||
["/docs", "https://docs.goauthentik.io"],
|
||||
]),
|
||||
],
|
||||
}),
|
||||
),
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
export default /** @type {Config} */ (deepmerge(CommonConfig, createDocusaurusConfig(config)));
|
@ -1,10 +0,0 @@
|
||||
import { DefaultIgnorePatterns, createESLintPackageConfig } from "@goauthentik/eslint-config";
|
||||
|
||||
export default createESLintPackageConfig({
|
||||
ignorePatterns: [
|
||||
// ---
|
||||
...DefaultIgnorePatterns,
|
||||
".docusaurus/",
|
||||
"./build",
|
||||
],
|
||||
});
|
@ -1,30 +0,0 @@
|
||||
[[plugins]]
|
||||
package = "netlify-plugin-cache"
|
||||
|
||||
[plugins.inputs]
|
||||
paths = [".docusaurus", ".cache", 'node_modules/.cache']
|
||||
|
||||
[[plugins]]
|
||||
package = "netlify-plugin-debug-cache"
|
||||
|
||||
[build]
|
||||
base = "docs"
|
||||
package = "integrations"
|
||||
command = "npm run build -w integrations"
|
||||
publish = "integrations/build"
|
||||
|
||||
[dev]
|
||||
command = "npm start"
|
||||
targetPort = 3000
|
||||
publish = "integrations/build"
|
||||
|
||||
[context.production.environment]
|
||||
NODE_ENV = "production"
|
||||
|
||||
[context.dev.environment]
|
||||
NODE_ENV = "development"
|
||||
|
||||
[[headers]]
|
||||
for = "/*"
|
||||
[headers.values]
|
||||
X-Frame-Options = "DENY"
|
@ -1,164 +0,0 @@
|
||||
---
|
||||
title: Integrate with Omada Controller
|
||||
sidebar_label: Omada Controller
|
||||
support_level: community
|
||||
---
|
||||
|
||||
## What is Omada Controller
|
||||
|
||||
> Omada Controller is a software platform used to centrally manage and monitor Omada networking devices like access points, switches, and routers. It provides a single interface for configuring, managing, and monitoring these devices, offering centralized control over your entire Omada network.
|
||||
>
|
||||
> -- https://www.omadanetworks.com/
|
||||
|
||||
## Preparation
|
||||
|
||||
The following placeholders are used in this guide:
|
||||
|
||||
- `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 Omada Controller with authentik, you need to create property mappings, a group, and an application/provider pair in authentik.
|
||||
|
||||
### Create property mappings in authentik
|
||||
|
||||
1. Log in to authentik as an administrator, and open the authentik Admin interface.
|
||||
2. Navigate to **Customization** > **Property Mappings**, click **Create**, select **SAML Provider Property Mappings**, and click **Next**.
|
||||
3. Configure the first mapping for the user's _given name_ (first name):
|
||||
- **Name**: `givenname`
|
||||
- **SAML Attribute Name**: `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname`
|
||||
- **Friendly Name**: Leave blank
|
||||
- **Expression**:
|
||||
|
||||
```python
|
||||
return request.user.name.split(" ", 1)[0]
|
||||
```
|
||||
|
||||
4. Click **Finish** to save. Then, repeat the process to create a mapping for the user's _surname_:
|
||||
- **Name**: `surname`
|
||||
- **SAML Attribute Name**: `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname`
|
||||
- **Friendly Name**: Leave blank
|
||||
- **Expression**:
|
||||
|
||||
```python
|
||||
return request.user.name.split(" ", 1)[-1]
|
||||
```
|
||||
|
||||
5. Click **Finish** to save. Then, repeat the process to create a mapping for the user's _group memberships_:
|
||||
- **Name**: `usergroup_name`
|
||||
- **SAML Attribute Name**: `usergroup_name`
|
||||
- **Friendly Name**: Leave blank
|
||||
- **Expression**:
|
||||
|
||||
```python
|
||||
for group in user.ak_groups.all():
|
||||
yield group.name
|
||||
```
|
||||
|
||||
6. Click **Finish** to save. Finally, repeat the process to create a mapping for the user's _username_:
|
||||
- **Name**: `username`
|
||||
- **SAML Attribute Name**: `username`
|
||||
- **Friendly Name**: Leave blank
|
||||
- **Expression**:
|
||||
|
||||
```python
|
||||
return request.user.username
|
||||
```
|
||||
|
||||
7. Click **Finish**.
|
||||
|
||||
### Create a group in authentik
|
||||
|
||||
1. Log in to authentik as an administrator and open the authentik Admin interface.
|
||||
2. Navigate to **Directory** > **Groups** and click **Create**.
|
||||
3. Set a name for the group (e.g. `Omada-admins`) and click **Create**.
|
||||
4. Click the name of the newly created group, then switch to the **Users** tab.
|
||||
5. Click **Add existing user**, select the user who needs Omada Controller administrator access, and click **Add**.
|
||||
|
||||
### Create an application and provider in authentik
|
||||
|
||||
1. Log in to authentik as an administrator, 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, and 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.
|
||||
- Note the application slug, it will be required when filling out the **Identity provider SSO URL** later on.
|
||||
- **Choose a Provider type**: select **SAML Provider** 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.
|
||||
- **ACS URL**:
|
||||
- For Cloud Controllers: `https://aps1-omada-account.tplinkcloud.com/sso/saml/login/`
|
||||
- For Software/Hardware Controllers: `https://<controller_ip_address>:8043/sso/saml/login`
|
||||
- **Issuer**:
|
||||
- For Cloud Controllers: `https://omada.tplinkcloud.com/`
|
||||
- For Software and Hardware Controllers: `https://<controller_ip_address>:8043`
|
||||
- Set the **Service Provider Binding** to `Post`.
|
||||
- Under **Advanced protocol settings**:
|
||||
- Set an available signing certificate.
|
||||
- Set **NameID Property Mapping** to `authentik default SAML Mapping: UPN`
|
||||
- Under **Property mappings**:
|
||||
- Select only the following **User Property Mappings**:
|
||||
- `authentik default SAML Mapping: Email`
|
||||
- `authentik default SAML Mapping: Name`
|
||||
- `authentik default SAML Mapping: UPN`
|
||||
- `givenname`
|
||||
- `surname`
|
||||
- `usergroup_name`
|
||||
- `username`
|
||||
- **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.
|
||||
|
||||
### Copy the metadata URL
|
||||
|
||||
1. Log into authentik as an administrator, and open the authentik Admin interface.
|
||||
2. Navigate to **Applications** > **Providers** and click on the name of the newly created Omada Controller provider.
|
||||
3. Under **Metadata**, click the **Copy Download URL**. This metadata URL will be required in the next section.
|
||||
|
||||
## Omada Controller configuration
|
||||
|
||||
1. Log in to the Omada Controller.
|
||||
2. Navigate to **Global View** > **Settings** > **SAML SSO**, and then click **Add New SAML Connection**.
|
||||
3. Set **Identity Provider Name** to `authentik`.
|
||||
4. Select `Metadata URL` as the **Configuration Method**, and then paste the metadata URL that you copied from authentik.
|
||||
5. Click **Load Info**, and then click **Send**.
|
||||
6. In the **Actions** column, click on the **Details** button next to the newly created authentik SAML connection.
|
||||
7. Take note of the **Entity ID**, **Omada ID**, **Resource ID**, and then click **OK**. These values will be required in the next section.
|
||||
8. At the top right of the page, click **Go To SAML Role**, and then **Add New SAML Role**.
|
||||
9. Set the desired **SAML Role Name**, **Role**, **User Type**, and **Privileges** for the new SAML role. The **SAML Role Name** must match the name of the previously created authentik group.
|
||||
10. Click **Create**.
|
||||
|
||||
## Encoding default relay state
|
||||
|
||||
The default relay state is generated by Base64-encoding a combination of the **Resource ID** and **Omada ID**, separated by an underscore (`_`).
|
||||
|
||||
You can generate the relay state value using one of the following methods:
|
||||
|
||||
### Linux and macOS
|
||||
|
||||
```bash
|
||||
echo -n '<Resource_ID>_<Omada_ID>' | base64 --wrap=0
|
||||
```
|
||||
|
||||
### Windows (PowerShell):
|
||||
|
||||
```powershell
|
||||
[Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes('<Resource_ID>_<Omada_ID>'))
|
||||
```
|
||||
|
||||
## Reconfigure authentik provider
|
||||
|
||||
1. Log in to authentik as an administrator, and open the authentik Admin interface.
|
||||
2. Navigate to **Applications** > **Providers** and click the **Edit** icon next to the newly created Omada Controller provider.
|
||||
3. Set **Issuer** to the **Entity ID** value from Omada Controller.
|
||||
4. Under **Advanced protocol settings**, set **Default relay state** to the encoded value from the previous section.
|
||||
5. Click **Update** to save your changes.
|
||||
|
||||
## Configuration verification
|
||||
|
||||
To verify that authentik is correctly integrated with Omada Controller, first log out of Omada Controller. Log in to authentik and click on the Omada Controller application in the application dashboard, and you should then be redirected to the Omada Controller dashboard.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Omada Networks Documentation - How to Configure SAML SSO on Omada Controller](https://www.omadanetworks.com/de/support/faq/4406/#_Toc193896083)
|
@ -1,22 +0,0 @@
|
||||
{
|
||||
"name": "@goauthentik/integration-docs",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "run-s build:types build:docusaurus",
|
||||
"build:docusaurus": "docusaurus build",
|
||||
"build:types": "tsc -b .",
|
||||
"deploy": "docusaurus deploy",
|
||||
"docusaurus": "docusaurus",
|
||||
"serve": "docusaurus serve",
|
||||
"start": "docusaurus start",
|
||||
"test": "node --test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@goauthentik/docusaurus-theme": "*"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/**
|
||||
* @file Sidebar configuration for the authentik integrations.
|
||||
*
|
||||
* @import { SidebarItemConfig } from "@docusaurus/plugin-content-docs/src/sidebars/types.js"
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type {ReadonlyArray<readonly [string, string]>}
|
||||
*/
|
||||
const categories = [
|
||||
["chat-communication-collaboration", "Chat, Communication & Collaboration"],
|
||||
["device-management", "Device Management"],
|
||||
["cloud-providers", "Cloud Providers"],
|
||||
["dashboards", "Dashboards"],
|
||||
["development", "Development"],
|
||||
["documentation", "Documentation"],
|
||||
["hypervisors-orchestrators", "Hypervisors / Orchestrators"],
|
||||
["infrastructure", "Infrastructure"],
|
||||
["networking", "Networking"],
|
||||
["media", "Media"],
|
||||
["miscellaneous", "Miscellaneous"],
|
||||
["monitoring", "Monitoring"],
|
||||
["platforms", "Platforms"],
|
||||
["security", "Security"],
|
||||
];
|
||||
|
||||
export default /** @type {SidebarItemConfig} */
|
||||
({
|
||||
integrations: [
|
||||
{
|
||||
type: "doc",
|
||||
id: "index",
|
||||
},
|
||||
{
|
||||
type: "doc",
|
||||
id: "applications",
|
||||
},
|
||||
...categories.map(([dirName, label]) => ({
|
||||
type: "category",
|
||||
label,
|
||||
items: [
|
||||
{
|
||||
type: "autogenerated",
|
||||
dirName,
|
||||
},
|
||||
],
|
||||
})),
|
||||
],
|
||||
});
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"references": [
|
||||
{
|
||||
"path": "../docusaurus-theme"
|
||||
}
|
||||
]
|
||||
}
|
13
docs/integrations/types/globals.d.ts
vendored
13
docs/integrations/types/globals.d.ts
vendored
@ -1,13 +0,0 @@
|
||||
/**
|
||||
* @file Supplemental type definitions for Docusaurus.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Docusaurus uses an unconventional module resolution strategy, which can lead to
|
||||
* issues when using TypeScript.
|
||||
*
|
||||
* The types in this file are intended to expose less visible types to TypeScript's
|
||||
* project references, allowing for better type checking and autocompletion.
|
||||
*/
|
||||
/// <reference types="@docusaurus/plugin-content-docs" />
|
||||
/// <reference types="@docusaurus/theme-classic" />
|
@ -1,101 +0,0 @@
|
||||
{
|
||||
"name": "@goauthentik/docs",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "run-s build:types build:docusaurus",
|
||||
"build:docusaurus": "npm run build -w topics",
|
||||
"build:types": "tsc -b",
|
||||
"docusaurus": "docusaurus",
|
||||
"lint": "eslint --fix .",
|
||||
"lint-check": "eslint --max-warnings 0 .",
|
||||
"prettier": "prettier --write .",
|
||||
"prettier-check": "prettier --check .",
|
||||
"start": "npm start -w topics"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^3.8.1",
|
||||
"@docusaurus/faster": "^3.8.1",
|
||||
"@docusaurus/module-type-aliases": "^3.8.1",
|
||||
"@docusaurus/plugin-client-redirects": "^3.8.1",
|
||||
"@docusaurus/plugin-content-docs": "^3.8.1",
|
||||
"@docusaurus/preset-classic": "^3.8.1",
|
||||
"@docusaurus/remark-plugin-npm2yarn": "^3.8.1",
|
||||
"@docusaurus/theme-common": "^3.8.1",
|
||||
"@docusaurus/theme-mermaid": "^3.8.1",
|
||||
"@docusaurus/tsconfig": "^3.8.1",
|
||||
"@docusaurus/types": "^3.8.1",
|
||||
"@eslint/js": "^9.29.0",
|
||||
"@goauthentik/docusaurus-config": "^2.1.1",
|
||||
"@goauthentik/docusaurus-theme": "*",
|
||||
"@goauthentik/eslint-config": "^1.0.5",
|
||||
"@goauthentik/prettier-config": "^2.0.1",
|
||||
"@goauthentik/tsconfig": "^1.0.4",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@reduxjs/toolkit": "^1.7.1",
|
||||
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
||||
"@types/lodash": "^4.17.18",
|
||||
"@types/node": "^24.0.3",
|
||||
"@types/pako": "^2.0.3",
|
||||
"@types/pidusage": "^2.0.5",
|
||||
"@types/postman-collection": "^3.5.11",
|
||||
"@types/react": "^18.3.23",
|
||||
"@types/react-dom": "^18.3.7",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.34.1",
|
||||
"@typescript-eslint/parser": "^8.34.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"docusaurus-plugin-openapi-docs": "^4.4.0",
|
||||
"docusaurus-theme-openapi-docs": "^4.4.0",
|
||||
"eslint": "^9.29.0",
|
||||
"fast-glob": "^3.3.3",
|
||||
"netlify-cli": "^22.2.1",
|
||||
"netlify-plugin-cache": "^1.0.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"pako": "^2.1.0",
|
||||
"pidtree": "^0.6.0",
|
||||
"pidusage": "^4.0.1",
|
||||
"postcss": "^8.5.6",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-packagejson": "^2.5.15",
|
||||
"prism-react-renderer": "^2.4.1",
|
||||
"react": "^18.3.1",
|
||||
"react-before-after-slider-component": "^1.1.8",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-redux": "^7.2.0",
|
||||
"remark-directive": "^4.0.0",
|
||||
"remark-github": "^12.0.0",
|
||||
"semver": "^7.7.2",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.35.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rspack/binding-darwin-arm64": "1.3.15",
|
||||
"@rspack/binding-linux-arm64-gnu": "1.3.15",
|
||||
"@rspack/binding-linux-x64-gnu": "1.3.15",
|
||||
"@swc/core-darwin-arm64": "1.12.7",
|
||||
"@swc/core-linux-arm64-gnu": "1.12.7",
|
||||
"@swc/core-linux-x64-gnu": "1.12.7",
|
||||
"@swc/html-darwin-arm64": "1.12.7",
|
||||
"@swc/html-linux-arm64-gnu": "1.12.7",
|
||||
"@swc/html-linux-x64-gnu": "1.12.7",
|
||||
"lightningcss-darwin-arm64": "1.30.1",
|
||||
"lightningcss-linux-arm64-gnu": "1.30.1",
|
||||
"lightningcss-linux-x64-gnu": "1.30.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
},
|
||||
"workspaces": [
|
||||
"api",
|
||||
"docusaurus-theme",
|
||||
"integrations",
|
||||
"topics"
|
||||
],
|
||||
"prettier": "@goauthentik/prettier-config",
|
||||
"overrides": {
|
||||
"@rspack/core": "1.4.0-rc.0"
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
module.exports = import("./docusaurus.config.esm.mjs").then(($) => $.default);
|
@ -1,92 +0,0 @@
|
||||
/**
|
||||
* @file Docusaurus Documentation config.
|
||||
*
|
||||
* @import { Config } from "@docusaurus/types";
|
||||
* @import { UserThemeConfig, UserThemeConfigExtra } from "@goauthentik/docusaurus-config";
|
||||
* @import { Options as DocsPluginOptions } from "@docusaurus/plugin-content-docs";
|
||||
* @import { ReleasesPluginOptions } from "@goauthentik/docusaurus-theme/releases/plugin"
|
||||
*/
|
||||
import { createDocusaurusConfig } from "@goauthentik/docusaurus-config";
|
||||
import { CommonConfig, CommonDocsPluginOptions } from "@goauthentik/docusaurus-theme/config";
|
||||
import { remarkLinkRewrite } from "@goauthentik/docusaurus-theme/remark";
|
||||
|
||||
import { GlobExcludeDefault } from "@docusaurus/utils";
|
||||
import { deepmerge } from "deepmerge-ts";
|
||||
import { createRequire } from "node:module";
|
||||
import { resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
/**
|
||||
* Documentation site configuration for Docusaurus.
|
||||
* @satisfies {Partial<Config>}
|
||||
*/
|
||||
const config = {
|
||||
staticDirectories: [
|
||||
// ---
|
||||
resolve(__dirname, "..", "static"),
|
||||
"static",
|
||||
],
|
||||
|
||||
themes: ["@goauthentik/docusaurus-theme"],
|
||||
|
||||
themeConfig: /** @type {UserThemeConfig & UserThemeConfigExtra} */ ({
|
||||
navbarReplacements: {
|
||||
DOCS_URL: "/",
|
||||
},
|
||||
algolia: {
|
||||
externalUrlRegex: /^(?:https?:\/\/)(integrations|api).?(goauthentik.io)/.source,
|
||||
},
|
||||
}),
|
||||
|
||||
plugins: [
|
||||
[
|
||||
"@docusaurus/theme-classic",
|
||||
{
|
||||
customCss: require.resolve("@goauthentik/docusaurus-config/css/index.css"),
|
||||
},
|
||||
],
|
||||
|
||||
[
|
||||
"@goauthentik/docusaurus-theme/releases/plugin",
|
||||
/** @type {ReleasesPluginOptions} */ ({
|
||||
docsDirectory: __dirname,
|
||||
}),
|
||||
],
|
||||
|
||||
//#region Documentation
|
||||
|
||||
[
|
||||
"@docusaurus/plugin-content-docs",
|
||||
deepmerge(
|
||||
CommonDocsPluginOptions,
|
||||
/** @type {DocsPluginOptions} */ ({
|
||||
id: "docs",
|
||||
routeBasePath: "/",
|
||||
path: ".",
|
||||
exclude: [...GlobExcludeDefault],
|
||||
include: ["**/*.mdx", "**/*.md"],
|
||||
|
||||
sidebarPath: "./sidebar.mjs",
|
||||
showLastUpdateTime: false,
|
||||
editUrl: "https://github.com/goauthentik/authentik/edit/main/docs/",
|
||||
|
||||
//#region Docs Plugins
|
||||
|
||||
beforeDefaultRemarkPlugins: [
|
||||
remarkLinkRewrite([
|
||||
// ---
|
||||
["/docs", ""],
|
||||
["/api", "https://api.goauthentik.io"],
|
||||
["/integrations", "https://integrations.goauthentik.io"],
|
||||
]),
|
||||
],
|
||||
}),
|
||||
),
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
export default /** @type {Config} */ (deepmerge(CommonConfig, createDocusaurusConfig(config)));
|
@ -1,46 +0,0 @@
|
||||
[[plugins]]
|
||||
package = "netlify-plugin-cache"
|
||||
|
||||
[plugins.inputs]
|
||||
paths = [".docusaurus", ".cache", 'node_modules/.cache']
|
||||
|
||||
[[plugins]]
|
||||
package = "netlify-plugin-debug-cache"
|
||||
|
||||
[build]
|
||||
base = "docs"
|
||||
package = "topics"
|
||||
command = "npm run build -w topics"
|
||||
publish = "topics/build"
|
||||
|
||||
[dev]
|
||||
command = "npm start"
|
||||
targetPort = 3000
|
||||
publish = "topics/build"
|
||||
|
||||
[context.production.environment]
|
||||
NODE_ENV = "production"
|
||||
|
||||
[context.dev.environment]
|
||||
NODE_ENV = "development"
|
||||
|
||||
# Migration from docs to separate directory
|
||||
[[redirects]]
|
||||
from = "/docs/integrations/*"
|
||||
to = "https://integrations.goauthentik.io/:splat"
|
||||
status = 302
|
||||
|
||||
[[redirects]]
|
||||
from = "/integrations/*"
|
||||
to = "https://integrations.goauthentik.io/:splat"
|
||||
status = 302
|
||||
|
||||
[[redirects]]
|
||||
from = "/docs/*"
|
||||
to = "/:splat"
|
||||
status = 302
|
||||
|
||||
[[headers]]
|
||||
for = "/*"
|
||||
[headers.values]
|
||||
X-Frame-Options = "DENY"
|
@ -1,22 +0,0 @@
|
||||
{
|
||||
"name": "@goauthentik/docs-topics",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "run-s build:types build:docusaurus",
|
||||
"build:docusaurus": "docusaurus build",
|
||||
"build:types": "tsc -b .",
|
||||
"deploy": "docusaurus deploy",
|
||||
"docusaurus": "docusaurus",
|
||||
"serve": "docusaurus serve",
|
||||
"start": "docusaurus start",
|
||||
"test": "node --test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@goauthentik/docusaurus-theme": "*"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24"
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
# CVE-2025-52553
|
||||
|
||||
_Reported by [SPIEGEL-Verlag](https://gruppe.spiegel.de)_
|
||||
|
||||
## Insufficient Session verification for Remote Access Control endpoint access
|
||||
|
||||
### Summary
|
||||
|
||||
After authorizing access to a RAC endpoint, authentik creates a token which is used for a single connection and is sent to the client in the URL. This token is intended to only be valid for the session of the user who authorized the connection, however this check is currently missing.
|
||||
|
||||
### Patches
|
||||
|
||||
authentik 2025.4.3 and 2025.6.3 fix this issue.
|
||||
|
||||
### Impact
|
||||
|
||||
When for example using RAC during a screenshare, a malicious user could access the same session by copying the URL from the shown browser.
|
||||
|
||||
### Workarounds
|
||||
|
||||
As a workaround it is recommended to decrease the duration a token is valid for (in the RAC Provider settings, set **Connection expiry** to `minutes=5` for example). We also recommend enabling the option **Delete authorization on disconnect**.
|
||||
|
||||
### For more information
|
||||
|
||||
If you have any questions or comments about this advisory:
|
||||
|
||||
- Email us at [security@goauthentik.io](mailto:security@goauthentik.io).
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"references": [
|
||||
{
|
||||
"path": "../docusaurus-theme"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
// @file TSConfig used by the docs package during development.
|
||||
//
|
||||
// @remarks
|
||||
// While this configuration will influence the IDE experience,
|
||||
// Docusaurus will instead use an internal configuration to build the site.
|
||||
//
|
||||
// @see https://docusaurus.io/docs/typescript-support
|
||||
{
|
||||
"extends": "./tsconfig.base.json",
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./docusaurus-theme"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "./api"
|
||||
},
|
||||
|
||||
{
|
||||
"path": "./integrations"
|
||||
},
|
||||
{
|
||||
"path": "./topics"
|
||||
}
|
||||
]
|
||||
}
|
2
go.mod
2
go.mod
@ -29,7 +29,7 @@ require (
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/wwt/guac v1.3.2
|
||||
goauthentik.io/api/v3 v3.2025063.1
|
||||
goauthentik.io/api/v3 v3.2025062.6
|
||||
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.15.0
|
||||
|
4
go.sum
4
go.sum
@ -298,8 +298,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
|
||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
goauthentik.io/api/v3 v3.2025063.1 h1:zvKhZTESgMY/SNiLuTs7G0YleBnev1v7+S9Xd6PZ9bc=
|
||||
goauthentik.io/api/v3 v3.2025063.1/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
goauthentik.io/api/v3 v3.2025062.6 h1:rlChhGP2vJufYCaTMb4sbRBEE1p2uL5T4HzMqF1AJ4A=
|
||||
goauthentik.io/api/v3 v3.2025062.6/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
@ -33,4 +33,4 @@ func UserAgent() string {
|
||||
return fmt.Sprintf("authentik@%s", FullVersion())
|
||||
}
|
||||
|
||||
const VERSION = "2025.6.3"
|
||||
const VERSION = "2025.6.2"
|
||||
|
@ -26,7 +26,7 @@ Parameters:
|
||||
Description: authentik Docker image
|
||||
AuthentikVersion:
|
||||
Type: String
|
||||
Default: 2025.6.3
|
||||
Default: 2025.6.2
|
||||
Description: authentik Docker image tag
|
||||
AuthentikServerCPU:
|
||||
Type: Number
|
||||
|
Binary file not shown.
@ -11,18 +11,18 @@
|
||||
# Nicola Mersi, 2024
|
||||
# tmassimi, 2024
|
||||
# Marc Schmitt, 2024
|
||||
# albanobattistella <albanobattistella@gmail.com>, 2024
|
||||
# Matteo Piccina <altermatte@gmail.com>, 2025
|
||||
# Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025
|
||||
# albanobattistella <albanobattistella@gmail.com>, 2025
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-25 00:10+0000\n"
|
||||
"POT-Creation-Date: 2025-05-28 11:25+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: albanobattistella <albanobattistella@gmail.com>, 2025\n"
|
||||
"Last-Translator: Kowalski Dragon (kowalski7cc) <kowalski.7cc@gmail.com>, 2025\n"
|
||||
"Language-Team: Italian (https://app.transifex.com/authentik/teams/119923/it/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -116,7 +116,7 @@ msgstr "Certificato Web utilizzato dal server Web authentik Core."
|
||||
|
||||
#: authentik/brands/models.py
|
||||
msgid "Certificates used for client authentication."
|
||||
msgstr "Certificati utilizzati per l'autenticazione del client."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/brands/models.py
|
||||
msgid "Brand"
|
||||
@ -130,6 +130,10 @@ msgstr "Brands"
|
||||
msgid "User does not have access to application."
|
||||
msgstr "L'utente non ha accesso all'applicazione."
|
||||
|
||||
#: authentik/core/api/devices.py
|
||||
msgid "Extra description not available"
|
||||
msgstr "Descrizione extra non disponibile"
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "Cannot set group as parent of itself."
|
||||
msgstr "Impossibile impostare il gruppo come padre di se stesso."
|
||||
@ -290,15 +294,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Collegamento a un utente con indirizzo email identico. Può avere "
|
||||
"implicazioni sulla sicurezza quando una fonte non convalida gli indirizzi "
|
||||
"email."
|
||||
"e-mail."
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid ""
|
||||
"Use the user's email address, but deny enrollment when the email address "
|
||||
"already exists."
|
||||
msgstr ""
|
||||
"Usa l'indirizzo email dell'utente, ma nega l'iscrizione quando l'indirizzo "
|
||||
"email esiste già."
|
||||
"Usa l'indirizzo e-mail dell'utente, ma nega l'iscrizione quando l'indirizzo "
|
||||
"e-mail esiste già."
|
||||
|
||||
#: authentik/core/models.py
|
||||
msgid ""
|
||||
@ -678,29 +682,26 @@ msgid ""
|
||||
"option has a higher priority than the `client_certificate` option on "
|
||||
"`Brand`."
|
||||
msgstr ""
|
||||
"Configura le autorità di certificazione per convalidare il certificato. "
|
||||
"Questa opzione ha una priorità maggiore rispetto all'opzione "
|
||||
"`client_certificate` su `Brand`."
|
||||
|
||||
#: authentik/enterprise/stages/mtls/models.py
|
||||
msgid "Mutual TLS Stage"
|
||||
msgstr "Fase di TLS reciproca"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/mtls/models.py
|
||||
msgid "Mutual TLS Stages"
|
||||
msgstr "Fasi di TLS reciproche"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/mtls/models.py
|
||||
msgid "Permissions to pass Certificates for outposts."
|
||||
msgstr " Permessi di trasmissione dei Certificati per gli avamposti."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/mtls/stage.py
|
||||
msgid "Certificate required but no certificate was given."
|
||||
msgstr " Il certificato è stato richiesto ma non è stato consegnato."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/mtls/stage.py
|
||||
msgid "No user found for certificate."
|
||||
msgstr "Nessun utente trovato per il certificato."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/enterprise/stages/source/models.py
|
||||
msgid ""
|
||||
@ -833,14 +834,6 @@ msgstr ""
|
||||
"Definisci a quale gruppo di utenti deve essere inviata e mostrata questa "
|
||||
"notifica. Se lasciato vuoto, la notifica non verrà inviata."
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"When enabled, notification will be sent to user the user that triggered the "
|
||||
"event.When destination_group is configured, notification is sent to both."
|
||||
msgstr ""
|
||||
"Se abilitata, la notifica verrà inviata all'utente che ha attivato l'evento."
|
||||
" Se destination_group è configurato, la notifica verrà inviata a entrambi."
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid "Notification Rule"
|
||||
msgstr "Regola di notifica"
|
||||
@ -1057,16 +1050,16 @@ msgstr "Avvio della sincronizzazione completa del provider"
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Syncing users"
|
||||
msgstr "Sincronizzazione degli utenti"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Syncing groups"
|
||||
msgstr "Sincronizzazione dei gruppi"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
#, python-brace-format
|
||||
msgid "Syncing page {page} of {object_type}"
|
||||
msgstr "Sincronizzazione della pagina {page} di {object_type}"
|
||||
msgid "Syncing page {page} of groups"
|
||||
msgstr "Sincronizzando pagina {page} dei gruppi"
|
||||
|
||||
#: authentik/lib/sync/outgoing/tasks.py
|
||||
msgid "Dropping mutating request due to dry run"
|
||||
@ -2468,10 +2461,6 @@ msgstr "Gruppo di aggiunta DN"
|
||||
msgid "Consider Objects matching this filter to be Users."
|
||||
msgstr "Considerare gli oggetti corrispondenti a questo filtro come Utenti."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "Attribute which matches the value of `group_membership_field`."
|
||||
msgstr "Attributo che corrisponde al valore di `group_membership_field`."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "Field which contains members of a group."
|
||||
msgstr "Campo che contiene i membri di un gruppo."
|
||||
@ -2513,8 +2502,6 @@ msgid ""
|
||||
"Delete authentik users and groups which were previously supplied by this "
|
||||
"source, but are now missing from it."
|
||||
msgstr ""
|
||||
"Elimina gli utenti e i gruppi authentik precedentemente forniti da questa "
|
||||
"fonte, ma che ora mancano."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "LDAP Source"
|
||||
@ -2536,8 +2523,6 @@ msgstr "Mappature delle proprietà della sorgente LDAP"
|
||||
msgid ""
|
||||
"Unique ID used while checking if this object still exists in the directory."
|
||||
msgstr ""
|
||||
"ID univoco utilizzato per verificare se questo oggetto esiste ancora nella "
|
||||
"directory."
|
||||
|
||||
#: authentik/sources/ldap/models.py
|
||||
msgid "User LDAP Source Connection"
|
||||
@ -2935,7 +2920,7 @@ msgstr "Connessioni sorgente SAML di gruppo"
|
||||
#: authentik/sources/saml/views.py
|
||||
#, python-brace-format
|
||||
msgid "Continue to {source_name}"
|
||||
msgstr "Continua su {source_name}"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/sources/scim/models.py
|
||||
msgid "SCIM Source"
|
||||
@ -3003,8 +2988,8 @@ msgstr "Fasi di configurazione dell'autenticatore email"
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Exception occurred while rendering E-mail template"
|
||||
msgstr ""
|
||||
"Si è verificata un'eccezione durante la visualizzazione del modello di posta"
|
||||
" elettronica"
|
||||
"Eccezione verificatasi durante la visualizzazione del modello di posta "
|
||||
"elettronica"
|
||||
|
||||
#: authentik/stages/authenticator_email/models.py
|
||||
msgid "Email Device"
|
||||
@ -3043,7 +3028,7 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Codice MFA via email.\n"
|
||||
" Codice MFA via e-mail.\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.html
|
||||
@ -3069,7 +3054,7 @@ msgid ""
|
||||
"Email MFA code\n"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Codice email MFA\n"
|
||||
"Codice e-mail MFA\n"
|
||||
|
||||
#: authentik/stages/authenticator_email/templates/email/email_otp.txt
|
||||
#, python-format
|
||||
@ -3336,7 +3321,7 @@ msgstr "Consensi utente"
|
||||
|
||||
#: authentik/stages/consent/stage.py
|
||||
msgid "Invalid consent token, re-showing prompt"
|
||||
msgstr "Token di consenso non valido, viene nuovamente visualizzato il prompt"
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/deny/models.py
|
||||
msgid "Deny Stage"
|
||||
@ -3356,11 +3341,11 @@ msgstr "Fasi fittizie"
|
||||
|
||||
#: authentik/stages/email/flow.py
|
||||
msgid "Continue to confirm this email address."
|
||||
msgstr "Continua per confermare questo indirizzo email."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/flow.py
|
||||
msgid "Link was already used, please request a new link."
|
||||
msgstr "Il collegamento è già stato utilizzato. Richiedine uno nuovo."
|
||||
msgstr ""
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Password Reset"
|
||||
@ -3380,7 +3365,7 @@ msgstr "Fase email"
|
||||
|
||||
#: authentik/stages/email/models.py
|
||||
msgid "Email Stages"
|
||||
msgstr "Fasi email"
|
||||
msgstr "Fasi Email"
|
||||
|
||||
#: authentik/stages/email/stage.py
|
||||
msgid "Successfully verified Email."
|
||||
@ -3482,7 +3467,7 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Se non hai richiesto una modifica della password, ignora questa email. Il link sopra è valido per %(expires)s.\n"
|
||||
" Se non hai richiesto una modifica della password, ignora questa e-mail. Il link sopra è valido per %(expires)s.\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/password_reset.txt
|
||||
@ -3500,11 +3485,11 @@ msgid ""
|
||||
"If you did not request a password change, please ignore this email. The link above is valid for %(expires)s.\n"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Se non hai richiesto una modifica della password, ignora questa email. Il link sopra è valido per %(expires)s.\n"
|
||||
"Se non hai richiesto una modifica della password, ignora questa e-mail. Il link sopra è valido per %(expires)s.\n"
|
||||
|
||||
#: authentik/stages/email/templates/email/setup.html
|
||||
msgid "authentik Test-Email"
|
||||
msgstr "email di prova di authentik"
|
||||
msgstr "e-mail di prova di authentik"
|
||||
|
||||
#: authentik/stages/email/templates/email/setup.html
|
||||
msgid ""
|
||||
@ -3513,7 +3498,7 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" Questa è un'email di prova per informarti che hai configurato correttamente le email di authentik.\n"
|
||||
" Questa è un'e-mail di prova per informarti che hai configurato correttamente le e-mail di authentik.\n"
|
||||
" "
|
||||
|
||||
#: authentik/stages/email/templates/email/setup.txt
|
||||
@ -3522,7 +3507,7 @@ msgid ""
|
||||
"This is a test email to inform you, that you've successfully configured authentik emails.\n"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"Questa è un'email di prova per informarti che hai configurato correttamente le email di authentik.\n"
|
||||
"Questa è un'e-mail di prova per informarti che hai configurato correttamente le e-mail di authentik.\n"
|
||||
|
||||
#: authentik/stages/identification/api.py
|
||||
msgid "When no user fields are selected, at least one source must be selected"
|
||||
@ -3725,7 +3710,7 @@ msgstr ""
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid "Email: Text field with Email type."
|
||||
msgstr "Email: Campo di testo con il tipo di email."
|
||||
msgstr "E-mail: Campo di testo con il tipo di e-mail."
|
||||
|
||||
#: authentik/stages/prompt/models.py
|
||||
msgid ""
|
||||
@ -3880,6 +3865,10 @@ msgstr "Fasi di accesso utente"
|
||||
msgid "No Pending user to login."
|
||||
msgstr "Nessun utente in attesa di accesso."
|
||||
|
||||
#: authentik/stages/user_login/stage.py
|
||||
msgid "Successfully logged in!"
|
||||
msgstr "Accesso effettuato!"
|
||||
|
||||
#: authentik/stages/user_logout/models.py
|
||||
msgid "User Logout Stage"
|
||||
msgstr "Fase di disconnessione dell'utente"
|
||||
|
Binary file not shown.
@ -15,7 +15,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-25 00:10+0000\n"
|
||||
"POT-Creation-Date: 2025-06-04 00:12+0000\n"
|
||||
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
|
||||
"Last-Translator: deluxghost, 2025\n"
|
||||
"Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\n"
|
||||
@ -118,6 +118,10 @@ msgstr "品牌"
|
||||
msgid "User does not have access to application."
|
||||
msgstr "用户没有访问此应用程序的权限。"
|
||||
|
||||
#: authentik/core/api/devices.py
|
||||
msgid "Extra description not available"
|
||||
msgstr "额外描述不可用"
|
||||
|
||||
#: authentik/core/api/groups.py
|
||||
msgid "Cannot set group as parent of itself."
|
||||
msgstr "无法设置组自身为父级。"
|
||||
@ -771,12 +775,6 @@ msgid ""
|
||||
"If left empty, Notification won't ben sent."
|
||||
msgstr "定义此通知应该发送到哪些用户组。如果留空,则不会发送通知。"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid ""
|
||||
"When enabled, notification will be sent to user the user that triggered the "
|
||||
"event.When destination_group is configured, notification is sent to both."
|
||||
msgstr "启用时,通知会被发送到触发事件的用户。当配置了 destination_group 时,通知也会同时发送到对应组。"
|
||||
|
||||
#: authentik/events/models.py
|
||||
msgid "Notification Rule"
|
||||
msgstr "通知规则"
|
||||
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user