← All articles
SECURITY Authentik: The Self-Hosted Identity Provider That Hi... 2026-02-09 · authentik · sso · identity-provider

Authentik: The Self-Hosted Identity Provider That Hits the Sweet Spot

Security 2026-02-09 authentik sso identity-provider oauth2 saml ldap security

You've outgrown simple reverse proxy authentication. You need actual OAuth2 and SAML support for your services, user self-registration for family members, and maybe an LDAP server so legacy apps can authenticate. But Keycloak feels like deploying an aircraft carrier to protect a fishing boat.

Authentik is an open-source identity provider that slots between the simplicity of Authelia and the complexity of Keycloak. It gives you a real identity provider with a polished admin UI, user self-service, OAuth2/OIDC, SAML, LDAP, and forward auth proxy — without requiring a Java runtime or a week of configuration.

What Authentik Does

Authentik vs. Authelia vs. Keycloak

Feature Authentik Authelia Keycloak
Primary role Identity provider + proxy Auth proxy only Full IAM platform
OAuth2 / OIDC Yes Yes Yes
SAML Yes No Yes
Forward auth proxy Yes Yes (primary mode) No
Built-in LDAP server Yes No (LDAP client only) No (LDAP client only)
User self-service Yes (enrollment, recovery) No Yes
Admin UI Modern, polished Minimal login portal Functional but dated
Flow customization Visual flow builder YAML config Authentication flow editor
Resource usage ~300-500 MB RAM ~30-50 MB RAM ~500 MB-1 GB RAM
Setup complexity Moderate Simple Complex
Language / Runtime Python (Django) Go Java (Quarkus)

When to choose Authentik

When to choose Authelia instead

When to choose Keycloak instead

Docker Compose Setup

Authentik requires PostgreSQL and Redis. Here is a production-ready Compose setup:

services:
  authentik-server:
    image: ghcr.io/goauthentik/server:latest
    restart: unless-stopped
    command: server
    environment:
      AUTHENTIK_REDIS__HOST: authentik-redis
      AUTHENTIK_POSTGRESQL__HOST: authentik-db
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS:?database password required}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
    volumes:
      - ./media:/media
      - ./custom-templates:/templates
    ports:
      - "9000:9000"
      - "9443:9443"
    depends_on:
      authentik-db:
        condition: service_healthy
      authentik-redis:
        condition: service_healthy

  authentik-worker:
    image: ghcr.io/goauthentik/server:latest
    restart: unless-stopped
    command: worker
    environment:
      AUTHENTIK_REDIS__HOST: authentik-redis
      AUTHENTIK_POSTGRESQL__HOST: authentik-db
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
    volumes:
      - ./media:/media
      - ./custom-templates:/templates
    depends_on:
      authentik-db:
        condition: service_healthy
      authentik-redis:
        condition: service_healthy

  authentik-db:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - authentik_db:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: authentik
      POSTGRES_USER: authentik
      POSTGRES_PASSWORD: ${PG_PASS}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d authentik -U authentik"]
      interval: 10s
      timeout: 5s
      retries: 5

  authentik-redis:
    image: redis:7-alpine
    restart: unless-stopped
    command: --save 60 1 --loglevel warning
    volumes:
      - authentik_redis:/data
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  authentik_db:
  authentik_redis:

Create a .env file:

PG_PASS=$(openssl rand -base64 36)
AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60)

Note that Authentik runs two containers from the same image: server handles the web interface and API, while worker runs background tasks like LDAP sync, email sending, and flow execution. Both are required.

First run

docker compose up -d

Navigate to http://your-server:9000/if/flow/initial-setup/ to create your admin account. This setup URL is only available on the first run — once you create the admin account, it disappears.

Connecting Services with OIDC

Most modern self-hosted apps support OpenID Connect. The pattern is consistent:

In Authentik

  1. Go to Applications → Providers → Create
  2. Select OAuth2/OpenID Connect
  3. Set a name (e.g., Grafana) and configure:
    • Authorization flow: default-provider-authorization-implicit-consent (or explicit if you want users to approve)
    • Redirect URIs: https://grafana.yourdomain.com/login/generic_oauth
  4. Copy the Client ID and Client Secret
  5. Go to Applications → Create and link it to the provider

Example: Grafana

