Compare commits
5 Commits
website/do
...
docusaurus
Author | SHA1 | Date | |
---|---|---|---|
95d6ffe898 | |||
8a5f755605 | |||
582812b3ec | |||
b10c795a26 | |||
8088e08fd9 |
4
.github/dependabot.yml
vendored
@ -78,13 +78,13 @@ updates:
|
||||
patterns:
|
||||
- "@goauthentik/*"
|
||||
- package-ecosystem: npm
|
||||
directory: "/website"
|
||||
directory: "/docs"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "04:00"
|
||||
open-pull-requests-limit: 10
|
||||
commit-message:
|
||||
prefix: "website:"
|
||||
prefix: "docs:"
|
||||
labels:
|
||||
- dependencies
|
||||
groups:
|
||||
|
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 website`)
|
||||
- [ ] The documentation has been formatted (`make docs`)
|
||||
|
83
.github/workflows/ci-api-docs.yml
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
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,4 +1,4 @@
|
||||
name: authentik-ci-website
|
||||
name: authentik-ci-docs
|
||||
|
||||
on:
|
||||
push:
|
||||
@ -18,50 +18,47 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
command:
|
||||
- lint:lockfile
|
||||
- prettier-check
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- working-directory: website/
|
||||
- name: Install dependencies
|
||||
working-directory: docs/
|
||||
run: npm ci
|
||||
- name: Lint
|
||||
working-directory: website/
|
||||
working-directory: docs/
|
||||
run: npm run ${{ matrix.command }}
|
||||
test:
|
||||
build-topics:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: website/package.json
|
||||
node-version-file: docs/package.json
|
||||
cache: "npm"
|
||||
cache-dependency-path: website/package-lock.json
|
||||
- working-directory: website/
|
||||
cache-dependency-path: docs/package-lock.json
|
||||
- working-directory: docs/
|
||||
name: Install Dependencies
|
||||
run: npm ci
|
||||
- name: test
|
||||
working-directory: website/
|
||||
run: npm test
|
||||
build:
|
||||
- name: Build Documentation via Docusaurus
|
||||
working-directory: docs/
|
||||
run: npm run build
|
||||
build-integrations:
|
||||
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: website/package.json
|
||||
node-version-file: docs/package.json
|
||||
cache: "npm"
|
||||
cache-dependency-path: website/package-lock.json
|
||||
- working-directory: website/
|
||||
cache-dependency-path: docs/package-lock.json
|
||||
- working-directory: docs/
|
||||
name: Install Dependencies
|
||||
run: npm ci
|
||||
- name: build
|
||||
working-directory: website/
|
||||
run: npm run ${{ matrix.job }}
|
||||
- name: Build Integrations via Docusaurus
|
||||
working-directory: docs/
|
||||
run: npm run build -w integrations
|
||||
build-container:
|
||||
if: ${{ github.repository != 'goauthentik/authentik-internal' }}
|
||||
runs-on: ubuntu-latest
|
||||
@ -98,7 +95,7 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
tags: ${{ steps.ev.outputs.imageTags }}
|
||||
file: website/Dockerfile
|
||||
file: docs/Dockerfile
|
||||
push: ${{ steps.ev.outputs.shouldPush == 'true' }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
@ -111,12 +108,12 @@ jobs:
|
||||
subject-name: ${{ steps.ev.outputs.attestImageNames }}
|
||||
subject-digest: ${{ steps.push.outputs.digest }}
|
||||
push-to-registry: true
|
||||
ci-website-mark:
|
||||
ci-docs-mark:
|
||||
if: always()
|
||||
needs:
|
||||
- lint
|
||||
- test
|
||||
- build
|
||||
- build-topics
|
||||
- build-integrations
|
||||
- build-container
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
4
.github/workflows/ci-outpost.yml
vendored
@ -24,8 +24,8 @@ jobs:
|
||||
run: |
|
||||
# Create folder structure for go embeds
|
||||
mkdir -p web/dist
|
||||
mkdir -p website/help
|
||||
touch web/dist/test website/help/test
|
||||
mkdir -p docs/help
|
||||
touch web/dist/test docs/help/test
|
||||
- name: Generate API
|
||||
run: make gen-client-go
|
||||
- name: golangci-lint
|
||||
|
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: website/Dockerfile
|
||||
file: docs/Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
context: .
|
||||
|
@ -10,7 +10,7 @@ coverage
|
||||
dist
|
||||
out
|
||||
.docusaurus
|
||||
website/docs/developer-docs/api/**/*
|
||||
docs/api/reference
|
||||
|
||||
## Environment
|
||||
*.env
|
||||
|
44
.vscode/tasks.json
vendored
@ -4,12 +4,7 @@
|
||||
{
|
||||
"label": "authentik/core: make",
|
||||
"command": "uv",
|
||||
"args": [
|
||||
"run",
|
||||
"make",
|
||||
"lint-fix",
|
||||
"lint"
|
||||
],
|
||||
"args": ["run", "make", "lint-fix", "lint"],
|
||||
"presentation": {
|
||||
"panel": "new"
|
||||
},
|
||||
@ -18,11 +13,7 @@
|
||||
{
|
||||
"label": "authentik/core: run",
|
||||
"command": "uv",
|
||||
"args": [
|
||||
"run",
|
||||
"ak",
|
||||
"server"
|
||||
],
|
||||
"args": ["run", "ak", "server"],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"panel": "dedicated",
|
||||
@ -32,17 +23,13 @@
|
||||
{
|
||||
"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",
|
||||
@ -52,26 +39,19 @@
|
||||
{
|
||||
"label": "authentik: install",
|
||||
"command": "make",
|
||||
"args": [
|
||||
"install",
|
||||
"-j4"
|
||||
],
|
||||
"args": ["install", "-j4"],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "authentik/website: make",
|
||||
"label": "authentik/docs: make",
|
||||
"command": "make",
|
||||
"args": [
|
||||
"website"
|
||||
],
|
||||
"args": ["docs"],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "authentik/website: watch",
|
||||
"label": "authentik/docs: watch",
|
||||
"command": "make",
|
||||
"args": [
|
||||
"website-watch"
|
||||
],
|
||||
"args": ["docs-watch"],
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"panel": "dedicated",
|
||||
@ -81,11 +61,7 @@
|
||||
{
|
||||
"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
|
||||
website/ @goauthentik/docs
|
||||
docs/ @goauthentik/docs
|
||||
CODE_OF_CONDUCT.md @goauthentik/docs
|
||||
# Security
|
||||
SECURITY.md @goauthentik/security @goauthentik/docs
|
||||
website/docs/security/ @goauthentik/security @goauthentik/docs
|
||||
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 ./website /work/website/
|
||||
COPY ./docs /work/docs/
|
||||
COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
|
||||
|
||||
RUN npm run build && \
|
||||
|
2
LICENSE
@ -1,7 +1,7 @@
|
||||
Copyright (c) 2023 Jens Langhammer
|
||||
|
||||
Portions of this software are licensed as follows:
|
||||
* All content residing under the "website/" directory of this repository is licensed under "Creative Commons: CC BY-SA 4.0 license".
|
||||
* All content residing under the "docs/" 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
@ -1,4 +1,4 @@
|
||||
.PHONY: gen dev-reset all clean test web website
|
||||
.PHONY: gen dev-reset all clean test web docs
|
||||
|
||||
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 website \
|
||||
--ignore docs \
|
||||
-l en
|
||||
|
||||
install: web-install website-install core-install ## Install all requires dependencies for `web`, `website` and `core`
|
||||
install: web-install docs-install core-install ## Install all requires dependencies for `web`, `docs` 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
|
||||
|
||||
#########################
|
||||
## Website
|
||||
## Docs
|
||||
#########################
|
||||
|
||||
website: website-lint-fix website-build ## Automatically fix formatting issues in the Authentik website/docs source code, lint the code, and compile it
|
||||
docs: docs-lint-fix docs-build ## Automatically fix formatting issues in the Authentik docs source code, lint the code, and compile it
|
||||
|
||||
website-install:
|
||||
cd website && npm ci
|
||||
docs-install:
|
||||
npm ci --prefix docs
|
||||
|
||||
website-lint-fix: lint-codespell
|
||||
cd website && npm run prettier
|
||||
docs-lint-fix: lint-codespell
|
||||
npm run prettier --prefix docs
|
||||
|
||||
website-build:
|
||||
cd website && npm run build
|
||||
docs-build:
|
||||
npm run build --prefix docs
|
||||
|
||||
website-watch: ## Build and watch the documentation website, updating automatically
|
||||
cd website && npm run watch
|
||||
docs-watch: ## Build and watch the documentation website, updating automatically
|
||||
npm run watch --prefix docs
|
||||
|
||||
#########################
|
||||
## Docker
|
||||
|
@ -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 ../../website/docs/install-config/configuration/configuration.mdx Configuration documentation} for more information.
|
||||
# @see {@link ../../docs/topics/install-config/configuration/configuration.mdx Configuration documentation} for more information.
|
||||
|
||||
postgresql:
|
||||
host: localhost
|
||||
|
9
docs/.browserslistrc
Normal file
@ -0,0 +1,9 @@
|
||||
[production]
|
||||
> 0.2%
|
||||
not dead
|
||||
not op_mini all
|
||||
|
||||
[development]
|
||||
last 1 chrome version
|
||||
last 1 firefox version
|
||||
last 1 safari version
|
12
website/.gitignore → docs/.gitignore
vendored
@ -2,6 +2,8 @@
|
||||
/node_modules
|
||||
|
||||
# Production
|
||||
/api/build
|
||||
/integrations/build
|
||||
/build
|
||||
/out
|
||||
/help
|
||||
@ -9,6 +11,7 @@
|
||||
# Generated files
|
||||
.docusaurus
|
||||
.cache-loader
|
||||
cache-output.json
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
@ -24,7 +27,8 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
static/docker-compose.yml
|
||||
static/schema.yml
|
||||
static/releases.gen.json
|
||||
docs/developer-docs/api/reference/**
|
||||
**/static/docker-compose.yml
|
||||
**/static/schema.yml
|
||||
**/static/releases.gen.json
|
||||
api/reference
|
||||
!integrations/**/media
|
20
docs/Dockerfile
Normal file
@ -0,0 +1,20 @@
|
||||
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,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://docs.goauthentik.io/integrations?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://integrations.goauthentik.io?utm_source=github).
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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 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 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).
|
||||
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).
|
||||
|
||||
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.
|
18
docs/api/authentication.md
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
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.
|
15
docs/api/clients.mdx
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
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 />
|
17
docs/api/clients/golang.md
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
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.
|
33
docs/api/clients/node.md
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
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.
|
||||
:::
|
13
docs/api/clients/python.md
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
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
docs/api/docusaurus.config.cjs
Normal file
@ -0,0 +1 @@
|
||||
module.exports = import("./docusaurus.config.esm.mjs").then(($) => $.default);
|
161
docs/api/docusaurus.config.esm.mjs
Normal file
@ -0,0 +1,161 @@
|
||||
/**
|
||||
* @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);
|
11
docs/api/ensure-reference-sidebar.mjs
Normal file
@ -0,0 +1,11 @@
|
||||
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,17 +1,11 @@
|
||||
import { DefaultIgnorePatterns, createESLintPackageConfig } from "@goauthentik/eslint-config";
|
||||
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* ESLint configuration for authentik's monorepo.
|
||||
*/
|
||||
const ESLintConfig = createESLintPackageConfig({
|
||||
export default createESLintPackageConfig({
|
||||
ignorePatterns: [
|
||||
// ---
|
||||
...DefaultIgnorePatterns,
|
||||
".docusaurus/",
|
||||
"./build",
|
||||
"./reference",
|
||||
],
|
||||
});
|
||||
|
||||
export default ESLintConfig;
|
@ -1,8 +1,9 @@
|
||||
---
|
||||
title: Flow executor (backend)
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
A big focus of authentik is the flows system, which allows you to combine and build complex conditional processes using stages and policies. Normally, these flows are automatically executed in the browser using authentik's [standard browser-based flow executor (/if/flows)](../../add-secure-apps/flows-stages/flow/executors/if-flow.md).
|
||||
A big focus of authentik is the flows system, which allows you to combine and build complex conditional processes using stages and policies. Normally, these flows are automatically executed in the browser using authentik's [standard browser-based flow executor (/if/flows)](/docs/add-secure-apps/flows-stages/flow/executors/if-flow).
|
||||
|
||||
However, any flow can be executed via an API from anywhere, in fact that is what every flow executor does. With a few requests you can execute flows from anywhere, and integrate authentik even better.
|
||||
|
||||
@ -64,7 +65,7 @@ Depending on the flow, you'll either get a 200 Response with another challenge,
|
||||
|
||||
Depending also on the stage, a response might take longer to be returned (especially with the Duo Authenticator validation).
|
||||
|
||||
To see the data layout for every stage possible, see the [API Browser](./reference/flows-executor-get)
|
||||
<!-- To see the data layout for every stage possible, see the [API Browser](./reference/flows-executor-get) -->
|
||||
|
||||
## Result
|
||||
|
16
docs/api/index.md
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
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.
|
30
docs/api/netlify.toml
Normal file
@ -0,0 +1,30 @@
|
||||
[[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"
|
24
docs/api/package.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"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": "*"
|
||||
}
|
||||
}
|
65
docs/api/sidebar.mjs
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @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;
|
25
docs/api/src/templates/api.mustache
Normal file
@ -0,0 +1,25 @@
|
||||
---
|
||||
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}}}
|
75
docs/api/src/theme/ApiItem/Layout/index.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
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>
|
||||
);
|
||||
}
|
10
docs/api/src/theme/ApiItem/Layout/styles.module.css
Normal file
@ -0,0 +1,10 @@
|
||||
.docItemContainer header + *,
|
||||
.docItemContainer article > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 997px) {
|
||||
.docItemCol {
|
||||
max-width: 75% !important;
|
||||
}
|
||||
}
|
245
docs/api/src/theme/ApiItem/index.tsx
Normal file
@ -0,0 +1,245 @@
|
||||
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;
|
44
docs/api/src/theme/ApiItem/store.ts
Normal file
@ -0,0 +1,44 @@
|
||||
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"];
|
70
docs/api/src/theme/DocSidebarItem/Link/index.tsx
Normal file
@ -0,0 +1,70 @@
|
||||
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;
|
127
docs/api/src/theme/DocSidebarItem/Link/styles.css
Normal file
@ -0,0 +1,127 @@
|
||||
.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;
|
||||
}
|
||||
}
|
8
docs/api/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"references": [
|
||||
{
|
||||
"path": "../docusaurus-theme"
|
||||
}
|
||||
]
|
||||
}
|
37
docs/api/types/api-plugin.d.ts
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/// <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
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @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,5 +1,7 @@
|
||||
---
|
||||
title: Websocket API
|
||||
sidebar_position: 3
|
||||
sidebar_label: Websockets
|
||||
---
|
||||
|
||||
authentik has two different WebSocket endpoints, one is used for web-based clients to get real-time updates, and the other is used for outposts to report their healthiness.
|
@ -1,4 +1,5 @@
|
||||
import { SupportLevelToLabel, isSupportLevel } from "@site/remark/support-directive.mjs";
|
||||
import { SupportLevelToLabel, isSupportLevel } from "#remark/support-directive.mjs";
|
||||
|
||||
import React from "react";
|
||||
|
||||
export interface SupportBadgeProps {
|
@ -0,0 +1,97 @@
|
||||
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>
|
||||
);
|
||||
},
|
||||
);
|
@ -0,0 +1,76 @@
|
||||
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}
|
||||
/>
|
||||
);
|
||||
};
|
32
docs/docusaurus-theme/components/VersionPicker/index.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
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}
|
||||
/>
|
||||
);
|
||||
};
|
33
docs/docusaurus-theme/components/VersionPicker/styles.css
Normal file
@ -0,0 +1,33 @@
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
81
docs/docusaurus-theme/components/VersionPicker/utils.ts
Normal file
@ -0,0 +1,81 @@
|
||||
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;
|
||||
}
|
85
docs/docusaurus-theme/config.js
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @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,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
3
docs/docusaurus-theme/eslint.config.mjs
Normal file
@ -0,0 +1,3 @@
|
||||
import { createESLintPackageConfig } from "@goauthentik/eslint-config";
|
||||
|
||||
export default createESLintPackageConfig();
|
21
docs/docusaurus-theme/index.js
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @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";
|
||||
},
|
||||
};
|
||||
}
|
23
docs/docusaurus-theme/package.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"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/*"
|
||||
}
|
||||
}
|
65
docs/docusaurus-theme/releases/plugin.mjs
Normal file
@ -0,0 +1,65 @@
|
||||
/* 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;
|
69
docs/docusaurus-theme/releases/utils.mjs
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @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;
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
* @file Remark plugin to transform `ak-enterprise` directives into badges.
|
||||
*
|
||||
* @import { Root } from "mdast";
|
||||
* @import {} from "mdast-util-directive";
|
||||
*/
|
||||
import { h } from "hastscript";
|
||||
import { SKIP, visit } from "unist-util-visit";
|
||||
@ -9,7 +10,7 @@ import { SKIP, visit } from "unist-util-visit";
|
||||
/**
|
||||
* MDAST plugin to transform `ak-enterprise` directives into badges.
|
||||
*/
|
||||
function remarkEnterpriseDirective() {
|
||||
export function remarkEnterpriseDirective() {
|
||||
/**
|
||||
* @param {Root} tree The MDAST tree to transform.
|
||||
*/
|
5
docs/docusaurus-theme/remark/index.mjs
Normal file
@ -0,0 +1,5 @@
|
||||
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";
|
35
docs/docusaurus-theme/remark/link-rewrite-directive.mjs
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @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;
|
@ -2,6 +2,7 @@
|
||||
* @file Remark plugin to transform `ak-preview` directives into preview badges.
|
||||
*
|
||||
* @import { Root } from "mdast";
|
||||
* @import {} from "mdast-util-directive";
|
||||
*/
|
||||
import { h } from "hastscript";
|
||||
import { SKIP, visit } from "unist-util-visit";
|
||||
@ -9,7 +10,7 @@ import { SKIP, visit } from "unist-util-visit";
|
||||
/**
|
||||
* MDAST plugin to transform `ak-preview` directives into preview badges.
|
||||
*/
|
||||
function remarkPreviewDirective() {
|
||||
export function remarkPreviewDirective() {
|
||||
/**
|
||||
* @param {Root} tree The MDAST tree to transform.
|
||||
*/
|
@ -2,6 +2,7 @@
|
||||
* @file Remark plugin to transform `ak-support` directives into support level badges.
|
||||
*
|
||||
* @import { Root } from "mdast";
|
||||
* @import {} from "mdast-util-directive";
|
||||
*/
|
||||
import { h } from "hastscript";
|
||||
import { SKIP, visit } from "unist-util-visit";
|
||||
@ -36,7 +37,7 @@ export function isSupportLevel(input) {
|
||||
/**
|
||||
* MDAST plugin to transform `ak-support` directives into preview badges.
|
||||
*/
|
||||
function remarkSupportDirective() {
|
||||
export function remarkSupportDirective() {
|
||||
/**
|
||||
* @param {Root} tree The MDAST tree to transform.
|
||||
*/
|
@ -2,6 +2,7 @@
|
||||
* @file Remark plugin to transform `ak-version` directives into version badges.
|
||||
*
|
||||
* @import { Root } from "mdast";
|
||||
* @import {} from "mdast-util-directive";
|
||||
*/
|
||||
import { h } from "hastscript";
|
||||
import { coerce } from "semver";
|
||||
@ -22,7 +23,7 @@ import { SKIP, visit } from "unist-util-visit";
|
||||
* # Feature Foobar <span class="badge badge--version">authentik: v1.2.3+</span>
|
||||
* ```
|
||||
*/
|
||||
function remarkVersionDirective() {
|
||||
export function remarkVersionDirective() {
|
||||
/**
|
||||
* @param {Root} tree The MDAST tree to transform.
|
||||
*/
|
@ -1,4 +1,3 @@
|
||||
/// <reference types="@docusaurus/plugin-content-docs" />
|
||||
/**
|
||||
* @file Swizzled DocItemContent component.
|
||||
*
|
||||
@ -8,11 +7,13 @@
|
||||
* the content of a documentation page. However, it also adds support for
|
||||
* support badges, and Authentik version badges.
|
||||
*/
|
||||
import { SupportBadge } from "#components/SupportBadge.tsx";
|
||||
import { VersionBadge } from "#components/VersionBadge.tsx";
|
||||
|
||||
import { useSyntheticTitle } from "#hooks/title.ts";
|
||||
|
||||
import { useDoc } from "@docusaurus/plugin-content-docs/client";
|
||||
import { ThemeClassNames } from "@docusaurus/theme-common";
|
||||
import { SupportBadge } from "@site/src/components/SupportBadge";
|
||||
import { VersionBadge } from "@site/src/components/VersionBadge";
|
||||
import { useSyntheticTitle } from "@site/src/hooks/title";
|
||||
import type { Props } from "@theme/DocItem/Content";
|
||||
import Heading from "@theme/Heading";
|
||||
import MDXContent from "@theme/MDXContent";
|
||||
@ -57,6 +58,22 @@ function useBadgeLinterEffect() {
|
||||
}, [hide_title, id]);
|
||||
}
|
||||
|
||||
interface BadgesProps {
|
||||
badges: JSX.Element[];
|
||||
}
|
||||
|
||||
const BadgeGroup: React.FC<BadgesProps> = ({ badges }) => {
|
||||
if (!badges.length) return null;
|
||||
|
||||
return (
|
||||
<p className="badge-group">
|
||||
{badges.map((badge, index) => (
|
||||
<React.Fragment key={index}>{badge}</React.Fragment>
|
||||
))}
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
const DocItemContent: React.FC<Props> = ({ children }) => {
|
||||
const syntheticTitle = useSyntheticTitle();
|
||||
const { frontMatter, metadata, contentTitle } = useDoc();
|
||||
@ -116,20 +133,4 @@ const DocItemContent: React.FC<Props> = ({ children }) => {
|
||||
);
|
||||
};
|
||||
|
||||
interface BadgesProps {
|
||||
badges: JSX.Element[];
|
||||
}
|
||||
|
||||
const BadgeGroup: React.FC<BadgesProps> = ({ badges }) => {
|
||||
if (!badges.length) return null;
|
||||
|
||||
return (
|
||||
<p className="badge-group">
|
||||
{badges.map((badge, index) => (
|
||||
<React.Fragment key={index}>{badge}</React.Fragment>
|
||||
))}
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocItemContent;
|
26
docs/docusaurus-theme/theme/DocSidebarItems/index.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
/// <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);
|
3
docs/docusaurus-theme/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json"
|
||||
}
|
@ -10,17 +10,11 @@
|
||||
* project references, allowing for better type checking and autocompletion.
|
||||
*/
|
||||
|
||||
declare module "@docusaurus/plugin-content-docs-types" {
|
||||
export * from "@docusaurus/plugin-content-docs";
|
||||
export * from "@docusaurus/plugin-content-docs/src/types.ts";
|
||||
export * from "@docusaurus/plugin-content-docs/src/sidebars/types.ts";
|
||||
}
|
||||
|
||||
declare module "@docusaurus/plugin-content-docs/src/sidebars/types" {
|
||||
export * from "@docusaurus/plugin-content-docs/src/sidebars/types.ts";
|
||||
}
|
||||
|
||||
declare module "@docusaurus/plugin-content-docs/client" {
|
||||
export * from "@docusaurus/plugin-content-docs/lib/client/doc.js";
|
||||
export * from "@docusaurus/plugin-content-docs/lib/client/docSidebarItemsExpandedState.js";
|
||||
export * from "@docusaurus/plugin-content-docs/lib/client/docsUtils.js";
|
||||
|
||||
import { DocContextValue as BaseDocContextValue } from "@docusaurus/plugin-content-docs/lib/client/doc.js";
|
||||
import { DocFrontMatter as BaseDocFrontMatter } from "@docusaurus/plugin-content-docs";
|
||||
|
44
docs/docusaurus-theme/types/globals.d.ts
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @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"];
|
||||
}
|
||||
}
|
11
docs/eslint.config.mjs
Normal file
@ -0,0 +1,11 @@
|
||||
import { DefaultIgnorePatterns, createESLintPackageConfig } from "@goauthentik/eslint-config";
|
||||
|
||||
export default createESLintPackageConfig({
|
||||
ignorePatterns: [
|
||||
// ---
|
||||
...DefaultIgnorePatterns,
|
||||
"**/.docusaurus/",
|
||||
"**/build",
|
||||
"**/reference",
|
||||
],
|
||||
});
|
@ -1,9 +1,11 @@
|
||||
---
|
||||
title: Integrate with Applications
|
||||
sidebar_label: Applications
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
import SupportBadge from "@site/src/components/SupportBadge";
|
||||
import SupportBadge from "@goauthentik/docusaurus-theme/components/SupportBadge.tsx";
|
||||
|
||||
import DocCardList from "@theme/DocCardList";
|
||||
|
||||
# Applications
|
||||
@ -23,14 +25,12 @@ All documented app integrations will have one of these badges:
|
||||
|
||||
<a id="add-new"></a>
|
||||
|
||||
To add documentation for a new application (with support level Community or Vendor), please use the integration template [`service.md`](https://github.com/goauthentik/authentik/blob/main/website/integrations/template/service.md) file from our GitHub repo. You can download the template file using the following command:
|
||||
To add documentation for a new application (with support level Community or Vendor), please use the integration template [`service.md`](https://github.com/goauthentik/authentik/blob/main/docs/topics/integrations/template/service.md) file from our GitHub repo. You can download the template file using the following command:
|
||||
|
||||
```shell
|
||||
wget https://raw.githubusercontent.com/goauthentik/authentik/main/website/integrations/template/service.md
|
||||
wget https://raw.githubusercontent.com/goauthentik/authentik/main/docs/topics/integrations/template/service.md
|
||||
```
|
||||
|
||||
Don't forget to edit the `website/sidebars/integrations.mjs` file to add your new integration to the appropriate section in the lefthand navigation pane.
|
||||
|
||||
## Integration categories
|
||||
|
||||
<DocCardList />
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
@ -19,7 +19,7 @@ The following placeholders are used in this guide:
|
||||
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.
|
||||
:::
|
||||
|
||||
For additional information about integrating with Slack, refer to their [documentation](https://slack.com/help/articles/205168057-Custom-SAML-single-sign-on).
|
||||
For additional information about integrating with Slack, refer to their [documentation](https://slack.com/help/topics/205168057-Custom-SAML-single-sign-on).
|
||||
|
||||
## authentik configuration
|
||||
|