Compare commits

..

1 Commits

Author SHA1 Message Date
3d8be6d699 website: bump docusaurus-theme-openapi-docs in /website
Bumps [docusaurus-theme-openapi-docs](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/tree/HEAD/packages/docusaurus-theme-openapi-docs) from 4.4.0 to 4.5.1.
- [Release notes](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/releases)
- [Changelog](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/commits/v4.5.1/packages/docusaurus-theme-openapi-docs)

---
updated-dependencies:
- dependency-name: docusaurus-theme-openapi-docs
  dependency-version: 4.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 18:24:16 +00:00
712 changed files with 5811 additions and 18938 deletions

View File

@ -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:

View File

@ -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`)

View File

@ -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 }}

View File

@ -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

View File

@ -1,4 +1,4 @@
name: authentik-ci-docs
name: authentik-ci-website
on:
push:
@ -18,47 +18,50 @@ 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
@ -95,7 +98,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,12 +111,12 @@ 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:

View File

@ -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: .

View File

@ -10,7 +10,7 @@ coverage
dist
out
.docusaurus
docs/api/reference
website/docs/developer-docs/api/**/*
## Environment
*.env

44
.vscode/tasks.json vendored
View File

@ -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"
}
]

View File

@ -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

View File

@ -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 && \

View File

@ -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.

View File

@ -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

View File

@ -13,7 +13,7 @@
# 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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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 />

View File

@ -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.

View File

@ -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.
:::

View File

@ -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
```

View File

@ -1 +0,0 @@
module.exports = import("./docusaurus.config.esm.mjs").then(($) => $.default);

View File

@ -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);

View File

@ -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);
}

View File

@ -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.

View File

@ -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"

View File

@ -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": "*"
}
}

View File

@ -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;

View File

@ -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}}}

View File

@ -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>
);
}

View File

@ -1,10 +0,0 @@
.docItemContainer header + *,
.docItemContainer article > *:first-child {
margin-top: 0;
}
@media (min-width: 997px) {
.docItemCol {
max-width: 75% !important;
}
}

View File

@ -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;

View File

@ -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"];

View File

@ -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;

View File

@ -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;
}
}

View File

@ -1,8 +0,0 @@
{
"extends": "../tsconfig.base.json",
"references": [
{
"path": "../docusaurus-theme"
}
]
}

View File

@ -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;
}

View File

@ -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"];
}
}

View File

@ -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>
);
},
);

View File

@ -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}
/>
);
};

View File

@ -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}
/>
);
};

View File

@ -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);
}
}
}

View File

@ -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;
}

View File

@ -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,
},
],
],
};

View File

@ -1,3 +0,0 @@
import { createESLintPackageConfig } from "@goauthentik/eslint-config";
export default createESLintPackageConfig();

View File

@ -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";
},
};
}

View File

@ -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/*"
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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";

View File

@ -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;

View File

@ -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);

View File

@ -1,3 +0,0 @@
{
"extends": "../tsconfig.base.json"
}

View File

@ -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"];
}
}

View File

@ -1,11 +0,0 @@
import { DefaultIgnorePatterns, createESLintPackageConfig } from "@goauthentik/eslint-config";
export default createESLintPackageConfig({
ignorePatterns: [
// ---
...DefaultIgnorePatterns,
"**/.docusaurus/",
"**/build",
"**/reference",
],
});

View File

@ -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;
}

View File

@ -1 +0,0 @@
module.exports = import("./docusaurus.config.esm.mjs").then(($) => $.default);

View File

@ -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)));

View File

@ -1,10 +0,0 @@
import { DefaultIgnorePatterns, createESLintPackageConfig } from "@goauthentik/eslint-config";
export default createESLintPackageConfig({
ignorePatterns: [
// ---
...DefaultIgnorePatterns,
".docusaurus/",
"./build",
],
});

View File

@ -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"

View File

@ -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"
}
}

View File

@ -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,
},
],
})),
],
});

View File

@ -1,8 +0,0 @@
{
"extends": "../tsconfig.base.json",
"references": [
{
"path": "../docusaurus-theme"
}
]
}

View File

@ -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" />

View File

@ -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"
}
}

View File

@ -1 +0,0 @@
module.exports = import("./docusaurus.config.esm.mjs").then(($) => $.default);

View File

@ -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)));

View File

@ -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"

View File

@ -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"
}
}

View File

@ -1,8 +0,0 @@
{
"extends": "../tsconfig.base.json",
"references": [
{
"path": "../docusaurus-theme"
}
]
}

