> ## Documentation Index
> Fetch the complete documentation index at: https://www.towbar.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# authentik

> authentik manages users, sign-in, and single sign-on across applications.

export const UseCaseNavigation = () => {
  useLayoutEffect(() => {
    const storageKey = "towbar-use-case-open-groups";
    const groupSelector = "#sidebar li[data-title] > button[aria-expanded]";
    let restoring = false;
    let frame = 0;
    function storedGroups() {
      try {
        return new Set(JSON.parse(sessionStorage.getItem(storageKey) || "[]"));
      } catch {
        return new Set();
      }
    }
    function save(groups) {
      try {
        sessionStorage.setItem(storageKey, JSON.stringify([...groups]));
      } catch {}
    }
    function groupName(button) {
      return button.parentElement?.dataset.title;
    }
    function rememberOpenGroups() {
      const groups = new Set();
      for (const button of document.querySelectorAll(groupSelector)) {
        if (button.getAttribute("aria-expanded") === "true") {
          const name = groupName(button);
          if (name) groups.add(name);
        }
      }
      save(groups);
    }
    function restoreOpenGroups() {
      frame = 0;
      const groups = storedGroups();
      if (!groups.size) return;
      restoring = true;
      for (const button of document.querySelectorAll(groupSelector)) {
        if (groups.has(groupName(button)) && button.getAttribute("aria-expanded") === "false") {
          button.click();
        }
      }
      restoring = false;
    }
    function scheduleRestore() {
      if (!frame) frame = requestAnimationFrame(restoreOpenGroups);
    }
    function onClick(event) {
      if (restoring || !(event.target instanceof Element)) return;
      const button = event.target.closest(groupSelector);
      if (button) {
        const name = groupName(button);
        if (!name) return;
        const groups = storedGroups();
        if (button.getAttribute("aria-expanded") === "true") groups.delete(name); else groups.add(name);
        save(groups);
        return;
      }
      if (event.target.closest('a[href^="/docs/use-cases/"]')) {
        rememberOpenGroups();
      }
    }
    const observer = new MutationObserver(scheduleRestore);
    document.addEventListener("click", onClick, true);
    observer.observe(document.getElementById("sidebar") || document.body, {
      childList: true,
      subtree: true
    });
    scheduleRestore();
    return () => {
      document.removeEventListener("click", onClick, true);
      observer.disconnect();
      cancelAnimationFrame(frame);
    };
  }, []);
  return null;
};

<UseCaseNavigation />

<img className="towbar-doc-brand-logo" src="https://mintcdn.com/avgeek/EGkEWLTQnOwecqNx/assets/use-case-logos/authentik.svg?fit=max&auto=format&n=EGkEWLTQnOwecqNx&q=85&s=516d7e8ddd359d1cbf82288c4a4c47b8" alt="authentik logo" aria-hidden="true" width="24" height="24" data-path="assets/use-case-logos/authentik.svg" />

**Upstream source:** [Current installation guide](https://docs.goauthentik.io/install-config/install/docker-compose/).

authentik needs PostgreSQL, a web server, and a background worker. Server and worker share the same application data volume. This minimal stack omits the upstream Docker socket mount, so Docker-managed outposts must be arranged separately.

## Towbar manifest

```yaml title=".towbar/services/authentik.compose.yml" theme={"system"}
id: authentik
name: authentik
file: deploy/authentik/compose.yml
strategy: maintenance
services:
  server:
    port: 9000
    domains:
      - authentik.example.com
    ingress:
      type: proxy
  postgresql: {}
  worker: {}
environments:
  production:
    server: 192.0.2.10
secrets:
  runtime:
    - PG_PASS
    - AUTHENTIK_SECRET_KEY
```

## Compose project

```yaml title="deploy/authentik/compose.yml" theme={"system"}
services:
  postgresql:
    image: postgres:16-alpine@sha256:721873c34ceb9f8d8fc265984940dc982404c105f19ad51be9fdc5970a6080ea
    environment:
      POSTGRES_DB: authentik
      POSTGRES_USER: authentik
      POSTGRES_PASSWORD: ${PG_PASS}
    volumes:
      - database:/var/lib/postgresql/data
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U authentik -d authentik
      interval: 10s
      retries: 10
  server:
    image: ghcr.io/goauthentik/server:2026.8.3@sha256:ab9b4e8cc4ab3f8d1198d2db6aeea66bafea1963b3f2843589e0d163f97d9849
    command:
      - server
    depends_on:
      postgresql:
        condition: service_healthy
    environment:
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
    volumes:
      - data:/data
  worker:
    image: ghcr.io/goauthentik/server:2026.8.3@sha256:ab9b4e8cc4ab3f8d1198d2db6aeea66bafea1963b3f2843589e0d163f97d9849
    command:
      - worker
    user: root
    depends_on:
      postgresql:
        condition: service_healthy
    environment:
      AUTHENTIK_POSTGRESQL__HOST: postgresql
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
    volumes:
      - data:/data
      - certs:/certs
volumes:
  database: {}
  data: {}
  certs: {}
```

## Configure

1. Prepare the example server, connect the repository, and map `production` to the branch containing these files. Replace the example server IP and domain.
2. Commit every file shown below under `deploy/authentik/`. The Towbar manifest points to the Compose file; it does not create it for you.
3. Sync the repository and inspect the resolved Compose project. Save the runtime values below if this example declares any.
4. Use a server with at least two CPU cores and 2 GB of RAM, as required by the upstream Compose guide. Save `PG_PASS` and `AUTHENTIK_SECRET_KEY` before deploying.
5. Back up PostgreSQL and the shared data/certificate volumes together. Without the Docker socket, deploy any future outposts manually.
6. Deploy it manually and run the verification below before enabling auto-deploy.

## Runtime values

Save these values on the Compose project after the repository sync. The manifest declares required keys, not their values.

| Key                    | Value to save                                                 |
| ---------------------- | ------------------------------------------------------------- |
| `PG_PASS`              | Generate a unique PostgreSQL password (under 100 characters). |
| `AUTHENTIK_SECRET_KEY` | Generate a long random key; retain it across upgrades.        |

## Verify

Open `/if/flow/initial-setup/` to set the first `akadmin` password, create a test application and provider, and confirm the worker is healthy after a redeploy.

For field constraints, see [Compose guide](/docs/services/modes/compose).
