thim.dev/blog
AUG 2026 · 6 MIN READ

One door

Self-hosting has a dirty secret: every application you run ships its own login page, and they are not created equal. Some are excellent. Some treat passwords the way a fairground treats safety inspections. All of them are separate doors into your life, each with its own lock, its own idea of session length, and its own opinion about whether two-factor is worth supporting.

Run fifteen services and you have fifteen doors. The security of everything behind them is the security of the worst one.

I stopped accepting that trade. There is one door now.

someone arrives the one door authentik + proxy prove who you are 2fa, every time no badge, no entry the apps none of them ever sees a password = a visitor one place to say yes; one place to say no longer

§ The shape of it

Authentik runs as the identity provider, and the reverse proxy in front of everything is the enforcement point. When a request arrives for anything protected, the proxy does not pass it along and hope the app's login page holds. It stops the request at the edge and asks Authentik one question: is this person allowed here?

No session, no entry. The request never reaches the application at all. Which means the application's own login page, whatever its quality, is no longer load-bearing: an outsider cannot even reach the form to attack it.

The applications behind the door never see a password. Most of them do not even know authentication happened; they just receive traffic that has already been vouched for. The few that integrate properly speak OIDC to Authentik and get told who arrived. Either way, there is exactly one place in the lab where a password or a passkey is ever presented, and it is a place I chose, configured, and can reason about.

§ What one door actually buys

Turning someone off is one action. When a person should no longer have access, I disable one account and every service stops recognising them at once. With per-app logins, offboarding is a scavenger hunt across fifteen admin panels, and the one you forget is the one that matters.

Two-factor is policy, not hope. The organisation requires a second factor, so every login through the door involves one, regardless of whether the app behind it has ever heard of TOTP. Per-app 2FA support stops mattering when no app does its own authentication.

Passkeys, once. I sign in with a hardware-backed key rather than a password. Doing that per-app would depend on fifteen separate implementations; doing it at the door means one implementation covers everything, including software that will never support passkeys natively.

Access is described in one language. Who can reach what is expressed as group membership in one system, not as a scattering of per-app user tables. When I want to know what someone can touch, I read one page.

Old software gets modern authentication. Half the value lands on applications that never expected an identity provider. A tool with a rudimentary login page, sitting behind the door, inherits 2FA, passkeys, and centralised session control it has no idea exist.

§ The tradeoff, stated plainly

Concentrating identity concentrates importance. Authentik is now the single most consequential service in the lab: when it is down, nothing protected can be signed into, and its own account database is the thing to protect above all others.

And there is a structural wrinkle worth understanding before you build this: the identity provider cannot sit behind itself. Its own login page must be reachable directly, because it is the thing that opens every other door. That is not a flaw, it is the definition of being the door, but it means the IdP is held to a different standard: it is the one service whose own authentication genuinely is load-bearing, so it gets hardware-backed credentials and the strictest settings, and it earns more of my attention than anything else I run.

I consider the trade obviously correct. One critical, carefully-watched service versus fifteen variably-mediocre login pages is not a close call. But it is a trade, and pretending otherwise is how people end up surprised.

§ The subtle part: sessions are not passwords

One thing that took a while to internalise: the door creates two layers of session. The proxy remembers that you have been vouched for; the app may separately remember you in its own cookie. Log out of the app and the proxy will happily vouch for you again without a prompt, which looks like a bug and is actually the design. The session that matters is the one at the door, so that is the one with the deliberate lifetime, and killing access for real means killing it there.

This is also why testing access changes from your own browser misleads: you carry valid sessions everywhere. The only honest test of "who can reach this" is a private window, every time. I have written that sentence before on this blog and I will probably write it again, because it is the single most repeatable mistake in this entire domain.

§ If you build this

Three things I would tell a friend starting from zero.

Put the enforcement at the proxy, not in each app. App-level SSO plugins vary as much as app-level login pages did; you would be trading fifteen bad doors for fifteen bad OIDC clients. The proxy model protects everything the same way, including the software that cannot be taught.

Treat groups as the API. Resist the temptation to grant access person-by-person, app-by-app. Define groups for the roles that exist, bind applications to groups, and membership becomes the only thing you ever edit.

And decide what is deliberately public. Not everything belongs behind the door; a public website behind SSO is a lesson I have already written up. The point of one door is not that everything is locked. It is that "locked" and "open" are each true on purpose, in one place you can read.

§ The point

Identity is the least glamorous part of the lab and the one with the highest stakes per minute of effort. Nothing here required exotic software or heroic configuration: one identity provider, one enforcement point, groups, a second factor, and the discipline to put nothing else in charge of the question "who are you".

The result is that the question gets asked well exactly once, instead of badly fifteen times. That is the whole idea.