User authentication states
Signed out, MFA, session expiry, and silent refresh.
Authentication is a state machine whether you design it as one or not — the only question is whether the states are written down or discovered through bug reports. This template writes them down: SignedOut, Authenticating, MfaRequired with its lockout path, SignedIn, and SessionExpired with the two outcomes that define modern session handling — silent refresh back to SignedIn, or refresh failure back to SignedOut.
The transitions that earn their place here are the unglamorous ones. "Too many attempts" out of MFA, and the expired-session fork, are exactly the cases that get improvised at implementation time when nobody drew them first.
When to use this template
- Frontend session logic — map the diagram one-to-one onto your auth store or reducer, so every state has a screen and every transition has a handler before coding starts.
- Security reviews — verify the failure paths: invalid credentials return to SignedOut, MFA attempts are bounded, and a failed refresh cannot leave the user in a phantom signed-in state.
- Cross-team alignment — backend, frontend, and mobile teams implementing the same auth flow can agree on these states once instead of diverging three ways.
How to adapt it
Match the states to your identity provider's actual semantics, then extend:
- Add an OAuth redirect state between SignedOut and Authenticating if social login bounces users through an external provider.
- Split SignedIn into active and idle substates if you enforce an inactivity timeout distinct from token expiry.
- Add a PasswordResetRequired state for forced rotations or compromised credential flows.
Visual edits regenerate clean Mermaid code, so the state machine you refine in the editor drops straight into your design doc — and stays in sync with the implementation it specifies.
Mermaid code
Copy it anywhere Mermaid is supported — GitHub, Notion, or your docs.
stateDiagram-v2
[*] --> SignedOut
SignedOut --> Authenticating: Submit credentials
Authenticating --> SignedIn: Credentials valid
Authenticating --> SignedOut: Invalid credentials
Authenticating --> MfaRequired: MFA enabled
MfaRequired --> SignedIn: Code verified
MfaRequired --> SignedOut: Too many attempts
SignedIn --> SessionExpired: Token expires
SessionExpired --> SignedIn: Silent refresh
SessionExpired --> SignedOut: Refresh failed
SignedIn --> SignedOut: Logout
Frequently asked questions
- What states does a user authentication flow have?
- This model uses five: SignedOut, Authenticating (credentials submitted, verdict pending), MfaRequired (password accepted, second factor outstanding), SignedIn, and SessionExpired (access token dead, refresh pending). Most auth bugs live in the last two transitions — what happens when a token expires and whether silent refresh succeeds or kicks the user out.
- Why model MFA as a separate state instead of part of login?
- Because the user is genuinely in between: the password was correct, but they are not signed in yet, and that half-authenticated condition needs its own UI, its own timeout, and its own lockout rule. The "too many attempts" transition back to SignedOut is a real security requirement that only becomes visible when MFA is a distinct state.
- What is silent token refresh and why is it in this diagram?
- Short-lived access tokens expire constantly during normal use; silent refresh exchanges a refresh token for a new access token in the background so the user never notices. The diagram shows both outcomes — SessionExpired back to SignedIn on success, and SessionExpired to SignedOut when the refresh token itself is invalid or revoked.
- When should I use a state diagram instead of a flowchart for auth?
- Use a state diagram when the user occupies exactly one state at a time and events drive the transitions — which is precisely how auth sessions behave, and how you will implement them in a state machine or reducer. Use a flowchart for the one-time signup journey. Edit the states visually and the editor regenerates clean Mermaid code.