Skip to content
Stribog

Identity

All writing

Authelia vs Authentik: Gateway Guard or Identity Provider

Authelia gates requests at your reverse proxy; authentik runs the directory. Protocols, user lifecycle, and what each shows an auditor in an access review.

Stribog12 min read

Most comparisons stop at weight, an admin UI and a count of protocols. The two tools sit at different layers of the stack, keep different state, and leave different evidence behind. A team that adopts one to protect a handful of internal dashboards is often asked, a year later, to answer identity-governance questions with it. Whether it can depends on a decision made on day one, usually without noticing.

Versions at time of writing: Authelia v4.39.28 and authentik 2026.8.4. Pricing quoted below is as listed on 2026-10-17.

The short answer: a gate or a directory

Authelia's own architecture page is precise about its scope: "Authelia is a companion of reverse proxies like Traefik… It can be seen as an extension of those proxies providing authentication functions and a login portal." It answers one question per request, allow or redirect, and it does not hold the user directory. Its first-factor backends are exactly two: an LDAP server such as OpenLDAP, OpenDJ, FreeIPA or Active Directory, or a YAML file of hashed passwords.

authentik is built the other way round. A provider in authentik is "an authentication method, a service that is used by authentik to authenticate the user for the associated application" — OIDC/OAuth2, SAML, LDAP, a generic proxy and others. The users, groups and policies those providers consult live in authentik itself. Forward auth is one provider among several, not the product.

So the deciding question is not features. It is ownership: if the identity of record should live in a directory you already run, or in a text file in git, Authelia fits. If the SSO layer should become the directory, with lifecycle and history attached, that is an identity provider's job — and the Keycloak, authentik and Zitadel comparison covers which full IdP to pick if that is where this lands.

How forward auth actually works

Forward auth splits one request into two. The reverse proxy receives the request, holds it, and sends a subrequest carrying the headers and cookies to the auth server. The auth server answers with an allow, or with a redirect to its login portal. On allow, the proxy forwards the original request to the application with identity headers attached.

Authelia's architecture page spells out the consequence: it "is directly connected to the reverse proxy but never directly connected to application backends and therefore the payloads sent by the clients of the protected API will never reach Authelia, only the authentication pieces will". The protected service can be a REST API, GraphQL, or anything else over HTTP. After login, the portal issues "a session cookie valid for all subdomains of the domain protected by Authelia", which the proxy forwards on each subsequent auth request.

Wiring it into Traefik is one middleware. Authelia's Traefik guide points forwardAuth at /api/authz/forward-auth and copies four response headers to the backend. As a file-provider document (the proxy layer itself is compared in Caddy, Traefik, NGINX, HAProxy):

yaml
http:
  middlewares:
    authelia:
      forwardAuth:
        address: "http://authelia:9091/api/authz/forward-auth"
        trustForwardHeader: true
        maxResponseBodySize: 8192
        authResponseHeaders:
          - "Remote-User"
          - "Remote-Groups"
          - "Remote-Email"
          - "Remote-Name"
  routers:
    grafana:
      rule: "Host(`grafana.example.com`)"
      entryPoints:
        - "websecure"
      middlewares:
        - "authelia"
      service: "grafana"
      tls: {}
  services:
    grafana:
      loadBalancer:
        servers:
          - url: "http://grafana:3000"
Traefik dynamic configuration (file provider). The Authelia portal needs its own router without this middleware. trustForwardHeader is only safe when the entrypoint trusts forwarded headers from known proxy addresses alone.

authentik's forward auth is the same pattern: it "uses your existing reverse proxy for application traffic and relies on the authentik outpost only to check authentication and authorization." It has two modes. In single-application mode, "only /outpost.goauthentik.io on the application domain is routed to the authentik outpost", and each application gets its own provider, policies and bindings. Domain-level mode covers many applications under one parent domain with one provider, and the docs are explicit about the price: you "cannot restrict individual applications to different users with separate application-level policies."

Keep forward auth apart from authentik's proxy mode. In proxy mode the outpost itself forwards the request to the application, so application traffic does pass through authentik. The "payloads never reach the auth server" property belongs to the forward-auth path only.

Same request flow at the proxy, different owner of the user record behind it.

