Breaking open Authentik's authentication flow: the identification stage for finding a user, the password stage for validating credentials, the authenticator validate stage for MFA verification, the range of TOTP, WebAuthn, and static OTP methods, and the device enrollment and recovery flows.

In episode 6, you learned to create policies — including the pattern that forces some users through MFA. Now it's time to open the inner workings of the machine: how the authentication flow actually works, and how that second security layer is executed by Authentik.
Imagine a building with two layered doors. The first door locks with a password — anyone who memorizes the combination can enter. The second door only opens if you also carry a special access card. One key alone isn't enough; that combination is what's called Multi-Factor Authentication. In this episode, you'll program both doors, from the identification stage to the authenticator validate stage.
In general, the login flow in Authentik runs through three stages represented by three stage types:
This order isn't a rigid rule — Authentik lets you rearrange and add other stages — but it's a sensible default pattern. Each stage answers a different question: "who are you", "what proof of knowledge do you have", and "what proof of possession do you have".
The identification stage answers the first question. This stage displays the login form, then looks up the user by username or email. Several behaviors can be configured:
The lookup result is stored as the user being processed, often called pending_user, in the flow context — data that later stages and policies (as you learned in episode 6) read.
The password stage validates the password against the configured authentication backend: Authentik's internal user database, or an LDAP source if you use federation. Several things can be configured:
Note: the password stage only validates "what you know". It doesn't guarantee security if the password has already leaked — that's why the second door exists.
This is the second door. The authenticator validate stage checks whether the user has a registered MFA device, then asks them to verify. What's interesting is that this stage is conditional: it only runs if the policy bound to the stage binding passes. That's where the "MFA required for admins" pattern from episode 6 comes from.
Authentik supports several authenticator types users can enroll:
Important
Requiring MFA without providing backup codes is a costly oversight. Always ask users to enroll static OTP during enrollment — when a phone is lost or an authenticator app is deleted, a static token is the only way back in until the user enrolls a new device.
There are situations where you want to give users a choice: "login with password OR passkey", or "verify with TOTP OR backup code". That's the purpose of the duplicate stage.
A duplicate stage marks a step as already completed. If several stages in one flow are marked as duplicates of each other, once one finishes, the rest are automatically skipped. Like a station gate: after your ticket is validated at one gate, you don't need to pass through the other queue gates.
This is also the key pattern for passwordless: run a WebAuthn duplicate stage alongside the password stage, so users with a passkey can log in without typing a password at all.
MFA is useless if users have no way to enroll devices. This is where the setup stages and supporting flows come in:
authenticator-totp-setup, authenticator-webauthn-setup, and authenticator-static-setup. Each stage shows instructions, validates the device, then saves it to the user.default-enrollment-flow), an MFA setup stage is appended at the end so the first device is enrolled right away.default-recovery-flow is used when a user forgets their password or loses a device. This flow usually verifies email or backup codes before allowing new device setup.Warning
The recovery flow is a shortcut into an account. Make sure it uses stronger verification than merely knowing an email: for example email plus an answer to a question, or a specially sent token. Don't let attackers use the recovery flow to take over someone else's account.
The most common way to enable MFA is binding a policy to the authenticator validate stage binding in the authentication flow. For example: require MFA only for members of the admins group.
if ak_is_group_member(request.user, name="admins"):
return True
return FalseThis policy is bound to the authenticator validate stage binding. The result: members of the admins group pass through the second door, while regular users go straight in after the password. Note how this works — a failing policy skips the stage, it doesn't stop the login. To enforce MFA, the validation stage must be one that only passes if a device is verified.
The second frequently used pattern is only running a setup stage when the user has no device at all — for example in the enrollment flow.
return not ak_user_has_authenticator(request.user)Tip
Combine the policies from episode 6 with this stage knowledge: you can require MFA for specific applications (via a policy that checks the application context), for specific networks, or only outside working hours. All the same conditional logic applies to the second door.
Key points from this episode:
Now both building doors are programmed: identity is verified, and MFA secures what matters most. Only one question remains — how can outside applications take advantage of all this? In episode 8, you'll open the third door: creating OAuth2 and OIDC providers in Authentik so external applications can log in with an industry standard.