# grafana.ini
[auth.generic_oauth]
enabled = true
name = Authentik
allow_sign_up = true
client_id = your-client-id
client_secret = your-client-secret
scopes = openid profile email
auth_url = https://auth.yourdomain.com/application/o/authorize/
token_url = https://auth.yourdomain.com/application/o/token/
api_url = https://auth.yourdomain.com/application/o/userinfo/
role_attribute_path = contains(groups[*], 'admins') && 'Admin' || 'Viewer'

Example: Portainer

Portainer supports OIDC natively:

  1. Go to Settings → Authentication → OAuth
  2. Use the Authentik provider endpoints
  3. Set the Client ID and Secret
  4. Map group claims to Portainer teams

Setting Up the LDAP Provider

This is one of Authentik's killer features. Many apps only support LDAP for external authentication — things like Jellyfin, older Nextcloud setups, or network equipment. Authentik can expose your user directory as an LDAP server.

  1. Go to Providers → Create → LDAP Provider
  2. Set the Base DN: dc=yourdomain,dc=com
  3. Set a Bind DN and password for service accounts
  4. Assign it to an Application
  5. Add LDAP port mapping to your Compose file:
  authentik-server:
    ports:
      - "9000:9000"
      - "9443:9443"
      - "389:3389"    # LDAP
      - "636:6636"    # LDAPS

Now configure your apps to authenticate against ldap://authentik-server:389 with the Base DN you set. Users managed in Authentik are automatically available over LDAP.

LDAP gotchas

Forward Auth Proxy

For services that have no native auth support, Authentik works as a forward auth proxy — similar to how Authelia works:

  1. Create a Proxy Provider in Authentik
  2. Set the external URL of your service
  3. Configure your reverse proxy to check with Authentik

Traefik example

# On your unprotected service
labels:
  - "traefik.http.routers.myapp.middlewares=authentik@docker"

# On the Authentik server
labels:
  - "traefik.http.middlewares.authentik.forwardAuth.address=http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
  - "traefik.http.middlewares.authentik.forwardAuth.trustForwardHeader=true"
  - "traefik.http.middlewares.authentik.forwardAuth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-email"

Caddy example

myapp.yourdomain.com {
    forward_auth authentik-server:9000 {
        uri /outpost.goauthentik.io/auth/caddy
        copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email
    }
    reverse_proxy myapp:8080
}

Customizing Flows

Authentik's flow system is one of its distinguishing features. Flows are visual pipelines that define what happens during login, enrollment, or password recovery.

The defaults work fine for most setups, but you can customize them:

The flow editor is drag-and-drop in the admin UI. Each stage (password prompt, MFA check, email verification) is a building block you can reorder or add conditions to.

Multi-Factor Authentication

Enable MFA globally or per-application:

  1. Go to Flows → default-authentication-flow
  2. Add an Authenticator Validation Stage after the password stage
  3. Choose which methods to allow: TOTP, WebAuthn, or static tokens

Users can configure their MFA devices at https://auth.yourdomain.com/if/user/ — the self-service portal.

WebAuthn with hardware keys (YubiKey, fingerprint readers) works well and is the strongest option. TOTP with an authenticator app is the practical default for most users.

Resource Requirements

Component RAM CPU Storage
Server container 200-400 MB 0.5 cores Minimal
Worker container 100-200 MB 0.5 cores Minimal
PostgreSQL 100-200 MB 0.25 cores 500 MB
Redis 30-50 MB Minimal 100 MB
Total ~500-800 MB ~1.5 cores ~1 GB

This is notably more than Authelia (50 MB total) but less than Keycloak (1 GB+). For a typical homelab server, the resource usage is perfectly manageable.

Common Pitfalls

Backup Strategy

Back up these things:

  1. PostgreSQL database: docker exec authentik-db pg_dump -U authentik authentik > authentik-backup.sql
  2. Media directory: Contains custom branding, icons, and uploaded files
  3. Secret key: Without it, encrypted data in the database is unrecoverable
  4. Custom templates: If you've modified login pages or email templates

The Bottom Line

Authentik occupies a genuinely useful niche. Authelia is perfect when you just need a login wall in front of your reverse proxy. Keycloak is the right choice for enterprise-scale identity management. Authentik gives you a real identity provider — with OIDC, SAML, LDAP, user self-service, and a modern UI — without the overhead and complexity of a full enterprise IAM platform.

If your services are starting to outgrow forward auth proxy and you find yourself wishing for proper OAuth2 clients, user registration flows, or an LDAP endpoint, Authentik is likely exactly what you need.

Resources