Jesse A. Green / notebook

authentik — User Guide

Generated May 2026 from goauthentik/authentik at 9e75f62

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

authentik is an open-source Identity Provider (IdP) and Single Sign-On (SSO) platform built for modern, protocol-diverse environments. It speaks SAML, OAuth2 / OIDC, LDAP, RADIUS, SCIM, WS-Federation, Microsoft Entra, Google Workspace, and SSF (Shared Signals Framework) — out of one server. You self-host it, configure it once, then point every app you want to secure at it.

This guide covers everything you need to install, configure, and operate authentik day-to-day. It is written against version 2026.8.0-rc1 (commit 9e75f62). Where the upstream documentation at docs.goauthentik.io goes deeper on a particular integration, this guide links there.

Important

authentik has a dual license model. The core (MIT, in authentik/) is forever-free. The Enterprise tier (authentik/enterprise/ under a custom EE License) adds features like SSF, MS Entra/Google Workspace sync, audit logging, MTLS stage, RAC, account lockdown, and unique-password policy. The two are in the same container — your license key activates Enterprise modules at runtime.


Table of Contents

  1. What authentik Does
  2. Concepts You Must Know
  3. Quick Start (Docker Compose)
  4. Installation
  5. Initial Setup
  6. Adding Your First Application
  7. Flows and Stages
  8. Providers — Securing Apps
  9. Sources — Authenticating Users
  10. Outposts
  11. Users, Groups, and RBAC
  12. Policies and Property Mappings
  13. Blueprints — GitOps for authentik
  14. Customization and Branding
  15. Events and Notifications
  16. Backups, Upgrades, and Air-Gapped Installs
  17. Common Tasks (Recipes)
  18. CLI Reference (ak)
  19. Troubleshooting
  20. FAQ
  21. Reference Tables

1. What authentik Does

authentik sits between your users and the apps you want to secure. A user opens an app. The app hands them off to authentik. authentik proves who they are using whatever combination of password / MFA / federated login / certificate / device check you've configured. authentik hands them back to the app with a signed token (SAML assertion, OIDC ID token, etc.) that the app trusts.

Capabilities

  • Identity Provider — authentik is the source of truth for who your users are. Local users, federated users, or both.
  • Single Sign-On — sign in once at authentik, access dozens of apps without re-entering credentials.
  • Multi-protocol — SAML, OAuth2/OIDC, LDAP, RADIUS, SCIM, WS-Federation, Forward Auth (Proxy provider), Remote Access Connection (RAC, an in-browser RDP/SSH/VNC gateway).
  • Inbound federation — accept logins from external LDAP, OAuth, SAML, Kerberos, SCIM, Plex, Telegram.
  • Outbound sync — push users and groups to MS Entra ID, Google Workspace, or any SCIM endpoint.
  • Flexible MFA — TOTP, WebAuthn (passkeys, security keys), Duo, SMS, email, static codes, endpoint device attestation (GDTC).
  • Self-service — users can recover passwords, manage MFA devices, view assigned apps, edit profile fields — without admin involvement.
  • Audit trail — every login, every config change, every consent grant is logged. Forwardable to Sentry, syslog, or your SIEM.
  • GitOps-native — every object (Flow, Stage, Policy, Provider, Application, User, Group) can be expressed as a YAML blueprint and applied declaratively.

What authentik is NOT

  • Not a password manager. Users still need to remember their authentik credentials (or federate from one they already do).
  • Not a CASB or proxy gateway by itself — but the Proxy provider + an outpost gives you Forward Auth (à la Authelia / oauth2-proxy) for any app that supports header-based auth or Traefik/Nginx forward-auth.
  • Not an MDM. authentik integrates with endpoint-attestation systems but doesn't manage devices.

2. Concepts You Must Know

These six concepts run through every page of the admin UI. Learn them first.

Concept What it is Lives at
Flow An ordered sequence of stages that completes one user-facing journey (login, recovery, enrollment, invalidation). Admin → Flows and Stages → Flows
Stage A single step inside a flow (identification, password, MFA, consent, user-write, etc.). 24 stage types ship in core + EE. Admin → Flows and Stages → Stages
Policy A boolean expression (Python or rule-based) that gates whether a stage executes, an app is visible, or a flow advances. Admin → Customization → Policies
Provider Outbound protocol implementation — SAML, OAuth2, LDAP, RADIUS, Proxy, RAC, SCIM, etc. The thing apps talk to. Admin → Applications → Providers
Source Inbound protocol implementation — federated login from external IdPs. Admin → Directory → Federation & Social login
Application A user-visible "tile" in the User interface. Wraps one Provider and (optionally) some policies. Admin → Applications → Applications

A simple login flow looks like this:

User → Application "Slack" → Provider (SAML) → authentik
   ↓
Flow "default-authentication-flow":
   Stage 1: Identification (enter username)
   Stage 2: Password
   Stage 3: Authenticator Validation (MFA)
   Stage 4: User Login (issue session)
   ↓
SAML assertion → Slack → user is signed in

Tip

If you only remember one thing, remember this: Flows are recipes. Stages are ingredients. Policies decide which ingredients to use today.


3. Quick Start (Docker Compose)

The fastest path to a working authentik. Requires 2 CPU cores, 2 GB RAM, and Docker Compose v2.

mkdir authentik && cd authentik
wget https://docs.goauthentik.io/compose.yml
echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env
docker compose pull
docker compose up -d

Then open http://<your-server>:9000/if/flow/initial-setup/ and set the password for the akadmin user.

Expected output of docker compose up -d:

[+] Running 5/5
 ✔ Network authentik_default       Created
 ✔ Container authentik-redis-1     Started   (NOTE: only present in legacy compose files; current version uses PostgreSQL listen/notify, no Redis)
 ✔ Container authentik-postgresql  Started
 ✔ Container authentik-server      Started
 ✔ Container authentik-worker      Started

Important

PostgreSQL passwords must be ≤ 99 characters due to a PostgreSQL libpq limitation. The openssl rand -base64 36 above produces a 48-char password, which is well within the limit. If you choose a custom password, stay under 100 chars.

Caution