Authelia: a companion to the proxy

Authelia's job is first factor, second factor, and the per-request policy decision. With the file backend, users live in YAML, each with a display name, a hashed password, an email and a list of groups. The passwords guide warns that the file "should be set with read/write permissions as it could be updated by users resetting their passwords", so it is not purely a config artefact under your control. Changes made by hand are picked up only if the backend's watch option is on; it defaults to false.

yaml
users:
  alice:
    disabled: false
    displayname: "Alice Example"
    password: "$argon2id$v=19$m=65536,t=3,p=2$BpLnfgDsc2WD8F2q$o/vzA4myCqZZ36bUGsDY//8mKUYNZZaR0t4MFFSs+iM"
    email: "alice@example.com"
    groups:
      - "ops"
  bob:
    disabled: false
    displayname: "Bob Example"
    password: "$argon2id$v=19$m=65536,t=3,p=2$BpLnfgDsc2WD8F2q$o/vzA4myCqZZ36bUGsDY//8mKUYNZZaR0t4MFFSs+iM"
    email: "bob@example.com"
    groups:
      - "dev"
users_database.yml. The digest is the example from Authelia's passwords guide; generate a real one per user with the command below.
bash
docker run --rm -it authelia/authelia:latest authelia crypto hash generate argon2
Interactive form: the password is typed at a prompt, not left in shell history.

On protocols, Authelia's OpenID Connect page says two things at once, and both should be read. It states that Authelia "can act as an OpenID Connect 1.0 Provider as part of an open beta". The same page states it is OpenID Certified to the Basic OP, Implicit OP, Hybrid OP, Form Post OP and Config OP profiles. It supports Core, Discovery and the Form Post Response Mode; Dynamic Client Registration and Session Management are planned.

SAML is not shipped. The SAML 2.0 provider sits in the roadmap's planning section, with "Decide On a Library" in progress. There is no administrator UI either: the dashboard and CLI roadmap item has its design stage in progress, and the User Management stage — create, modify and delete accounts — is marked not started.

State is small but real. The storage backend — SQLite locally, or MySQL or PostgreSQL — holds "user preferences, 2FA device handles and secrets, authentication logs, etc." Sessions are a separate concern, covered below.

authentik: an identity provider that can also gate

authentik's open-source tier lists OIDC, SAML, LDAP, SCIM, RADIUS, Kerberos and Proxy, and states it is OpenID Certified for OpenID Connect. Two of those change what the tool is. The LDAP provider lets legacy services bind to authentik over LDAPS, with code-based MFA and SSSD integration for Linux logins. Code-based MFA is off unless the provider's Code-based MFA Support setting is enabled and its bind flow includes an Authenticator Validation stage. The SCIM provider pushes users and groups outward: a create, modify or delete is sent to all SCIM providers, and "once an hour, all SCIM providers are fully synchronized." That delete reaches only applications with a SCIM provider; an application connected only by OIDC, SAML or LDAP does not receive it, and still needs its own offboarding step.

The architecture is a server container, a worker and PostgreSQL. The server container holds the core server and an embedded outpost, with a lightweight router in front of both. Since 2025.10, Redis is gone: caching, the embedded outpost's session store and WebSockets moved to Postgres, completing a migration that moved tasks in 2025.8. The release notes add that authentik "will use roughly 50% more database connections to Postgres" as a result. The Docker Compose install is documented for test and small-scale production setups, with a minimum of 2 CPU cores and 2 GB of RAM.

Configuration can be code. Blueprints are YAML files that template and automate configuration — authentik's own default authentication flow is created by one. A blueprint is applied in a single atomic database transaction: if any entry fails, the whole blueprint rolls back. Entries take a state of present (the default), created, must_created or absent, and absent uses Django's delete, which can cascade to related objects.

yaml
version: 1
metadata:
  name: access-review-groups
entries:
  - model: authentik_core.group
    state: present
    identifiers:
      name: app-grafana-ops
    attrs:
      is_superuser: false
      attributes:
        review_owner: platform-team
        review_scope: grafana
A blueprint declaring one group per review scope, checked against the authentik 2026.8.4 blueprint schema. identifiers find the object; attrs are applied on create and update.

