Skip to main content

Hardening authentik

authentik is secure by default, but you can tighten it further. Most of the changes below cost something in convenience. Apply the ones that match your threat model rather than all of them at once.

Authentication

Password policy

The shipped password policy requires 8 characters and runs a zxcvbn strength check, failing anything scoring 2 or below. It is bound to the default password change flow only, so it does not apply to enrollment flows or to passwords an administrator sets directly. Bind it, or a policy like it, anywhere else a user can choose a password.

Two changes bring the policy in line with the NIST SP 800-63 Digital Identity Guidelines:

  • Raise the minimum length to 15 characters. NIST allows 8 characters only when the password is one factor of MFA, and the shipped authentication flow skips MFA validation for users with no authenticator enrolled. If MFA is mandatory in your deployment, 8 characters remains sufficient.
  • Enable Check haveibeenpwned.com, which covers NIST's requirement to compare passwords against commonly used, expected, or compromised values.
note

The haveibeenpwned.com check needs outbound network access, so it does not work on air-gapped instances. Air-gapped deployments need an Expression policy that checks against a locally held list instead.

For the remaining options, see Password policy. A password expiry policy also exists, though NIST no longer recommends routine forced rotation.

Multi-factor authentication

Requiring a second factor is the single most effective change you can make to an authentication flow. Add an Authenticator Validation stage to your authentication flow and review these settings:

  • Not configured action defaults to Continue, which lets a user with no authenticator sign in with a password alone. Set it to Force the user to configure an authenticator, or to Deny the user access if you enroll authenticators out of band.

  • Restrict Device Classes to the methods you accept. All six are enabled by default; limiting the stage to WebAuthn removes phishable factors such as TOTP and SMS.

  • Set WebAuthn User verification to Required. The default, Preferred, lets an authenticator prove possession without confirming who is holding it.

  • Use WebAuthn Device type restrictions to limit authentication to approved hardware. Configure the same allowlist on the WebAuthn authenticator setup stage so new enrollments match.

    The filter only applies to devices that have a stored device type. Devices enrolled before authentik 2024.4, and authenticators whose AAGUID authentik does not recognize, have no stored type and pass the filter untouched. To make the restriction enforceable, delete those enrollments and have the users re-enroll.

  • Last validation threshold defaults to seconds=0, which validates on every attempt. Only raise it if you deliberately want to skip validation for users who recently used a device.

  • Leave the four throttling factors at their default of 1. They apply exponential back-off to code-based methods, doubling the lockout after each consecutive failure: one second, then two, then four. Setting a factor to 0 turns the back-off off entirely.

Recovery flows deserve the same scrutiny. A recovery flow that only requires an emailed link reduces the whole account to the security of the user's mailbox.

Account enumeration

The Identification stage ships with enumeration protection on, but two of its defaults still leak.

  • Keep Pretend user exists enabled, as it is by default. With it off, an unknown identifier fails at this stage while a valid one continues, which tells an attacker which is which.
  • Disable Show matched user, which is enabled by default. It shows the matched account's username and avatar on the next step, and falls back to echoing whatever was typed for an unknown identifier, so the two cases look different.
  • Limit User Fields to the identifiers you need. The default flow accepts both email and username, which doubles the values an attacker can test per account.
  • Bind a policy to the Enrollment flow, Recovery flow, and Passwordless flow, or delete those flows, if they should not be reachable. Unlinking them here only removes them from the login screen; the flows stay live at /if/flow/<slug>/.

Brute-force resistance

Combine these controls to slow down credential stuffing:

  • Use a Reputation policy to react to repeated failures from a username or client IP. Each failed login scores -1 and each success +1, and the policy passes when the score is at or below its threshold, so it passes for bad actors. Bind it to a CAPTCHA stage to challenge low-reputation requests, or to the authentication flow with Negate enabled to deny them. Binding it to a flow without Negate locks out everyone except the attacker. Score limits live under System > Settings as Reputation: lower limit and Reputation: upper limit.
  • Add a CAPTCHA stage unconditionally, either standalone or inline on the Identification stage, if you would rather not make it reputation-dependent.
  • Bind a GeoIP policy to restrict sign-ins to expected countries, or to require extra verification elsewhere.
  • Configure notification rules on login_failed and suspicious_request so spikes surface instead of only being recorded.