View File

@ -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"
}
]
}

View File

@ -23,8 +23,8 @@ export const DefaultIgnorePatterns = [
"**/out",
"**/dist",
"**/.wireit",
"docs/**/build/**",
"docs/.docusaurus/**",
"website/build/**",
"website/.docusaurus/**",
"**/node_modules",
"**/coverage",
"**/storybook-static",

View File

@ -144,9 +144,7 @@ skip = [
"**/web/out",
"./web/storybook-static",
"./web/custom-elements.json",
"./docs/build",
"./docs/api/build",
"./docs/integrations/build",
"./website/build",
"./gen-ts-api",
"./gen-py-api",
"./gen-go-api",
@ -201,7 +199,7 @@ omit = [
"*/migrations/*",
"*/management/commands/*",
"*/apps.py",
"docs/",
"website/",
]
[tool.coverage.report]

View File

@ -39,10 +39,8 @@ const pluginName = "mdx-plugin";
* @returns {Plugin}
*/
export function mdxPlugin({ root }) {
const prefix = "~docs";
// TODO: Replace with `resolvePackage` after NPM Workspaces support is added.
const docsPackageRoot = path.resolve(MonoRepoRoot, "docs");
const docsPackageRoot = path.resolve(MonoRepoRoot, "website");
/**
* @param {PluginBuild} build
@ -56,8 +54,7 @@ export function mdxPlugin({ root }) {
if (!args.path.startsWith("~")) return args;
return {
path: path.join(docsPackageRoot, "topics", args.path.slice(prefix.length)),
path: path.resolve(docsPackageRoot, args.path.slice(1)),
pluginName,
};
}
@ -77,7 +74,7 @@ export function mdxPlugin({ root }) {
const publicPath = path.resolve(
"/",
path.relative(path.join(root, "docs", "topics"), data.path),
path.relative(path.join(root, "website"), data.path),
);
const publicDirectory = path.dirname(publicPath);

View File

@ -163,7 +163,7 @@ export class ProxyProviderViewPage extends AKElement {
return input;
}
const extHost = new URL(this.provider.externalHost);
// See docs/topics/add-secure-apps/providers/proxy/forward_auth.mdx
// See website/docs/add-secure-apps/providers/proxy/forward_auth.mdx
if (this.provider?.mode === ProxyMode.ForwardSingle) {
return input
.replaceAll("authentik.company", window.location.hostname)

View File

@ -7,6 +7,7 @@ import { MDXWrapper } from "#elements/ak-mdx/components/MDXWrapper";
import { remarkAdmonition } from "#elements/ak-mdx/remark/remark-admonition";
import { remarkHeadings } from "#elements/ak-mdx/remark/remark-headings";
import { remarkLists } from "#elements/ak-mdx/remark/remark-lists";
import { WithAuthentikConfig } from "#elements/mixins/config";
import { DistDirectoryName, StaticDirectoryName } from "#paths";
import { compile as compileMDX, run as runMDX } from "@mdx-js/mdx";
import apacheGrammar from "highlight.js/lib/languages/apache";

View File

@ -1,8 +1,8 @@
import { useMDXModule } from "#elements/ak-mdx/MDXModuleContext";
import { useMDXModule } from "@goauthentik/elements/ak-mdx/MDXModuleContext";
import { resolve } from "node:path";
import React from "react";
import React, { memo } from "react";
const DOCS_DOMAIN = "https://docs.goauthentik.io";
const DOCS_DOMAIN = "https://goauthentik.io";
/**
* A custom anchor element that applies special behavior for MDX content.

View File

@ -2,8 +2,6 @@
/node_modules
# Production
/api/build
/integrations/build
/build
/out
/help
@ -11,7 +9,6 @@
# Generated files
.docusaurus
.cache-loader
cache-output.json
# Misc
.DS_Store
@ -27,8 +24,7 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/static/docker-compose.yml
**/static/schema.yml
**/static/releases.gen.json
api/reference
!integrations/**/media
static/docker-compose.yml
static/schema.yml
static/releases.gen.json
docs/developer-docs/api/reference/**

21
website/Dockerfile Normal file
View File

@ -0,0 +1,21 @@
FROM --platform=${BUILDPLATFORM} docker.io/library/node:24 AS website-builder
ENV NODE_ENV=production
WORKDIR /work/website
RUN --mount=type=bind,target=/work/website/package.json,src=./website/package.json \
--mount=type=bind,target=/work/website/package-lock.json,src=./website/package-lock.json \
--mount=type=cache,id=npm-website,sharing=shared,target=/root/.npm \
npm ci --include=dev
COPY ./website /work/website/
COPY ./blueprints /work/blueprints/
COPY ./schema.yml /work/
COPY ./SECURITY.md /work/
RUN npm run build-bundled
FROM docker.io/library/nginx:1.27.5
COPY --from=website-builder /work/website/build /usr/share/nginx/html

View File

@ -1,11 +1,11 @@
# authentik documentation source
This directory contains the source files for the [authentik technical documentation](https://docs.goauthentik.io/docs?utm_source=github) and the [authentik integration guides](https://integrations.goauthentik.io?utm_source=github).
This directory contains the source files for the [authentik technical documentation](https://docs.goauthentik.io/docs?utm_source=github) and the [authentik integration guides](https://docs.goauthentik.io/integrations?utm_source=github).
Contributions are welcome! Please refer to our [contributor guidelines](https://docs.goauthentik.io/developer-docs?utm_source=github) for details about contributing code or docs.
Contributions are welcome! Please refer to our [contributor guidelines](https://docs.goauthentik.io/docs/developer-docs?utm_source=github) for details about contributing code or docs.
For instructions to set up your local environment for building docs locally, refer to our [Docs development environment](https://docs.goauthentik.io/developer-docs/setup/website-dev-environment?utm_source=github) page.
For instructions to set up your local environment for building docs locally, refer to our [Docs development environment](https://docs.goauthentik.io/docs/developer-docs/setup/website-dev-environment?utm_source=github) page.
For instructions for writing the docs and then testing in your local build, plus tips on writing, links to our Style Guide and templates, see the [Writing documentation guide](https://docs.goauthentik.io/developer-docs/docs/writing-documentation?utm_source=github).
For instructions for writing the docs and then testing in your local build, plus tips on writing, links to our Style Guide and templates, see the [Writing documentation guide](https://docs.goauthentik.io/docs/developer-docs/docs/writing-documentation?utm_source=github).
To ensure a smooth review process, we encourage you to build the documentation locally to preview and test your documentation contributions. Be sure to test locally before opening a pull request. Let us know if you have any questions or want help with any part of the process.

View File

@ -45,7 +45,7 @@ When multiple policies/groups/users are attached, you can configure the _Policy
Application entitlements can be used through authentik to manage authorization within an application (what areas of the app users or groups can access). Entitlements are scoped to a single application and can be bound to multiple users and/or groups (binding policies is not currently supported), giving them access to the entitlement. An application can either check for the name of the entitlement (via the `entitlements` scope), or via attributes stored in entitlements.
An authentik admin can create an entitlement [in the Admin interface](#create-an-application-entitlement) or using the [authentik API](/api).
An authentik admin can create an entitlement [in the Admin interface](#create-an-application-entitlement) or using the [authentik API](../../developer-docs/api/api.md).
Because entitlements exist within an application, names of entitlements must be unique within an application. This also means that entitlements are deleted when an application is deleted.

View File

@ -7,7 +7,7 @@ As covered in the [overview](./index.md), bindings interact with many other comp
For instructions to create a binding, refer to the documentation for the specific components:
- [Bind a stage to a flow](../stages/index.md#bind-a-stage-to-a-flow)
- [Bind a policy to a flow or stage](../../../customize/policies/working_with_policies.md#bind-a-policy-to-a-flow-or-stage)
- [Bind a policy to a flow or stage](../../../customize/policies/working_with_policies#bind-a-policy-to-a-flow-or-stage)
- [Bind users or groups to a specific application with an Application Entitlement](../../applications/manage_apps.mdx#application-entitlements)
- [Bind a policy to a specific application when you create a new application and provider](../../applications/manage_apps.mdx#instructions)
- [Bind users and groups to a stage binding, to define whether or not that stage is shown](../stages/index.md#bind-users-and-groups-to-a-flows-stage-binding)

View File

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 113 KiB

View File

@ -5,7 +5,7 @@ title: Default
This is the default, web-based environment that flows are executed in. All stages are compatible with this environment and no limitations are imposed.
:::info
All flow executors use the same [API](/api/docs/flow-executor), which allows for the implementation of custom flow executors.
All flow executors use the same [API](../../../../developer-docs/api/flow-executor.md), which allows for the implementation of custom flow executors.
:::
## Layouts

View File

Before

Width:  |  Height:  |  Size: 564 KiB

After

Width:  |  Height:  |  Size: 564 KiB

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