Two policy models in one Authelia install

This is the detail that surprises teams in an audit. Authelia's access control section opens with: "This section does not apply to OpenID Connect 1.0." Rules match on domain, resources, methods, networks and subject, and those criteria describe one HTTP request. An OIDC token is issued to a client, not to a request, so the OIDC FAQ explains that Authelia "implemented the authorization policy as a direct option in the client."

A client's authorization_policy defaults to two_factor and can be one_factor, two_factor, or a named entry under the provider's authorization_policies. Both live in the same configuration.yml, so it is still one file — but two evaluation paths:

yaml
# excerpt — session, storage and secrets omitted
access_control:
  default_policy: "deny"
  rules:
    - domain: "status.example.com"
      resources:
        - "^/health$"
      policy: "bypass"
    - domain: "grafana.example.com"
      subject:
        - "group:ops"
      policy: "two_factor"

identity_providers:
  oidc:
    authorization_policies:
      no_contractors:
        default_policy: "two_factor"
        rules:
          - policy: "deny"
            subject:
              - "group:contractors"
    clients:
      - client_id: "wiki"
        client_name: "Internal wiki"
        authorization_policy: "no_contractors"
        redirect_uris:
          - "https://wiki.example.com/oauth2/callback"
Both policy mechanisms side by side. access_control decides proxied requests; the client policy decides the OIDC authorization request.

Three consequences follow. A domain: wiki.example.com rule in access_control does nothing for the wiki's OIDC login. access_control sees a client_credentials token only if the authz endpoint is explicitly configured to accept the Bearer scheme — the default forward-auth path above does not — and the client is allowed the authelia.bearer.authz scope. Such a token is always treated as one-factor and matches the subject oauth2:client:<client_id>, so only a one_factor rule is useful; it still does not decide the OIDC authorization request. And Authelia warns that the client policy "should not be used as a crutch for applications which do not implement the most basic level of access control on their end": OIDC moves the second half of authorization into each application. two_factor is, per the docs, "currently the highest level of authentication policy available" — there is no step-up beyond it.

Not one policy file but two policy engines in one file — and the application's own checks as a third.

What breaks, and who is paged

  • Authelia sessions without Redis. By default sessions are held in memory, and "not configuring redis leaves Authelia stateful." One replica is fine; a second replica, or a restart, loses sessions. Redis is highly recommended for production and important for high availability.
  • The users file drifting from git. A password reset writes to the file. If watch is off, a hand edit is not picked up until restart; if the file is generated from git, the next deploy can overwrite a reset. Decide which side owns the file before the first user forgets a password.
  • authentik's single dependency. Postgres now carries the cache, tasks, WebSockets and the embedded outpost's sessions as well as the data. Its connection limit and failover are the IdP's availability, so size max_connections and any pooler for the higher connection count that 2025.10 announced. If Postgres requires TLS, authentik now needs TLS 1.3 or the Extended Master Secret extension to connect.
  • Outpost misrouting. Single-application forward auth works only if /outpost.goauthentik.io on each app domain reaches the outpost. A proxy rule that forgets that path breaks login for that one app while everything else looks healthy.
  • A lapsed authentik Enterprise licence. Covered in the next section; it fails slowly and visibly, and authentication keeps working.

The access review: what each one can show an auditor

An access review asks three things: who has access to what now, who used it, and when was access removed for people who left. Controls frameworks phrase it differently — the access-control and audit families in NIST SP 800-53 on Kubernetes, or the Annex A controls in ISO 27001 without inherited controls — but the evidence is the same.

Authelia produces raw evidence, not a report. Who has access is the users file — reviewable as git history if it is managed there — or the LDAP directory; what they can reach is access_control plus every OIDC client's policy plus each application's own roles. Who logged in sits as authentication logs in the storage backend. Removal is a file edit, disabled: true or deletion, or a change in LDAP. Authelia ships no access-review report, so whoever owns the review writes the queries.

authentik keeps a structured trail. Its event log records every event, whether user- or system-initiated, with passwords and credentials stripped. Default retention is 365 days, set under System > Settings; to forward events elsewhere, the docs recommend shipping the container logs and shortening internal retention. That is all open source. Several governance features are not: the Enterprise tier lists scheduled user offboarding, enhanced audit logging for compliance, and exportable CSV reports, alongside Privileged Access Management and Google Workspace and Microsoft Entra ID integration.