Sessions

Session lifetime

The User Login stage controls how long an authenticated session lasts.

  • Session duration defaults to seconds=0, which ends the session when the browser closes. Any explicit duration makes the session persistent instead, surviving browser restarts for that long. Set one only if you need it, and keep it short.
  • Remember device defaults to days=30. That is a signed cookie identifying the user on this device, outliving the session itself. Set it to seconds=0 if you do not want it.
  • Remember me offset defaults to seconds=0, which hides the remember-me option. Leave it there, or keep any offset short.
  • Enable Terminate other sessions, off by default, so a new sign-in invalidates the user's existing sessions.

Session binding

The User Login stage can bind a session to the network and location it was created from, then terminate it when the client moves beyond the configured strictness. This limits how far a stolen session cookie travels. A cookie replayed from within the same permitted ASN or region still works, so treat binding as relocation detection rather than as replay protection.

  • Network binding can bind to ASN; ASN and network; or ASN, network, and IP.
  • GeoIP binding can bind to continent; continent and country; or continent, country, and city.

Both default to no binding. When a bound session moves, authentik terminates it and records a logout event naming what changed.

warning

Stricter bindings cause more spurious logouts. Users on mobile networks, on VPNs, or behind load-balanced egress change ASN or IP mid-session as a matter of course. Start with the loosest binding that meets your requirements and read the resulting logout events before tightening it.

Each binding type needs its own database: network binding uses the ASN database (AUTHENTIK_EVENTS__CONTEXT_PROCESSORS__ASN), GeoIP binding uses the GeoIP City database (AUTHENTIK_EVENTS__CONTEXT_PROCESSORS__GEOIP).

warning

A missing database fails the lookup, which counts as a broken binding and terminates the session. authentik only runs the check once a client's IP changes, never at login, so a missing database can stay hidden long after you enable binding.

Administrative access

Limit superusers

Any account in a group with Superuser Privileges can change every object in authentik, including the flows that protect it. Grant the smallest set of permissions that lets an administrator do their job:

  • Use roles and access control to assign specific object and global permissions instead of superuser membership.
  • Review superuser group membership regularly, and require phishing-resistant MFA on every superuser account.

Impersonation

Impersonation lets an administrator act as another user. Both settings live under System > Settings and are enabled by default:

  • Disable Impersonation if you do not need it. This applies globally, superusers included.
  • Keep Require reason for impersonation enabled so every use carries a justification.

Impersonation always generates impersonation_started and impersonation_ended events. Configure a notification rule on them so use is visible in real time rather than at audit.

Tokens and app passwords

API tokens and app passwords bypass flow-based authentication, including MFA.

Review existing tokens under Directory > Tokens and App passwords, and prefer service accounts with scoped permissions over tokens tied to a superuser.

Audit events

Events are authentik's audit log. Two settings under System > Settings govern retention:

  • Event retention defaults to days=365. Raise it to match your requirements, or forward events to an external system and lower it. authentik stamps the expiry when it writes the event, so a change only affects events recorded afterwards.
  • GDPR compliance, enabled by default, deletes a user's events along with the user. Disable it if your audit requirements outweigh that, bearing local data protection obligations in mind.

Notification rules give early warning of administrative activity: model_created, model_updated, and model_deleted for configuration changes, or secret_view for reading a token or certificate. See event actions for the full list.

Restricting configuration changes

Expressions, blueprints, and CAPTCHA stages all let a highly privileged user change how authentik behaves. By default authentik limits them to superusers and users holding the relevant permissions, and logs every change. To remove the ability entirely, block the corresponding API endpoints in front of authentik, for example at your reverse proxy.

Once you do, the affected objects can only be edited through blueprints on the file system. Restrict access to that file system, and to whatever deploys files onto it, with the same care.

Expressions

