Header-based authentication to legacy apps with the authentik proxy: when teams need it
Teams need header-based authentication when an application cannot speak OIDC or SAML but reads the signed-in username from an HTTP header. The authentik proxy provider answers this directly: after a user signs in to authentik, the proxy outpost sits in front of the application and passes identity to it as headers. The outpost sets user-specific headers (such as the username and email) and application-specific headers for the upstream app, so the application can trust the value it receives without running its own login. The application keeps its existing access logic, while authentik takes over sign-in, multi-factor prompts and policy decisions.
This pattern is usually the better choice when the application's login code is old, unsupported or costly to change, and the app already maps a header value to a local account or role. Rebuilding its login means changes to the application code, new test cycles and a new attack surface inside the app. A proxy approach moves that work to the edge, but it also moves trust to the edge. Before you commit, confirm that the application honors only the headers it is meant to receive, that users cannot reach it directly, and that any header the client sends is stripped or overwritten before it reaches the app. Ask your vendor or the authentik documentation which headers the outpost sets in your version, since the exact names and behavior should be verified, not assumed.
This page covers how the proxy outpost's user and application headers work, how additionalHeaders on users and groups add static values, how custom dynamic headers are built with custom scope mappings, and how to keep the application unreachable except through the proxy. It also covers the decisions and checks that matter most for a legacy app: which headers to trust, how to test header spoofing, and how to confirm that direct network paths to the app are closed. Reverse proxy specifics are covered in the sibling pages for each proxy.
Which header option fits which application
This table compares the three ways to pass identity to an upstream application: the built-in user and application headers, static values from additionalHeaders, and dynamic values from custom scope mappings. Read each row as a question you should answer before choosing, and treat the risk column as the cost you accept by picking that option.
| Header option | Best fit | Maintained by | Main risk |
|---|---|---|---|
| Built-in user and application headers | Apps that only need the signed-in username, email or application name to label sessions or pre-fill a profile | authentik proxy outpost, with no extra configuration beyond the provider | The app must accept the header names authentik sends, so confirm the exact names in your environment before relying on them |
| Static headers via additionalHeaders on a group | A fixed flag for everyone in a group, such as a tenant or environment label | The administrator who edits the group in authentik | Values go stale when membership changes, so a user removed from a group may keep the old header until the session ends |
| Static headers via additionalHeaders on a user | A single account needing a fixed attribute the app cannot read from its own directory | The administrator who maintains that user record | Per-user values multiply quickly, and each one is another place for drift and manual errors |
| Dynamic headers via custom scope mappings | Roles, departments or entitlements computed from current group membership or user attributes at login | The team that writes and tests the scope mapping expression | Logic errors can grant or withhold access silently, so test each mapping with representative users |
| Header trust in the application | Any app that reads identity from a header instead of its own login | The application owner, who must enforce the header only from the proxy | If the app is reachable without passing through the proxy, anyone can forge the header, so block direct access |
| Identity header names in the app config | Apps with fixed header names that cannot be changed | The application owner and the authentik administrator together | A mismatch between header names in the app and the proxy causes silent failures or blank user fields |
| Session lifetime of header values | Any header that carries access decisions | The authentik administrator setting session and token lifetimes | A header set at login stays valid for the session, so revoked access may persist until the session expires |
| Change testing before release | Dynamic headers and any header that drives roles | The deploying team, before each change goes to users | Changes take effect only on new sessions in many cases, so verify with a fresh login and a previously signed-in account |
How to set up header authentication step by step
This sequence takes an application that trusts HTTP headers from confirmed identity inputs, puts authentik's proxy outpost in front of it, and closes the direct path so that only the proxy can supply those headers. Each step ends with a check you can run before moving on.
Confirm the app's header names and trust model
Before touching authentik, document exactly which headers the application reads (for example, the username, email and group headers), whether it expects them on every request, and how it decides to trust them. Ask the application owner or read its configuration reference, and confirm whether the app also has a local login that would bypass the headers. The step is done when you have a written list of header names, value formats and the network source the app will accept them from. Check: a reviewer can read the list and say which request should be allowed and which should be refused.
Create the proxy provider and application
In the authentik admin interface, create a proxy provider set to the mode that matches your app (single application or domain level), enter the external hostname users will open, and then create the application that links to it. Keep the external host separate from the app's internal address, since the outpost will reach the app over the internal network. The step is done when the application appears in the library and the provider shows the expected external host. Check: the provider's external host and the application's launch URL match the hostname in your written plan.
Assign policies to limit who can sign in
Bind a policy or group binding to the application so that only the users and groups that should reach the app are authorized. Authorization happens before headers are sent, so an unauthorized user never reaches the upstream application. Test with one allowed account and one account outside the group. The step is done when the allowed user receives the application and the other user is denied. Check: a denied user gets an authentik access denial page and the application receives no request from that account.
Configure user, group and dynamic headers
Work out which values the app needs. Use the headers the proxy outpost sets for the user and the application, add static values through additionalHeaders on users or groups, and create custom scope mappings for any value that changes per user, such as a role claim formatted for the app. Confirm the header names match the list from the first step exactly, including case and any prefix. The step is done when a test account's session produces the expected header values. Check: capture the headers the app receives for the test user and compare each one to the written list.
Route the app hostname through the outpost
Configure your reverse proxy so that the application hostname sends traffic to the authentik proxy outpost, which forwards authenticated requests to the app and sets the headers. The proxy configuration differs by product, so follow the guide for your proxy and confirm the outpost path and header pass-through settings there. The step is done when a browser request to the hostname redirects to the authentik sign-in page and, after login, loads the application. Check: the application loads through the hostname and its logs show the expected user identity.
Test that the app rejects spoofed headers
Send requests directly to the application's internal address with the identity headers set to a made-up user, and also send the same headers through the public hostname while signed out. The application must refuse both, and the outpost must not pass a client-supplied header through to the app. Repeat with a header the proxy is expected to overwrite. The step is done when every spoofed request fails and every legitimate request succeeds. Check: record the status codes and the app log lines for each request so you can show the result to a security reviewer.
Block direct access to the application
Restrict the application so it accepts connections only from the proxy, using network rules, firewall policy, or a private network path, depending on your platform. Remove any public port or DNS record that points straight at the app, and disable local bypass logins if the app allows them. Confirm the proxy can still reach the app after the rule is applied. The step is done when a request from outside the proxy network cannot reach the application at all. Check: run the direct-access test again from an untrusted network segment and confirm it times out or is refused.
Where the proxy sits in front of the application
On a single Docker Compose host, the simplest layout runs the authentik server container, which includes core and the embedded outpost, alongside a worker container and PostgreSQL. The proxy can sit on the same host as the application, so no separate outpost service is needed. The Compose guide positions this setup for test environments and small-scale production and calls for at least 2 CPU cores and 2 GB of RAM.
- Fit: suits a small number of legacy applications on one host, where all traffic already enters through one reverse proxy.
- Components: the server, worker and PostgreSQL run together, and authentik 2025.10 removed Redis, so caching, tasks and sessions now live in PostgreSQL.
- Sizing: the 2 CPU and 2 GB RAM figure is a minimum from the guide, so add headroom for your own login volume and proxied traffic.
- Shared resources: proxied traffic competes with the identity service on the same host, so a busy application can slow sign-ins.
- Hardening: the embedded outpost is served from the server itself, so decide whether you need it at all before you enable proxy routes.
Check that the reverse proxy reaches the embedded outpost on the server, and that the application cannot be contacted on its own port from outside the host.
A standalone proxy outpost runs as its own service next to the application, separate from the authentik server. It connects back to the authentik server for its configuration, so you can place it on a different host or network segment from the identity service. This placement helps when the application sits in a zone that should not hold the identity server or its database, or when proxy capacity must scale apart from the core.
- Placement: run the outpost on the application host or in the zone where the reverse proxy already sits.
- Connectivity: confirm that the outpost reaches the authentik server address and that the server can reach the outpost, including ports and TLS settings allowed by your firewall rules.
- Tokens: each outpost authenticates with a token issued by authentik, so store it in your secrets tooling and plan how you rotate it.
- Scaling: add outpost hosts or replicas for the proxy without changing the identity server.
- Version match: keep the outpost version aligned with the authentik server version, as the outposts documentation requires for compatibility.
After every authentik upgrade, check the outpost version against the server and confirm that the proxy host can still reach the server through the paths your firewall allows.
On Kubernetes, authentik installs with Helm, and the proxy can run as an outpost in the cluster beside the application pods. The Helm guide says the PostgreSQL bundled with the chart is for demonstration and test environments and recommends a separately managed PostgreSQL for production. Where the outpost runs depends on whether authentik manages it for you or you deploy it with your own manifests.
- Ingress path: the cluster ingress must send requests for protected hostnames to the outpost, so ingress rules and the authentication integration must agree on hosts and paths.
- Database: use a separately managed PostgreSQL for production, with backups and a restore test, and keep the chart's bundled database for test clusters only.
- Replicas: run more than one outpost replica where the application needs availability, and confirm how sessions behave across replicas.
- Namespaces: decide whether outposts sit in the application namespace or a shared one, since that choice shapes network policies and RBAC.
- Management mode: choose between authentik-managed outposts and manual manifests, and review the tradeoffs on the sibling page for Kubernetes outposts.
Before you route any application through the outpost, confirm the chart version you plan to deploy, the database endpoint and the network policies that let the ingress reach the outpost.
The proxy outpost works with the reverse proxy in front of the application, and each proxy has its own way of asking authentik whether a request is allowed and passing identity headers upstream. This page does not repeat those configurations. Pick the sibling page that matches the proxy you already run, and treat the proxy as part of the access control design, because a route that bypasses it can bypass authentication.
- NGINX: the auth_request pattern, the outpost location and header passing are covered on the NGINX page, including ingress-nginx annotations.
- Traefik: the forwardAuth middleware, Compose labels and Kubernetes ingress routes are covered on the Traefik page.
- Caddy: the forward_auth directive, with TLS handled by Caddy, is covered on the Caddy page.
- HAProxy, Envoy or Istio: HAProxy has its own page, while Envoy and Istio use external authorization, which changes how paths are routed to authentik.
- Protection mode: choose per-application or domain-level protection before you set proxy routes, since cookie scope and policies differ between the two.
List every hostname and path your proxy serves, then confirm which ones pass through the authentication check and whether any bypass it.
Keeping the legacy app unreachable except through the proxy
Header-based sign-in only holds if the application trusts headers from one place. The cards below cover the controls that keep that place the proxy, and each one names something your team can test before go-live and after every change.
Block direct access to the app
If users or attackers can reach the application's port directly, they can send their own X-authentik style identity headers and skip sign-in entirely. Verify this by requesting the application's internal address and hostname from a machine outside the proxy network, and confirm the connection is refused or times out. Repeat the test after any change to load balancers, DNS or published ports.
Restrict the listening network
Bind the application to a private interface or a Docker network that only the outpost can join, instead of 0.0.0.0 on a shared host. In Kubernetes, a NetworkPolicy should allow ingress to the application pods only from the outpost pods. Ask the platform team to show the rule and test it from a pod in another namespace.
Strip client-supplied identity headers
The proxy in front of the application should remove any identity headers a client sends before it forwards the request, then set them itself from the authenticated session. Without this step, a request that reaches the proxy with a forged header may pass it through unchanged. Test by sending a request with a made-up user header while signed out and confirming the application still shows no user.
Limit trusted proxy addresses
Many applications accept identity headers from any source address or from a configurable list of trusted proxies. Set that list to the outpost's exact address or subnet, and avoid wildcard or load-balancer ranges that other clients can reach. Confirm the setting in the application's own configuration, since defaults vary by product and version.
Review group-based headers on change
Group headers are copied from directory state when a session is created, so a user removed from a group can keep the old value until the session expires or is revoked. Decide the session lifetime with the application owner, and test by removing a user from a group and confirming the application denies the old role. Keep the mapping list short and reviewed.
Keep identity values out of logs
Access logs from the proxy and the application can record full headers, which often include user names, email addresses and group lists. Set the proxy's log format to omit or hash identity fields where your policy requires it, and check a sample of log lines from a test sign-in. Route these logs to a store with the same access controls as the source system.
Trade-offs of header trust compared with OIDC or SAML
Header-based authentication is a reasonable bridge when an application has no OIDC or SAML support, cannot be changed in the time available, and can be placed where only the proxy reaches it. It is the wrong pattern when the application will stay in service for years, holds sensitive data, or has other entry points. The core trade-off is that the application stops verifying identity itself. It accepts a value such as the user header set by the proxy outpost and treats it as true. With OIDC or SAML, the application validates a signed token or assertion and can check issuer, audience and expiry. With header trust, the only evidence is the network path, so the proxy and the network design become the security boundary.
That dependence has operational consequences. Every request must pass through the proxy, so a proxy outage, a misconfigured route, or a bypass path such as a second ingress, a direct container port or a debug endpoint removes the access check entirely. Before go-live, confirm that the application's port is not published on any host or network the proxy does not sit in front of, that the application rejects requests lacking the proxy's header source, and that internal health checks and service-to-service calls are handled deliberately. Also confirm how the outpost behaves when it cannot reach the authentik server, because your availability target depends on it. Ask the application's vendor or maintainers whether they plan native OIDC or SAML support, since that answer determines whether the pattern is temporary.
Plan the exit path at the start, not when the bridge begins to fail. Record which headers the application reads, which roles or groups they map to inside the application, and who owns that mapping. Keep the authentik provider and application definitions in version control or exported configuration so the setup can be reproduced. Set a review date for the decision, and treat any new feature that depends on a header as a new trust decision that needs the same review. When native SSO becomes available, run both paths in parallel for a set of test users, compare the resulting account and role assignments, and remove the header path only after you have verified that no route still reaches the application without the new login.
Limits to confirm in your environment
Header-based authentication only works when the application, the proxy and the authentik release agree on the same contract. The cards below list the assumptions most often wrong in practice, so each one can be tested against the actual application and version before traffic is moved.
Exact header names the app reads
The proxy outpost sets user-specific and application-specific headers, and your application must read exactly those names. Header names are matched as configured, and many applications expect a particular casing or prefix. Read the application's authentication configuration or source, then compare it with the headers the outpost sends from a test request. Treat any mismatch as a blocker, not a configuration detail to patch later.
Multi-valued group headers
Group membership is often passed as one header, and some applications read only the first value, parse a comma-separated list differently, or expect repeated headers. Confirm how the application handles multiple values before relying on group-based authorization inside it. If the application cannot parse several groups, decide whether to map a single role per header or to keep authorization in the proxy policy.
WebSocket and upload behavior
Protected applications that use WebSockets, server-sent events or large file uploads may behave differently when traffic passes through the outpost and the reverse proxy in front of it. Test a real session for each feature, including reconnects after idle periods, and confirm body size limits at both the proxy and the application. Record which paths are expected to bypass authentication, if any.
Session lifetime alignment
The outpost session and the application's own session can expire at different times. If the application keeps a session longer than authentik does, users may stay signed in to the app after the proxy has ended their access. Set the authentik session length, the cookie settings and the application timeout together, and test logout from both sides so a closed session is closed everywhere.
Supported authentik version line
Confirm which authentik version line your rollout will use and whether it still receives security fixes when you go live and during support. The security policy lists the supported versions and states that security releases are announced at least 24 hours in advance, so plan a window to apply them. Check the policy again before go-live rather than relying on a version recorded in an earlier design document.
Unreachable except through the proxy
Trusted headers are only safe if clients cannot send them directly to the application. Confirm that the application listens only on a private network reachable from the proxy, that the proxy strips any incoming identity headers before setting its own, and that a direct request with forged headers is refused. Test this from outside the proxy network, because internal routing often exposes the backend by accident.
Questions teams ask before header-based authentication rollout
How much effort does header-based authentication to a legacy app take?
Effort depends mostly on how many applications sit behind the proxy, how much each one trusts its headers, and how many environments need testing. A single app with one hostname and a clear header contract is a small, contained job. A portfolio of apps with mixed routing, shared domains and different header expectations takes longer because each app needs its own check. No supplied figure sets a duration, so ask any provider for a written breakdown per application, covering design, outpost deployment, header mapping, testing and cutover. Ask which parts are one-time (design, initial configuration, cutover) and which recur (new apps, upgrades, user and group changes).
What drives the cost of a proxy rollout up or down?
The main drivers are the number of applications, the number of distinct hostnames and paths, how many groups need different header values, the reverse proxy in use, and the depth of testing required by your change process. Applications that already read a trusted header are cheaper to protect than applications that need code changes to accept one. Quotes should separate the discovery and design work, the configuration per application, the outpost deployment on Docker or Kubernetes, and the handover to your team. Ask which items are fixed in the written scope and which are priced as change requests.
Can our internal team set this up without a partner?
Yes, if your team has someone who can operate authentik, configure a proxy provider, edit reverse proxy routing and test header handling in a non-production environment. The hardest part is usually not the authentik setting but the application side: confirming which headers the app trusts, locking the app so only the proxy can reach it, and proving that a forged header from a client is rejected. Teams that lack an application owner for each legacy system often find the knowledge gap takes more time than the configuration itself. A partner is useful when you need a fixed scope, an independent review or capacity during cutover.
What do we need to provide to a partner before the work starts?
Plan to provide the following before the scope is agreed:
- An inventory of each legacy application, its hostnames, paths and current login method
- A named owner for each application who can confirm which headers it reads and how it maps a user to an account
- Access to a test environment that mirrors production routing, including the reverse proxy and DNS names
- Your change window rules, rollback expectations and who approves cutover
Without app owners and a test environment, header behavior is guessed rather than verified, which is where most rollbacks start.
Does the open-source edition of authentik include the proxy provider?
The proxy provider is listed among authentik's provider types, and authentik's repository places most of the code under the MIT license (SPDX: MIT). Code in the authentik/enterprise/ directory falls under a separate enterprise license. Confirm the exact licensing of the components you plan to use against the LICENSE file in the repository and the current provider documentation before you finalize the design. The pricing page lists Enterprise-only features such as Google Workspace and Microsoft Entra ID integrations, mTLS, privileged access management and enhanced audit logging, so check that none of those are needed for your header design. Your licensing review should be written down in the scope.
How do authentik upgrades affect the proxy configuration?
Upgrades can change how the outpost and provider behave, so the proxy configuration should be treated as part of the release, not as a separate task. The 2026.5.x and 2026.8.x lines are listed as receiving security fixes, and the project announces security releases at least 24 hours in advance, which gives you a window to test. Keep the outpost version aligned with the server version, test header output in staging after each upgrade, and confirm that additionalHeaders and custom scope mappings still produce the values your applications expect. Ask any partner how upgrades are scheduled and whether they are covered by a retainer or a separate change.
How do we confirm that applications cannot be reached without the proxy?
Confirm it with tests rather than assumptions. The application should only accept connections from the proxy's network path, for example through firewall rules, private networking or a bound interface, and any header the application trusts must be stripped or overwritten at the proxy so clients cannot inject their own values. Run direct requests to the application with forged headers and confirm they are refused, then repeat the test after every configuration change. Record the results as evidence for your security review.
How DeployOpen scopes and delivers header-based access
DeployOpen plans and implements header-based access inside your own infrastructure, under a fixed scope that is agreed in writing before work starts. The scope lists each protected legacy application, the proxy provider and outpost placement, the header set each application expects (for example, which user identifier, email, name or group values it reads), any additionalHeaders on users or groups, and any custom dynamic headers built from scope mappings. Ask for the scope to name the reverse proxy in front of each application, because the proxy is where the trusted headers are set, stripped and checked. Deliverables and timelines follow from that written list, so a quote can be compared line by line against your own team's estimate.
The verification step is what makes the design safe, and it should be a named deliverable rather than an assumption. DeployOpen tests header spoofing: a request that carries forged X- identity headers from outside the proxy must not reach the application with those values intact. It also tests direct-access blocking: the application's own network address, port and internal hostname must refuse connections that did not come through the proxy. Each test is run against every protected application in scope, and the results are recorded as evidence for your security and audit teams. Confirm with the vendor which headers your authentik version sets and how the outpost handles incoming copies of them, since that behavior determines what the tests must prove.
Ongoing work is handled through a retainer rather than a new project each time. A retainer can cover monitoring of the outpost and proxy configuration, support during authentik upgrades (authentik requires planned upgrades, and outposts must match the server version), re-running the spoofing and direct-access checks after application or proxy changes, and adding new applications under the same pattern. The scope of any retainer, its response expectations and its service levels are agreed in writing, so ask for them explicitly. Your team keeps ownership of the applications and the trust boundary, and the written handover documents how each header is produced, where it is enforced and how to test it again.