As listed on 2026-10-17, Enterprise is $5 per user per month and $0.02 per external user per month, billed annually, with no cost for service accounts; Enterprise Plus starts at $20k annually. authentik counts internal and external users separately, and disabled users and service accounts consume no capacity — so disabling leavers promptly is also a licensing control. The pricing page commits that no open-source feature will move to Enterprise.

Exit ramps: leaving either one

Leaving Authelia is mostly a configuration exercise. The identity of record was never inside it: it is the users file or the external LDAP directory, and both move to the next system as they are. What stays behind is the SQL storage — user preferences, 2FA device handles and secrets, and authentication logs. Plan for users to re-enrol their second factor, and archive the authentication logs for as long as the review period requires. Redis holds session state only and is discarded. Authelia is Apache-2.0.

Leaving authentik means moving a directory. Users, groups, policies, flows and the event history are objects in Postgres. Configuration clicked together in the admin UI is not trapped: running ak export_blueprint in any authentik worker emits a blueprint for most objects, and a single flow can be exported from the flow list — but not every object is covered, primary keys are hardcoded, write-only secrets such as an OAuth client secret are omitted, and manual cleanup is expected. Treat the blueprint coverage of your configuration as the measure of how portable it is. The core is MIT-licensed, and the authentik/enterprise/ directory is under a separate licence — check what in that tree your deployment depends on before calling it open source end to end.

The long game: pick by the question you will be asked

Authelia fits when the directory already exists or the population is small and stable, every protected application speaks HTTP behind your proxy, and the review can be answered from git history and an LDAP query. authentik fits when the SSO layer has to become the directory, any application needs SAML, LDAP binds or SCIM provisioning, or the review must come out of one system with history attached. One SAML application is enough to force the question.

There is a staged path that strands nobody. Put users in LDAP rather than the YAML file from the start, run Authelia in front of it, and keep access_control and every OIDC client policy in git. If an IdP is needed later, it takes over the directory instead of rebuilding it, and Authelia's state is discarded rather than migrated. The same discipline that keeps workload identity in SPIFFE/SPIRE separate from people applies here: keep the record of who someone is in a place you own, and let the gate in front of it be replaceable.

§FAQ/Common questions

Frequently asked

Is Authelia or authentik better for a homelab or small team?

Neither is better in general. Authelia suits a fixed set of users in a YAML file or existing LDAP directory, with every app behind one reverse proxy. authentik suits a team that wants the SSO layer to own users and groups, or needs SAML, LDAP or SCIM.

Does Authelia support SAML?

No. Authelia's SAML 2.0 identity provider is on its roadmap under planning, with choosing a library in progress. It does act as an OpenID Connect 1.0 provider, which its docs describe as an open beta while also listing OpenID Certified profiles.

Why don't Authelia access_control rules apply to my OIDC app?

By design. access_control evaluates individual proxied requests by domain, path, method, network and subject. OIDC tokens are issued to a client, so each client has its own authorization_policy: one_factor, two_factor (the default) or a named policy from the provider's authorization_policies.

Does authentik still need Redis?

No. Since authentik 2025.10, caching, the embedded outpost session store and WebSockets moved to PostgreSQL, so Postgres is the only stateful service; back up the server's `/data` volume too, which holds uploaded files and CSV reports. The release notes expect roughly 50% more Postgres connections as a result.

What happens if an authentik Enterprise licence expires?

After the combined licence has been expired for over six weeks, the deployment enters read-only mode. Users can still log in and be authorized; administrators can read configuration, manage licences, and update or delete users, but cannot change most other objects. Open-source installs are unaffected.

authelia vs authentikauthentik vs autheliaauthelia forward auth traefikauthentik forward auth outpostauthelia oidc access controlself-hosted sso access review evidence

Executive Briefing

Thirty minutes to clarify your infrastructure risk

Walk us through your vendor footprint and regulatory constraints. We will tell you honestly where sovereignty creates leverage — and where it does not. No pitch deck. No obligation.