Expressions run custom Python inside authentik to modify its behavior. To stop every user, superusers included, from creating or editing them, block:

  • /api/v3/policies/expression*
  • /api/v3/propertymappings*
  • /api/v3/stages/prompt/prompts*
  • /api/v3/managed/blueprints*

Blueprints

Blueprints manage authentik configuration as code. They carry the same permission requirements as expressions, but because they drive the API at a lower level they can create other objects outright. To stop every user from creating or editing them, block:

  • /api/v3/managed/blueprints*

CAPTCHA stage

The CAPTCHA stage verifies a user while authenticating or authorizing an application. It supports several providers, including Google's reCAPTCHA and Cloudflare's Turnstile, so the URL of the JavaScript snippet it loads is editable. Depending on your threat model, a malicious insider could point it somewhere else. To stop every user from creating or editing CAPTCHA stages, block:

  • /api/v3/stages/captcha*
  • /api/v3/managed/blueprints*

Deployment

Secret key

AUTHENTIK_SECRET_KEY signs session cookies and backs several other cryptographic operations. Generate it from a cryptographically secure source, keep it out of version control, and supply it through a secret manager rather than a plaintext environment file. Rotating it invalidates every active session, so change it if it leaks, not as routine maintenance.

Trusted proxy headers

AUTHENTIK_LISTEN__TRUSTED_PROXY_CIDRS decides which source addresses may set proxy headers such as X-Forwarded-For. It defaults to loopback plus every private range, which is broader than most deployments need.

Narrow it to the addresses of your actual reverse proxies. Any untrusted client that can reach authentik directly from a listed range can spoof its own client IP, which undermines reputation policies, GeoIP policies, session binding, and the accuracy of the audit log all at once.

Database connections

AUTHENTIK_POSTGRESQL__SSLMODE defaults to disable, which validates no certificate at all. Unless the database is reached over a trusted local socket, set it to verify-ca, or to verify-full where hostname verification is available.

Embedded outpost

The embedded outpost runs inside the authentik server and serves proxy provider traffic. If you run standalone outposts, or no proxy providers at all, set AUTHENTIK_OUTPOSTS__DISABLE_EMBEDDED_OUTPOST to true to shut it off.

Logging and error reporting

  • Keep AUTHENTIK_LOG_LEVEL at its info default in production. trace is a debugging level and can put session cookies and request headers into your logs.
  • AUTHENTIK_ERROR_REPORTING__ENABLED is disabled by default. If you enable it, leave AUTHENTIK_ERROR_REPORTING__SEND_PII disabled, or point the DSN at a Sentry instance you control.

HTTP headers

Content Security Policy (CSP)

Content Security Policy mitigates content injection. authentik does not set a CSP on its own interface, so it depends on your installation; we recommend setting the header at a reverse proxy.

warning

authentik already sets a restrictive CSP on user-uploaded files under /media. Do not overwrite a header authentik has set, as replacing that one weakens it. Add your header only where none exists.

authentik needs at least these locations allowed:

default-src 'self';
img-src https: data:;
object-src 'none';
frame-ancestors 'self'; # Same-origin framing is used by the flow executor and SAML
style-src 'self' 'unsafe-inline'; # Required due to Lit/ShadowDOM
script-src 'self' 'unsafe-inline'; # Required for generated scripts

Get this wrong and the client silently fails to load code it needs, so test before rolling it out. Your deployment may need more locations, for example:

  • when using a CAPTCHA service
  • when using Sentry
  • when using custom JavaScript in a prompt stage
  • when using Spotlight Sidecar for development
  • when using images hosted over HTTP
note

frame-ancestors 'none' is stricter, but the flow executor and the SAML POST bindings intentionally permit same-origin framing. Use 'self' unless you have confirmed nothing in your deployment relies on it.

Other headers

authentik already sends X-Frame-Options on its own responses. At the reverse proxy, consider adding:

  • Strict-Transport-Security, once every host under the domain is served over HTTPS.
  • Referrer-Policy: strict-origin-when-cross-origin or stricter, so flow URLs carrying tokens do not leak in referrers.
  • X-Content-Type-Options: nosniff.