All authentik containers must run in UTC. Do not mount /etc/timezone or /etc/localtime — it breaks OAuth and SAML clock-skew validation. Times in the UI are localized client-side. (See GitHub #3005.)


4. Installation

Choose your deployment

Docker Compose

Best for: lab, homelab, small production (< 500 users, single host).

wget https://docs.goauthentik.io/compose.yml
echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env
docker compose pull && docker compose up -d

The compose file pins a specific authentik version. To upgrade, re-download the file (it tracks the latest stable release) and run docker compose pull && docker compose up -d.

Kubernetes (Helm)

Best for: production at scale, HA, multi-replica.

helm repo add authentik https://charts.goauthentik.io
helm repo update
helm upgrade --install authentik authentik/authentik \
  -n authentik --create-namespace \
  --set authentik.secret_key=$(openssl rand -base64 60 | tr -d '\n') \
  --set postgresql.auth.password=$(openssl rand -base64 36 | tr -d '\n') \
  --set postgresql.enabled=true

The chart's full schema lives at github.com/goauthentik/helm. Override values.yaml for production: external PostgreSQL, replicaCount > 1 for server and worker, ingress with cert-manager, and geoip.enabled=true if you want GeoIP-based policies.

AWS CloudFormation

Best for: AWS shops that want a one-click deploy.

Templates are hosted at docs.goauthentik.io/docs/install-config/install/aws. The bundled CDK app lives at lifecycle/aws/app.py in the repo.

DigitalOcean Marketplace

Best for: trying authentik on a fresh droplet.

DigitalOcean Marketplace listing provisions a droplet with authentik pre-installed via Docker Compose.

System requirements

Profile CPU RAM Disk Postgres
Lab / homelab 2 cores 2 GB 10 GB bundled
Small prod (≤ 500 users) 2 cores 4 GB 20 GB bundled or external
Medium prod (≤ 10k users) 4 cores 8 GB 50 GB external recommended
Large prod / HA 8+ cores per replica × N 16+ GB per replica 100+ GB external + replica

Note

authentik does not require Redis in current versions. Pub/sub uses PostgreSQL LISTEN/NOTIFY via the bundled django-channels-postgres and django-postgres-cache packages. This simplifies deployment but means PostgreSQL is your only stateful dependency.

Configure SMTP early — authentik uses email for password resets, MFA, invitations, and admin alerts.

# in your compose .env or values.yaml
AUTHENTIK_EMAIL__HOST: smtp.example.com
AUTHENTIK_EMAIL__PORT: 587
AUTHENTIK_EMAIL__USERNAME: [email removed]
AUTHENTIK_EMAIL__PASSWORD: <smtp-app-password>
AUTHENTIK_EMAIL__USE_TLS: "true"
AUTHENTIK_EMAIL__FROM: [email removed]

Test it after restart:

docker compose exec worker ak test_email [email removed] -S default-email-stage

Expected output:

Sending test email via stage 'default-email-stage' to [email removed]... sent.

Reverse proxy

You almost certainly want one. authentik listens on :9000 (HTTP) and :9443 (HTTPS) by default. Place it behind Traefik / Nginx / Caddy / HAProxy with a real TLS cert.

Important

Add your reverse proxy's IP to AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS so authentik trusts X-Forwarded-For. Defaults cover RFC1918 ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) and IPv6 link-local — if you're behind a non-RFC1918 reverse proxy (Cloudflare Tunnel, public load balancer), add its CIDRs explicitly.

For full reverse-proxy snippets see docs.goauthentik.io/docs/install-config/reverse-proxy.


5. Initial Setup

  1. Open http://<your-server>:9000/if/flow/initial-setup/.
  2. Set a password for akadmin (the bootstrap superuser).
  3. You're redirected to the Admin interface at /if/admin/.

Tip

The User interface (/if/user/) is what your end users see. The Admin interface (/if/admin/) is the config UI. The Flow interface (/if/flow/) is what runs during a login/enroll/recovery. Bookmark whichever you use most.

Verify the install

In the Admin interface:

  1. Dashboard — should show "System status: All good", PostgreSQL connected, embedded outpost healthy.
  2. System → Workers — at least one worker is connected (Last seen < 60s ago). If "No workers" persists, see Troubleshooting.
  3. Flows and Stages → Flows — you should see 6+ default flows: default-authentication-flow, default-invalidation-flow, default-password-change-flow, default-source-enrollment-flow, default-source-authentication-flow, default-user-settings-flow.

If any of the above is missing, the bundled blueprints didn't apply. Run docker compose exec worker ak apply_blueprint default/0-bootstrap.yaml and check the System Tasks page for the result.

First admin actions

  1. Replace akadmin with a real account: Directory → Users → Create (your name) → assign to the authentik Admins group → log out, log back in as you.
  2. Disable akadmin: Directory → Users → akadmin → Deactivate. (Don't delete — keep it for break-glass recovery.)
  3. Generate a recovery key in case you lock yourself out:
docker compose exec worker ak create_recovery_key 525600 akadmin

The output is a URL like https://<your-server>/if/flow/...?token=.... Print it, store it offline. It's valid for 525,600 minutes (one year).


6. Adding Your First Application

Let's secure a real app — Grafana via OAuth2/OIDC.

Step 1 — Create the Provider

  1. Admin → Applications → Providers → Create → OAuth2/OpenID Provider.
  2. Name: Grafana OAuth.
  3. Authorization flow: default-provider-authorization-implicit-consent (or explicit-consent if you want users to see the scopes screen).
  4. Client type: Confidential.
  5. Note the auto-generated Client ID and Client Secret.
  6. Redirect URIs: https://grafana.example.com/login/generic_oauth (exact match — wildcards via regex are supported but discouraged).
  7. Signing Key: pick authentik Self-signed Certificate (or your own).
  8. Save.

Step 2 — Create the Application

  1. Admin → Applications → Applications → Create.
  2. Name: Grafana.
  3. Slug: grafana (URL-safe, becomes /application/o/grafana/).
  4. Provider: select Grafana OAuth.
  5. Launch URL: https://grafana.example.com.
  6. Icon: upload or paste a URL.
  7. Save.

Step 3 — Configure Grafana

In Grafana's grafana.ini:

[auth.generic_oauth]
enabled = true
name = authentik
client_id = <client-id-from-step-1>
client_secret = <client-secret-from-step-1>
scopes = openid profile email
auth_url = https://<authentik>/application/o/authorize/
token_url = https://<authentik>/application/o/token/
api_url = https://<authentik>/application/o/userinfo/
login_attribute_path = preferred_username
role_attribute_path = contains(groups[*], 'Grafana Admins') && 'Admin' || 'Viewer'

Restart Grafana, click "Sign in with authentik", and you're in.

Tip

The OIDC discovery endpoint at https://<authentik>/application/o/grafana/.well-known/openid-configuration returns all URLs above as JSON — paste that into any modern OIDC client and it auto-configures.

Step 4 — Restrict who can log in

  1. Customization → Policies → Create → Expression Policy.

  2. Expression:

    return ak_is_group_member(request.user, name="Grafana Users")
    
  3. Bind it: Applications → Applications → Grafana → Policy / Group / User Bindings → Create binding → Policy = the one you just made, Negate = no.

Now only members of the Grafana Users group will see Grafana in their User interface and be allowed to authenticate.


7. Flows and Stages

A flow is a recipe. Each step in the recipe is a stage. Flows are addressed in the URL: /if/flow/<slug>/.

Default flows

Slug Purpose
default-authentication-flow The main login flow.
default-invalidation-flow Logout / session destroy.
default-password-change-flow User-initiated password change.
default-recovery-flow Forgot password.
default-source-enrollment-flow First-time login from a federated source.
default-source-authentication-flow Subsequent login from a federated source.
default-provider-authorization-implicit-consent OAuth2 consent screen (auto-allow).
default-provider-authorization-explicit-consent OAuth2 consent screen (show scopes).
default-user-settings-flow The /if/user/#/settings self-service page.
default-user-settings-flow (MFA tab) MFA enrollment/management.

All shipped stage types

Confirmed in extracted/class_hierarchy.tsv and the authentik/stages/ directory tree:

Stage Purpose License
identification Collect username/email (and optionally show federated source buttons) core
password Validate the user's password core
prompt Generic form (collect arbitrary attributes) core
consent "Do you allow Grafana to read your email?" core
user_login Create the session core
user_logout Destroy the session core
user_write Persist collected attributes to a User object (enrollment, profile update) core
user_delete Delete a user account core
invitation Validate an invitation token core
deny Hard stop the flow (with custom message) core
redirect Send the user to an external URL core
email Send an email (verification, recovery) core
captcha Google reCAPTCHA / hCaptcha / Cloudflare Turnstile core
source Hand off to a federated source mid-flow core
authenticator_static Static one-time backup codes core
authenticator_totp TOTP enrollment (Google Authenticator, 1Password, etc.) core
authenticator_webauthn Passkey / FIDO2 / security-key enrollment core
authenticator_duo Duo Push enrollment core
authenticator_sms SMS code (Twilio or generic webhook) core
authenticator_email Email OTP core
authenticator_endpoint_gdtc Google Device Trust Connector Enterprise
authenticator_validate Validate any of the above MFA factors core
account_lockdown Lock account on policy match Enterprise
mtls Validate client cert (mutual TLS) Enterprise

Editing a flow

  1. Flows and Stages → Flows → click the flow name.
  2. Stage Bindings tab — drag stages to reorder, click Create binding to add a new stage, edit the binding's Order number to reposition.
  3. To gate a stage on a policy: edit the binding → set Policy → Save. Now the stage runs only if the policy returns True.

Tip

Never edit a default-* flow directly. Clone it (Duplicate action), edit the clone, then point your application at the new flow. Defaults get re-applied on upgrade and your changes will vanish.

Building a custom flow — example

A "passwordless WebAuthn" login flow:

  1. Create flow: name Passwordless, slug passwordless, designation Authentication, layout Stacked.
  2. Bind stages in order:
    • 10 — default-authentication-identification (Identification, but configure it to not show password)
    • 20 — default-authentication-mfa-validation (Authenticator Validation, accept only WebAuthn)
    • 30 — default-authentication-login (User Login)
  3. Done. Send users to /if/flow/passwordless/ to test.

8. Providers — Securing Apps

Providers are how external apps talk to authentik. Each app gets one provider. Pick the protocol the app supports.

Available provider types

Provider Use when… Notes
OAuth2 / OpenID Connect The app is a modern web app or SPA, supports OIDC Most common. Confidential or public client. Refresh tokens, device code grant, dynamic client registration via /application/o/register/.
SAML 2.0 The app is enterprise software (Atlassian, Salesforce, AWS IAM, Microsoft 365) IdP-initiated and SP-initiated. Encryption + signing. Per-app NameID format. Redirect or POST binding.
Proxy The app has no auth, but you can put a reverse proxy in front of it Requires an outpost. Three modes: forward auth (Nginx/Traefik/Caddy), forward auth (single application), proxy.
LDAP The app only speaks LDAP (e.g. Gitea, Nextcloud, Synology) authentik becomes an LDAP server. Requires an LDAP outpost. Supports bind-DN and search-bind flows.
RADIUS The app or appliance only speaks RADIUS (firewalls, VPNs, switches) Requires a RADIUS outpost. PAP, CHAP, MS-CHAPv2.
SCIM 2.0 You want to push users/groups to an external SaaS that supports SCIM Outbound provisioning. Schedules and reconciliation.
Microsoft Entra ID You want to sync users/groups to Entra ID (formerly Azure AD) Enterprise. Uses MS Graph.
Google Workspace You want to sync users/groups to Google Workspace Enterprise. Uses Admin SDK.
WS-Federation The app speaks WS-Federation (legacy SharePoint, some .NET apps) Enterprise.
RAC (Remote Access Connection) You want browser-based RDP/SSH/VNC via Apache Guacamole-like UI Enterprise. Requires a RAC outpost.
SSF (Shared Signals Framework) You want to push session events to a SaaS that consumes SSF Enterprise. Push-only.

OAuth2 / OIDC — endpoints

Auto-mounted by authentik when a provider exists:

Endpoint Path Used by
Discovery /application/o/<slug>/.well-known/openid-configuration Most modern OIDC clients (just paste the URL)
Authorization /application/o/authorize/ Browser-driven login
Token /application/o/token/ Code → token exchange
UserInfo /application/o/userinfo/ Token → user attributes
JWKS /application/o/<slug>/jwks/ Token signature verification
End-session /application/o/<slug>/end-session/ Single Logout
Introspection /application/o/introspect/ Resource server token validation
Revoke /application/o/revoke/ Refresh-token revocation
Device /application/o/device/ Device code grant (TVs, CLIs)

SAML — metadata

IdP metadata URL: https://<authentik>/api/v3/providers/saml/<id>/metadata/?download
SSO URL (redirect): https://<authentik>/application/saml/<slug>/sso/binding/redirect/
SSO URL (POST):     https://<authentik>/application/saml/<slug>/sso/binding/post/
SLO URL (redirect): https://<authentik>/application/saml/<slug>/slo/binding/redirect/
SLO URL (POST):     https://<authentik>/application/saml/<slug>/slo/binding/post/

Most SAML SPs will accept the metadata URL and configure themselves. If yours doesn't, download the XML and import it.

Proxy — Forward Auth recipe (Traefik)

The Proxy provider lets you put authentik in front of any app, even ones with zero auth support, by terminating in an outpost and verifying every request.

# traefik.yml — middleware
http:
  middlewares:
    authentik:
      forwardAuth:
        address: http://outpost.authentik.svc.cluster.local:9000/outpost.goauthentik.io/auth/traefik
        trustForwardHeader: true
        authResponseHeaders:
          - X-authentik-username
          - X-authentik-email
          - X-authentik-uid
          - X-authentik-groups
          - X-authentik-name

Then on any service:

labels:
  - "traefik.http.routers.myapp.middlewares=authentik@file"

Now myapp requires an authentik login. The user's email, username, and groups are forwarded as headers — your app can use them or ignore them.


9. Sources — Authenticating Users

A source lets users sign into authentik with credentials from somewhere else. authentik supports both push-style (we ask them) and pull-style (they're already logged in elsewhere) federation.

Available source types

Source Use when… Notes
LDAP You have Active Directory or OpenLDAP and want users to log in with their AD credentials Periodic sync of users + groups. Detects deletions. Password validation at login time.
OAuth2 You want "Sign in with Google / GitHub / GitLab / Discord / Microsoft / Twitter / Twitch / Mailcow / Apple / Okta / Keycloak / Shibboleth / WeChat" Each is a preconfigured type with the right OAuth client/scope defaults. Generic OAuth2 source for anything else.
SAML You want users to sign in via an external SAML IdP (your customer's Okta, etc.) Outbound metadata + inbound assertion validation.
Kerberos Domain-joined Windows clients should SSO via GSSAPI/SPNEGO Requires a keytab. Supports principal-name mapping.
SCIM An external IdP pushes users/groups to you via SCIM 2.0 Receive-side. Schemas and PATCH support.
Plex You're building a Plex-centric service Uses Plex's auth API.
Telegram Telegram login widget Uses Telegram's bot API.

Adding an LDAP source (Active Directory)

  1. Directory → Federation & Social login → Create → LDAP Source.
  2. Server URI: ldap://dc1.example.com:389 or ldaps://dc1.example.com:636.
  3. Bind CN: cn=authentik,ou=Service Accounts,dc=example,dc=com (a read-only service account).
  4. Bind Password: the password for that account.
  5. Base DN: dc=example,dc=com.
  6. User object filter: (objectClass=user) (or (&(objectClass=user)(sAMAccountName=*)) to skip computer accounts).
  7. Group object filter: (objectClass=group).
  8. Object uniqueness field: objectSid for AD, uid for OpenLDAP, entryUUID for 389DS.
  9. Save → click Run sync now.
  10. Verify: Directory → Users now shows synced users with the source set to your LDAP source.

Tip

Test the connection first without saving the source:

docker compose exec worker ak ldap_check_connection <source-slug>

The command is in authentik/sources/ldap/management/commands/ldap_check_connection.py. It prints OK or a Python-formatted error.

Adding an OAuth2 source (GitHub)

  1. Federation & Social login → Create → OAuth Source → Provider type: GitHub.
  2. Get a Client ID/Secret from GitHub: GitHub → Settings → Developer settings → OAuth Apps → New OAuth App.
  3. Authorization callback URL on GitHub: https://<authentik>/source/oauth/callback/<source-slug>/.
  4. Paste Client ID + Secret into authentik. Save.
  5. Edit your default-source-enrollment-flow and default-source-authentication-flow if you want custom enrollment behavior. Defaults are usually fine.
  6. The "Sign in with GitHub" button now appears on your identification stage if you bound the source to it.

Kerberos SSO (Active Directory desktops)

# 1. Create a keytab on a DC
ktpass -princ HTTP/[email removed] \
       -mapuser authentik$ -pass <password> \
       -crypto AES256-SHA1 -ptype KRB5_NT_PRINCIPAL \
       -out authentik.keytab

# 2. Copy keytab into the authentik worker:
docker cp authentik.keytab authentik-worker-1:/var/lib/authentik/

# 3. Federation → Create → Kerberos Source
#    keytab path: /var/lib/authentik/authentik.keytab
#    realm: EXAMPLE.COM

# 4. Test:
docker compose exec worker ak kerberos_check_connection <source-slug>

Then enable it in your identification stage's Source settings so the Kerberos button (or auto-SSO if you bind to MTLS) appears.


10. Outposts

An outpost is a separate process (Go binary, runs in its own container) that handles the wire protocol for non-HTTP providers. authentik core runs in Python; outposts run in Go because LDAP, RADIUS, RDP, and forward-auth need low-latency raw-protocol handling.

Outpost types

Confirmed in the briefing's module_index.cbf (cmd/proxy, cmd/ldap, cmd/radius, cmd/rac, cmd/server):

Outpost Binary Port Used by
Embedded inside the server container shares 9000 Proxy provider for single-host installs
Proxy cmd/proxy 9000/9443 Proxy provider for separate deployment
LDAP cmd/ldap 3389/6636 (TLS) LDAP provider
RADIUS cmd/radius 1812 (UDP) RADIUS provider
RAC cmd/rac varies RAC provider (Guacamole-style)

Embedded vs separate

  • Embedded — easiest. Lives inside the main server container. Set the application's outpost = authentik Embedded Outpost. No extra deploy. Use for proxy providers only.
  • Separate — required for LDAP, RADIUS, RAC, and recommended for production Proxy at scale. Deploy as a separate Docker container or Kubernetes pod. authentik can auto-deploy outposts to Docker or Kubernetes if you give the worker the necessary socket / kubeconfig access.

Auto-deploying outposts via Docker

The default compose.yml mounts /var/run/docker.sock into the worker container. This lets authentik spin up outpost containers when you create a Proxy/LDAP/RADIUS/RAC provider and bind it to an outpost.

Warning

Mounting /var/run/docker.sock gives the worker container effective root on the host. If you can't accept that, use a Docker Socket Proxy to restrict the operations, or deploy outposts manually.

Manual outpost deployment

# outpost-proxy.compose.yml
services:
  proxy:
    image: ghcr.io/goauthentik/proxy:2026.8.0-rc1
    ports:
      - 9000:9000
      - 9443:9443
    environment:
      AUTHENTIK_HOST: https://authentik.example.com
      AUTHENTIK_TOKEN: <outpost-token-from-admin-ui>
      AUTHENTIK_INSECURE: "false"

The outpost token is generated when you create the outpost in the Admin UI. Each outpost gets its own token.


11. Users, Groups, and RBAC

Users

Three user types, set per-user:

Type Counts toward license? Notes
internal Yes Regular user. Can log into the User interface.
external Yes Customer-facing user (B2C). Same capabilities as internal but billed differently in Enterprise.
service_account No API consumer. Cannot interactively log in. Holds tokens.
internal_service_account No Used by outposts. Created automatically.

Switch a user's type:

docker compose exec worker ak change_user_type --type service_account alice

The command is in authentik/core/management/commands/change_user_type.py:11. Use --all to change every user (be careful).

Groups

Groups can be local (created in authentik), synced (from an LDAP/SCIM/OAuth source), or hybrid. Group membership drives:

  • Application access — bind a group to an application via a policy or directly via "Group Bindings".
  • RBAC roles — assign a Role to a Group; everyone in the group gets the role.
  • SAML/OIDC claims — the groups claim in OAuth2 access tokens, the SAML MemberOf attribute, and the LDAP-provider memberOf are all auto-populated from group membership.

RBAC

Roles assign Django-Guardian object-level permissions. The bundled authentik Admins role grants full admin. You can create finer roles like "View users in engineering group only".

Role permission scope Notes
Global Affects everything (e.g. can_view_event)
Per-model Affects a model class (e.g. can_change_user on User)
Per-object Affects a single instance (e.g. can_change_user on user-id=42)

See Directory → RBAC in the Admin UI.


12. Policies and Property Mappings

Policies

A policy is a function that returns True or False. You bind policies to flows, stages, application visibility, or source enrollment to gate access.

Policy type Returns True when…
Expression A Python expression evaluates truthy. Has access to request, ak_user_has_authenticator(...), ak_is_group_member(...), ak_logger, and more.
Event Matcher A specific event has occurred recently for this user (e.g. "5 failed logins in 1 hour").
Password Password meets complexity / age requirements.
Reputation The user's IP/user reputation score is above a threshold (negative scores accumulate on failed logins).
Expiry The user/password is older than N days.
GeoIP Login is from a specific country/ASN. Requires GeoLite2 mounted at /geoip/.
Dummy Always returns the value you configure. For testing.
Unique Password Enterprise. Password has never been used by this user before.

Expression policy — example

# Block logins from non-corporate IPs unless user is in 'Remote Workers' group
from authentik.policies.utils import ak_is_group_member

if request.context.get("geoip") and request.context["geoip"]["country"] != "US":
    return ak_is_group_member(request.user, name="Remote Workers")
return True

Available helpers (documented in website/docs/customize/policies/expression/):

Function Use
ak_is_group_member(user, name="...") Check membership by group name
ak_user_has_authenticator(user, device_type="totp") Does the user have an MFA device?
ak_logger.info("msg") Write to authentik's log
ak_call_policy("slug", request=request) Compose policies — call one from another
request.context["geoip"] IP geolocation, if enabled
request.context["asn"] ASN data, if enabled

Property mappings

Property mappings transform user/group attributes into the shape your provider/source needs. They're tiny Python expressions.

OAuth2 scope mapping — example

# Adds the user's department to the 'department' claim
return {
    "department": request.user.attributes.get("department", "unknown"),
    "manager": request.user.attributes.get("manager_email"),
}

SAML attribute mapping — example

# Send memberships as a multi-valued SAML attribute
return [group.name for group in request.user.ak_groups.all()]

Mappings are listed under Customization → Property Mappings.


13. Blueprints — GitOps for authentik

Blueprints let you define every authentik object (Flow, Stage, Policy, Provider, Application, User, Group, Outpost) as YAML, apply them automatically on startup, and version-control them in git.

A minimal blueprint

version: 1
metadata:
  name: "my-grafana-app"
entries:
  - model: authentik_providers_oauth2.oauth2provider
    identifiers:
      name: "Grafana OAuth"
    attrs:
      client_type: "confidential"
      client_id: !Env GRAFANA_CLIENT_ID
      client_secret: !Env GRAFANA_CLIENT_SECRET
      redirect_uris:
        - matching_mode: strict
          url: "https://grafana.example.com/login/generic_oauth"
      signing_key: !Find [authentik_crypto.certificatekeypair, [name, "authentik Self-signed Certificate"]]
  - model: authentik_core.application
    identifiers:
      slug: "grafana"
    attrs:
      name: "Grafana"
      provider: !KeyOf provider-id
      meta_launch_url: "https://grafana.example.com"

YAML tags

Tag What it does
!Env VAR Read environment variable VAR
!Find [model, [field, value]] Look up an existing object by field/value
!KeyOf <id> Reference another object in the same blueprint by identifiers.id
!Format ["template {0}", arg] Python .format()
!If [condition, then, else] Conditional
!Context key Read from the apply-time context

Applying blueprints

How What
Mounted at /blueprints/ Automatically discovered and applied on startup
docker compose exec worker ak apply_blueprint <file> Manual apply, useful for testing
Via API: POST /api/v3/managed/blueprints/ Upload and apply at runtime

The apply_blueprint command is at authentik/blueprints/management/commands/apply_blueprint.py:36.

Tip

Bundled blueprints live at blueprints/default/, blueprints/example/, and blueprints/system/. Don't edit those — copy what you need into a new file under your own /blueprints/custom/ mount.

Example library

The blueprints/example/ directory ships ~20 ready-to-adapt blueprints covering common SaaS apps (Slack, Nextcloud, AWS, GitLab, etc.) plus all the protocol patterns. Browse the GitHub directory for the full list.


14. Customization and Branding

Brands (multi-tenancy)

A Brand is a subdomain-scoped configuration: logo, colors, default flows, footer links. Use this to run multiple "instances" of authentik from one deployment.

  1. System → Brands → Create.
  2. Domain: customer-a.auth.example.com.
  3. Default flows: set the four flows (auth, invalidation, recovery, unenrollment) you want this brand to use.
  4. Branding: set logo, favicon, title, additional metadata.
  5. Save.

When a request hits customer-a.auth.example.com, authentik will use this brand's flows and visual settings.

Custom CSS

System → Brands → <your brand> → Custom CSS:

:root {
    --pf-global--primary-color--100: #1f2937;
    --pf-global--BackgroundColor--dark-100: #111827;
}
.pf-c-login__main-header img { max-height: 80px; }

Applied immediately to all flow and admin interfaces under this brand.

Email templates

Mount custom templates at /templates/ in the worker container, then reference them in an Email stage's "Template" dropdown. See authentik/stages/email/templates/ for the structure to clone.


15. Events and Notifications

Every authentik action emits an event. Events are stored in PostgreSQL and queryable from the Admin UI.

Event types (sampled from extracted/class_hierarchy.tsv)

Action Trigger
login / login_failed User authentication attempt
logout Session destruction
user_write User attribute change
password_set Password change
secret_view Sensitive value shown in UI
configuration_error Misconfiguration detected
policy_execution Policy evaluated
model_created / model_updated / model_deleted DB change
update_available New authentik version released
impersonation_started / impersonation_ended Admin impersonated a user
flow_execution Flow ran
source_linked User completed federated enrollment

Notification rules

  1. System → Events → Notification Rules → Create.
  2. Event matcher policy: e.g. EventMatcher policy for login_failed.
  3. Group to notify: e.g. Security Admins.
  4. Severity, transport (email, webhook, Sentry).
  5. Save.

Webhook transports

# Notification Transport: Webhook (Generic)
URL: https://chat.example.com/hooks/incoming/xyz
Webhook Body:
{
  "text": "{{ notification.body }}",
  "user": "{{ notification.user.username }}",
  "severity": "{{ notification.severity }}"
}

Slack-formatted and Discord-formatted variants ship as separate transport types.


16. Backups, Upgrades, and Air-Gapped Installs

Backups

authentik state lives in two places:

  1. PostgreSQL — every object, every user, every flow, every event. Back it up with pg_dump:

    docker compose exec postgresql pg_dump -U authentik authentik > authentik-$(date +%F).sql
    
  2. /data volume — uploaded files (icons, flow backgrounds, CSV reports). tar it:

    docker compose exec server tar -C /data -czf - . > authentik-data-$(date +%F).tar.gz
    

Restore: stop authentik, psql < dump.sql and untar the data volume back.

Upgrades

wget -O compose.yml https://docs.goauthentik.io/compose.yml
docker compose pull
docker compose up -d

Migrations run automatically in the worker on container start. Watch the worker logs:

docker compose logs -f worker | grep -E "(migrat|error)"

Important

Always read the release notes at docs.goauthentik.io/docs/releases before upgrading. Some releases introduce breaking changes (e.g. 2026.5.0 changed the email password-reset template — see #22757). Migrations are forward-only.

Air-gapped installs

Set in .env:

AUTHENTIK_DISABLE_UPDATE_CHECK=true
AUTHENTIK_DISABLE_STARTUP_ANALYTICS=true
AUTHENTIK_ERROR_REPORTING__ENABLED=false

Mirror the container images to an internal registry. authentik does not call home for license validation in core; the Enterprise license server is checked periodically — see docs.goauthentik.io/docs/install-config/air-gapped for the full offline procedure.


17. Common Tasks (Recipes)

Enable MFA for a specific group

  1. Create an Expression Policy:

    return ak_is_group_member(request.user, name="MFA Required")
    
  2. Edit default-authentication-flow → Stage Binding for default-authentication-mfa-validation → set this policy. Now MFA validation runs only for users in the MFA Required group.

Force password rotation every 90 days

  1. Customization → Policies → Create → Password Expiry Policy → Days: 90.
  2. Edit default-authentication-flow → after Password stage, add a stage binding for default-password-change-prompt (or a custom prompt) gated by this policy.

Auto-enrol new users from an OAuth source into a group

  1. Federation & Social login → <your source> → Property Mapping:

    # Enrollment Mapping
    from authentik.core.models import Group
    default_group, _ = Group.objects.get_or_create(name="Auto-enrolled")
    return {"ak_groups": [default_group]}
    
  2. Bind this mapping to the source's enrollment flow.

Use an external PostgreSQL

In .env:

AUTHENTIK_POSTGRESQL__HOST=db.example.com
AUTHENTIK_POSTGRESQL__PORT=5432
AUTHENTIK_POSTGRESQL__NAME=authentik
AUTHENTIK_POSTGRESQL__USER=authentik
AUTHENTIK_POSTGRESQL__PASSWORD=<password>
AUTHENTIK_POSTGRESQL__SSLMODE=require

Then remove the postgresql service from compose.yml. The same env keys exist for read replicas via AUTHENTIK_POSTGRESQL__READ_REPLICAS__0__HOST etc. (see authentik/lib/default.yml lines 18-31).

Run with FIPS-compliant crypto

authentik/lib/default.yml exposes:

compliance:
  fips:
    enabled: false   # set true via AUTHENTIK_COMPLIANCE__FIPS__ENABLED=true

The Rust outposts already link aws-lc-rs with the fips feature (see Cargo.toml). When compliance.fips.enabled=true, authentik also restricts TLS cipher suites and refuses non-FIPS modules at startup.

Export your config as blueprints

docker compose exec worker ak apply_blueprint --export > my-config.yaml

This roundtrips every flow/stage/provider/policy currently in the DB into a blueprint you can commit to git.

Generate or rotate an admin recovery key

docker compose exec worker ak create_recovery_key 60 akadmin

60 is duration in minutes (so 1 hour). The output URL bypasses MFA and password — store it offline.

Test an SMTP setup without sending real reset emails

docker compose exec worker ak test_email [email removed] -S default-email-stage

(From authentik/stages/email/management/commands/test_email.py.)

Apply schema changes to your IDE — generate Python types

docker compose exec worker ak build_schema --api-file schema.yml

Then download schema.yml, run openapi-generator against it for your language of choice. (The TypeScript client ships pre-generated at packages/client-ts/; Go client at packages/client-go/; Rust client at packages/client-rust/.)


18. CLI Reference (ak)

All commands run inside the worker container: docker compose exec worker ak <command>. The full list is auto-discovered from Django management commands under authentik/*/management/commands/. The most useful ones, from extracted/cli_commands.tsv:

Command Purpose Source
ak apply_blueprint <file> Apply a blueprint file (or --export to dump current state) authentik/blueprints/management/commands/apply_blueprint.py:36
ak benchmark -p 4 --csv Stress-test flow execution. -p = parallel processes authentik/flows/management/commands/benchmark.py:56-63
ak build_schema --api-file schema.yml Regenerate the OpenAPI spec authentik/api/management/commands/build_schema.py:20-21
ak change_user_type --type <type> --all <usernames> Convert user(s) between internal / external / service_account authentik/core/management/commands/change_user_type.py:11-13
ak create_admin_group <user> Add a user to the bootstrap admins group authentik/recovery/management/commands/create_admin_group.py:18
ak create_recovery_key <minutes> <user> Generate a one-shot recovery URL authentik/recovery/management/commands/create_recovery_key.py:29-36
ak hash_password <password> Hash a password as authentik stores it (for blueprint seeding) authentik/core/management/commands/hash_password.py:13
ak import_certificate --name <n> --certificate <pem> --private-key <pem> Import a TLS cert/key pair authentik/crypto/management/commands/import_certificate.py:51-53
ak kerberos_check_connection <source-slug> Smoke-test a Kerberos source authentik/sources/kerberos/management/commands/kerberos_check_connection.py:17
ak kerberos_sync <source-slug> Run an on-demand Kerberos sync authentik/sources/kerberos/management/commands/kerberos_sync.py:16
ak ldap_check_connection <source-slug> Smoke-test an LDAP source authentik/sources/ldap/management/commands/ldap_check_connection.py:17
ak ldap_sync <source-slug> Run an on-demand LDAP sync authentik/sources/ldap/management/commands/ldap_sync.py:15
ak scim_sync <provider-slug> Run an on-demand SCIM provisioning sync (outbound) authentik/providers/scim/management/commands/scim_sync.py:15
ak set_flag <flag_key> <flag_value> Toggle a tenant feature flag authentik/tenants/management/commands/set_flag.py:11-12
ak test_email <to> -S <stage-slug> Send a test email through a configured email stage authentik/stages/email/management/commands/test_email.py:49-50
ak clean_orphan_obj_perms --batch-size N Clean up Guardian object permissions for deleted users packages/ak-guardian/guardian/management/commands/clean_orphan_obj_perms.py:25-40

Also bundled but rarely user-facing: dumpdata, loaddata, makemigrations, migrate, runserver, shell — all standard Django management commands.

Outpost binaries

Binary Cobra-style commands Source
authentik-proxy serve, healthcheck cmd/proxy/main.go
authentik-ldap serve, healthcheck cmd/ldap/main.go
authentik-radius serve, healthcheck cmd/radius/main.go
authentik-rac serve, healthcheck cmd/rac/main.go
authentik-server serve, healthcheck, worker cmd/server/main.go, cmd/server/server.go:26, cmd/server/healthcheck.go:20

All Go binaries respect AUTHENTIK_* env vars the same way the Python server does (parsed by internal/config/config.go).


19. Troubleshooting

Error: Migration authentik_core.0058_setup fails on upgrade

Cause. Upgrading directly across more than one minor release without intermediate migrations applied. Confirmed in #22688 (upgrade from 2025.10.2 → 2026.5.0).

Solution. Roll back to your previous tag, then upgrade one minor release at a time:

# Restore the previous compose.yml
git checkout HEAD~1 compose.yml
docker compose up -d
# Wait for healthy, then upgrade to the next minor
sed -i 's|:2025.10.2|:2025.12.5|' compose.yml
docker compose pull && docker compose up -d
# Repeat for each minor up to 2026.5.0

Prevention. Read the release notes before every upgrade; skip-version upgrades are explicitly unsupported.

Error: No identification data provided after upgrading 2FA

Cause. Bug introduced in 2025.12.1 affecting Authenticator Validation Stage configurations. Tracked in #19552 (43 community comments — fix landed in 2026.1.0).

Solution. Upgrade to 2026.1.0 or later. Workaround on the affected version: edit your authentication flow's Authenticator Validation stage and re-save it (resets the internal device-class set).

Prevention. Stick to .0 / .x patch versions on production; let .0-rc and .0 settle before adopting.

Error: Starting the worker makes the server not load

Cause. Resource contention or a worker that holds the DB exclusive lock during a long-running migration. Closed in #22606; fix backported.

Solution. Restart in order: stop both, start server and postgresql, wait for server to be healthy, then start worker. If migrations still hang, docker compose logs worker to see which migration is stuck.

Prevention. Pin pre-release tags only in staging.

Error: SAML provider not JSON serializable (2026.5.0)

Cause. Regression in Event.log_deprecation when the SAML provider uses redirect binding. Closed in #22694 — patched in 2026.5.1.

Solution. Upgrade to 2026.5.1 or later.

Prevention. Subscribe to release announcements; this was hotfixed within 48 hours.

Error: OAuth single logout broken (2026.5.0)

Cause. Front-channel logout regression. Tracked in #22572 (14 comments, still open at time of writing).

Solution. Workaround: switch the OAuth provider to back-channel logout in the Provider's "Logout settings" tab. Long-term fix is pending.

Prevention. Test logout flows in staging before upgrading.

Error: LDAP Provider not returning expected results

Cause. Various root causes — most commonly missing objectClass mappings or incorrect search base. See #22743 (closed).

Solution.

  1. Check the LDAP outpost is connected: Admin → Applications → Outposts → the outpost should show "Last seen" within 60 seconds.
  2. Try the search manually:
    ldapsearch -H ldap://outpost.example.com:3389 \
      -D "cn=service-account,ou=users,dc=ldap,dc=goauthentik,dc=io" \
      -w '<token>' -b "dc=ldap,dc=goauthentik,dc=io" \
      "(objectClass=user)"
    
  3. Check the outpost logs: docker compose logs ldap-outpost.

Prevention. Keep your LDAP provider's "Search group" pointing at a small test group during initial setup; expand only after the smoke test passes.

Error: Admin interface crashes in Safari

Cause. Web component bug in older Safari versions. Tracked in #19166 (8 comments) → references #14322.

Solution. Use Firefox or Chrome for the Admin interface. The User interface is unaffected. Upgrade Safari to 17+.

Prevention. Test admin workflows in the browsers your team actually uses.

Error: "Refresh" on Outposts page doesn't refresh state

Cause. UI bug — the button triggers a fetch but doesn't re-render the list. Tracked in #19951.

Solution. Reload the whole page (F5). The data is updated; only the visual update is broken.

Prevention. N/A — cosmetic.

Error: authentik redirects to interface instead of app

Cause. Application launch URL not set or set incorrectly. Tracked in #18450.

Solution. Edit the Application → Launch URL must be the public URL of the app, not authentik's URL. For OAuth apps, this is what the user lands on after consent.

Prevention. Always test the Launch URL by clicking the app tile in the User interface after creation.

Error: Custom user attributes prevent invitation creation

Cause. Wizard validation bug when the User model has required custom attributes. Tracked in #22637.

Solution. Use the API directly to create the invitation:

curl -X POST -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  https://<authentik>/api/v3/stages/invitation/invitations/ \
  -d '{"name":"new-user","flow":"<uuid>","fixed_data":{"email":"[email removed]"}}'

Prevention. Mark custom user attributes as nullable in your prompt stage until the wizard fix lands.

Error: Cannot import the device-code-flow blueprint

Cause. The blueprint file location moved between releases. Tracked in #19525.

Solution. Use the bundled blueprint via apply_blueprint:

docker compose exec worker ak apply_blueprint default/flow-device-code-authorization.yaml

Prevention. Reference blueprints via their canonical name (default/...) rather than downloading them.

Error: Email password-reset uses naturaltime ungrammatically

Cause. Template uses Django's naturaltime filter which produces "now", "1 day", "2 days" — readable in English but ungrammatical when used as in "Token expires {{ ... }}". Tracked in #22757.

Solution. Override the template by mounting your own at /templates/email/password_reset.html in the worker container.

Prevention. Custom email templates are a one-time fix.

Error: outpost shows disconnected immediately after creation

Cause. Outpost token not propagated yet (auto-deploy mode), or the outpost can't reach AUTHENTIK_HOST.

Solution.

  1. Check the outpost logs: docker logs <outpost-container>. Look for "connected" or any TLS/network errors.
  2. Verify AUTHENTIK_HOST is reachable from the outpost: docker exec <outpost> wget -qO- $AUTHENTIK_HOST/-/health/ready/.
  3. If the outpost is in a different network/cluster, set AUTHENTIK_HOST_BROWSER to the user-facing URL and AUTHENTIK_HOST to the internal URL.

Prevention. Always set AUTHENTIK_HOST_BROWSER separately when behind a reverse proxy.

Error: PostgreSQL "password too long"

Cause. PostgreSQL's libpq does not accept passwords > 99 chars.

Solution. Regenerate PG_PASS with a shorter length:

sed -i '/^PG_PASS=/d' .env
echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env

If you've already run with the long password, you'll also need to ALTER USER in PostgreSQL to match.

Prevention. Stick with the documented openssl rand -base64 36 recipe.

Error: All users sign in but no apps appear

Cause. Users are authenticated but no Application is bound to their group / a policy is denying visibility.

Solution.

  1. Admin → Applications → Applications → <your app> → Policy Bindings — check if there's a deny policy.
  2. Directory → Users → <user> → see "Applications" tab — what does this user actually have access to?
  3. If empty, add a group binding from a group that includes the user.

Prevention. When creating an app, always set at least one group/user binding immediately, or accept "no policy = visible to everyone".


20. FAQ

Q: Is authentik really free? What does Enterprise add? Yes — the core (everything in authentik/ except authentik/enterprise/) is MIT-licensed and free forever. Enterprise adds: SSF, MS Entra/Google Workspace sync, audit logging, MTLS stage, RAC provider, account lockdown stage, unique-password policy, and a Support center. Pricing at goauthentik.io/pricing.

Q: Do I need Redis? No. Current authentik uses PostgreSQL LISTEN/NOTIFY for pub/sub and PostgreSQL for caching via django-postgres-cache. PostgreSQL is the sole stateful dependency.

Q: How many users can authentik handle? With the Docker Compose default (single server + worker, bundled PostgreSQL) you can serve thousands of users comfortably. For tens of thousands, switch to Kubernetes Helm with replicaCount > 1 and an external PostgreSQL with read replicas. authentik scales horizontally — both server and worker are stateless except for the embedded outpost.

Q: Can authentik replace Okta / Entra ID / Auth0? For most SAML and OIDC use cases, yes. For B2C at internet scale (millions of users) you'll want to tune PostgreSQL aggressively. For specific Okta features like AD agent or feature flags, you'd need to build them — authentik covers the protocol surface but Okta has a lot of integration glue you'd reimplement.

Q: How do passwordless / passkey / WebAuthn work? Configure the authenticator_webauthn stage and bind it as the only required MFA in your flow. Skip the password stage entirely (or make it conditional on absence of WebAuthn). The user enrolls a passkey once, then logs in with just username + passkey.

Q: Can I use authentik with a custom domain per tenant? Yes — that's exactly what Brands are for. Create one Brand per domain. Each brand can override the default flows, branding, and metadata.

Q: Does authentik support SCIM both ways? Yes. As a provider (push users to Slack/Zoom/etc.) and as a source (Okta pushes users to you). Both implement SCIM 2.0 with PATCH semantics.

Q: Where does authentik store sessions? PostgreSQL. The session table is authentik_core_authenticatedsession. Cookies are HTTP-only, Secure (over HTTPS), with SameSite=Lax by default. The session-cookie age is configurable per brand.

Q: Can users self-register? Yes — bind a user_write stage at the end of an enrollment flow and link to it from your identification stage. Be aware that without an Email or Captcha stage, you're exposing user creation publicly.

Q: How do I migrate from Keycloak / Authelia / Authentik? There's no automated importer. Inventory your Realms → Brands, Clients → Providers, Users → exported user CSV (use ak loaddata), then test SSO with one app before flipping the cutover.

Q: Does authentik have an audit log? The Events system covers most of what you'd want: every login, model change, configuration change, impersonation, etc. The Enterprise audit log adds tamper-evidence, retention controls, and structured export.

Q: How do I export and import a single flow? ak apply_blueprint --export > all.yaml, then hand-extract the flow's section. There's also an API endpoint: GET /api/v3/managed/blueprints/?model=authentik_flows.flow returns blueprint fragments per flow.

Q: Can authentik act as an OIDC client for other apps' authentication? No — authentik is an IdP, not an SP. To pull users from Google/GitHub/etc., use Sources, not Providers.

Q: How do I integrate with Cloudflare Access? Use a Proxy provider in "Forward auth (Cloudflare)" mode, then configure Cloudflare to call authentik's auth endpoint. Full recipe at docs.goauthentik.io/integrations/security/cloudflare-access.

Q: Where are the integration recipes? goauthentik.io/integrations — the website/integrations/ directory in the source has a one-pager per supported third-party app (~150+ integrations as of 2026.8.0).

Q: How do I delete a user but keep their audit trail? Use a user_delete stage in a custom flow, or Admin → Directory → Users → checkbox → "Disable" (preserves the user record but blocks login). Hard deletion removes the user from Events too, which usually isn't what you want.

Q: What's the relationship between a Flow and a Brand? A Brand has four "default flow" slots (authentication, invalidation, recovery, unenrollment). When a request hits that brand's domain, authentik uses those flows. The Flow itself is brand-agnostic — one flow can be the default for many brands.

Q: Can I run authentik behind Cloudflare? Yes. Set AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS to include Cloudflare's IP ranges (or 0.0.0.0/0 if you trust your network), and verify X-Forwarded-For reaches authentik correctly.

Q: How do I rotate the signing certificate for OIDC? Generate a new certificate (Admin → System → Certificates → Generate or upload), then edit your OAuth provider and switch its "Signing Key" to the new one. Existing tokens signed with the old key stay valid until they expire; clients that use JWKS will refresh automatically.

Q: Does authentik support hardware-based MFA (Yubikey)? Yes — Yubikeys appear as WebAuthn devices when used in WebAuthn mode. Plug in, register via the authenticator-webauthn stage, done. Yubikey OTP (not WebAuthn) isn't separately supported.


21. Reference Tables

Container ports

Port Protocol Used by
9000 HTTP Server (web UI + API + embedded outpost)
9443 HTTPS Server (web UI + API + embedded outpost)
3389 LDAP LDAP outpost (StartTLS supported)
6636 LDAPS LDAP outpost (TLS)
1812 RADIUS (UDP) RADIUS outpost
9300 HTTP Prometheus metrics (/metrics)
9900 HTTP Debug endpoint (internal/debug/debug.go, pprof + dump_config; disabled in prod)

Defaults from authentik/lib/default.yml lines 36-49.

Health endpoints

Path Returns
/-/health/live/ 200 if process is running
/-/health/ready/ 200 if DB + worker connected and migrations done
/-/metrics/ Prometheus format (on port :9300 by default)

Useful env vars (AUTHENTIK_* namespace)

All keys in default.yml are env-overridable. Nesting uses __. Examples:

Env var What it sets
AUTHENTIK_SECRET_KEY Django secret key (required)
AUTHENTIK_POSTGRESQL__HOST PostgreSQL host
AUTHENTIK_POSTGRESQL__PORT PostgreSQL port
AUTHENTIK_POSTGRESQL__NAME DB name
AUTHENTIK_POSTGRESQL__USER DB user
AUTHENTIK_POSTGRESQL__PASSWORD DB password (also via env://POSTGRES_PASSWORD)
AUTHENTIK_POSTGRESQL__SSLMODE require, prefer, disable
AUTHENTIK_LISTEN__HTTP [::]:9000
AUTHENTIK_LISTEN__HTTPS [::]:9443
AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS comma-separated CIDR list
AUTHENTIK_LOG_LEVEL debug, info, warning, error
AUTHENTIK_ERROR_REPORTING__ENABLED true enables Sentry
AUTHENTIK_EMAIL__HOST SMTP host
AUTHENTIK_DISABLE_UPDATE_CHECK true for air-gapped
AUTHENTIK_DISABLE_STARTUP_ANALYTICS true for air-gapped
AUTHENTIK_OUTPOSTS__CONTAINER_IMAGE_BASE Override outpost image prefix (e.g. for internal registry)
AUTHENTIK_OUTPOSTS__DISCOVER true (default) to auto-discover Docker/Kubernetes
AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST true to disable the in-server proxy
AUTHENTIK_BLUEPRINTS_DIR Path to mounted blueprints (default /blueprints)
AUTHENTIK_CERT_DISCOVERY_DIR Path watched for external certs (default /certs)
AUTHENTIK_WEB__WORKERS Gunicorn worker processes (default 2)
AUTHENTIK_WEB__THREADS Threads per worker (default 4)
AUTHENTIK_WORKER__PROCESSES Dramatiq worker processes (default 1)
AUTHENTIK_WORKER__THREADS Threads per worker (default 2)
AUTHENTIK_COMPLIANCE__FIPS__ENABLED true for FIPS mode
AUTHENTIK_TENANTS__ENABLED true for multi-tenant (different from Brands)
AUTHENTIK_GEOIP Override /geoip/GeoLite2-City.mmdb path

For the complete keyspace, run docker compose exec server cat /etc/authentik/config.yml after install — every default is enumerated.

Default flow slugs (in blueprints/default/)

Slug Purpose
default-authentication-flow Login
default-invalidation-flow Logout
default-password-change-flow Password change
default-recovery-flow Forgot password
default-source-enrollment-flow First federated login → create local user
default-source-authentication-flow Subsequent federated login
default-source-pre-authentication-flow Pre-source decisions (e.g. terms of service)
default-provider-authorization-implicit-consent Auto-allow OAuth consent
default-provider-authorization-explicit-consent Show OAuth scope screen
default-provider-invalidation-flow Logout for OIDC RP-initiated logout
default-user-settings-flow /if/user/#/settings page
default-user-settings-flow (MFA tab) Enroll/manage MFA devices
default-flow-pre-authentication Run before any other authentication (e.g. brand-level CAPTCHA)

Key file paths inside the container

Path Contains
/etc/authentik/config.yml Merged effective config (read-only, regenerated on start)
/blueprints/ Mount your custom YAML here
/data/ Uploaded files (icons, backgrounds, CSV exports)
/certs/ Externally-discovered cert pairs (<name>.crt + <name>.key)
/templates/ Custom email templates
/geoip/ GeoLite2-City.mmdb + GeoLite2-ASN.mmdb
/lifecycle/ Startup scripts and migrations

Where to learn more

For an architectural deep-dive — request flow, code layout, the outpost wire protocol, blueprint internals, performance tuning, and security posture — see the Admin & Developer Guide.