Templates
Types
EN

Login Flow Diagram Guide

How to draw a login flow diagram that answers the questions reviewers actually ask — what a session is, why every failure looks the same, and three editable examples.

Published on ·9 min read
loginauthenticationsequence-diagramtemplate

What is a login flow diagram?

A login flow diagram shows how an anonymous request turns into an identified one. Not "how the password is checked" — that part is one arrow and a library call. What the diagram is actually about is the thing handed back afterwards, how long it lives, where it is stored, and what invalidates it.

Almost every login diagram on the internet is the same picture: a box for the form, a diamond that says credentials correct?, a green arrow to "Dashboard" and a red arrow back to "Login". That picture is not wrong, it is just answering a question nobody has. Nobody is confused about whether a wrong password should let you in. What people are confused about — and what breaks in production — is everything the diamond leaves out: what got created on the yes branch, how many times you can take the no branch before something happens, and whether the two branches are distinguishable from the outside.

That last point is why this is usually a sequence diagram rather than a flowchart. A flowchart draws your server's reasoning. A sequence diagram draws what crosses the wire, which is the only thing an attacker can see, and therefore the only thing worth reviewing. The moment you draw responses as arrows instead of outcomes as boxes, "user not found" and "wrong password" stop being two branches of your logic and become two strings a stranger can tell apart.

This page draws the password path. The second factor and the sign-in-with-Google button attach to it at a single point each, and each has its own page — folding them in here would produce a diagram with three beginnings.

What a login flow diagram has to show

Six things. If your diagram has the diamond but not these, it is a picture of a form, not of a login.

  • The session, as a named artifact with a lifetime. Not "log the user in" — draw what is created, where it is stored, and for how long: sid cookie, HttpOnly Secure SameSite=Lax, 30-day absolute lifetime. Half the arguments a login design produces are actually arguments about cookie attributes that nobody wrote down.
  • One response for every failure. Wrong password, unknown email, disabled account, unverified email — the arrow back to the user should carry the same status and the same words. Draw them merging into a single arrow, because a diagram with four differently-worded error arrows is the enumeration bug, drawn.
  • The rate limit, with its two subjects. Per account and per IP are different controls solving different attacks — credential stuffing against one user, spraying across many. Put both on the diagram with numbers, and put the lockout response on it too, since "429 with a retry-after" and "silently pretend the password was wrong" are different products.
  • The constant-time detail. The hash verification runs even when there is no user row. If your diagram branches to "return 401" before the hash step, it is documenting a timing oracle: the unknown-email path returns in 2ms and the wrong-password path in 200ms, and that difference is machine-readable.
  • The two attachment points, as one arrow each. The second factor plugs in after the password check and before the session is issued. An external identity provider replaces the password check entirely. Marking those two spots keeps this diagram honest about its own scope, and tells the reader where the other diagram begins.
  • Password reset. It is not a support feature, it is a second way to obtain a session, and it is attacked as one. A login diagram that stops at the form is missing half of its own attack surface.

Here is the skeleton — the version everybody draws, with none of the six on it. It is worth looking at precisely because it looks finished. Every arrow in it is correct; the diagram is still useless for review, because nothing here can be wrong in an interesting way.

View the Mermaid source
sequenceDiagram
    participant User
    participant App as Web App
    participant Auth as Auth Service
    participant DB as User Store

    User->>App: email and password
    App->>Auth: sign in
    Auth->>DB: look up the user by email
    DB-->>Auth: the stored password hash
    Auth-->>App: session token
    App->>User: redirect to the dashboard
A minimal login flow diagram: the user submits an email and password, the service checks the hash and returns a session.

How to draw a login flow diagram

Three steps. The first one is a reordering, and it is most of the value.

Step 1 · Draw the session first, not the check

Start at the end. Before you draw a single arrow of the form, write down what exists after a successful login that did not exist before:

- a row somewhere, or a signed token with nothing behind it - an identifier delivered to the browser, with a specific set of cookie attributes - an expiry — and probably two: an idle one and an absolute one - a list of things that destroy it early

Now work backwards. The credential check exists to authorise creating that object, and once you see it in that order the diagram writes itself: the check is a guard, and everything interesting is on the other side of it.

Doing it the usual way — form, diamond, done — produces diagrams where the session is implied by an arrow labelled "success". That label is where lifetime bugs hide, because nothing on the page ever forced anyone to say how long "success" lasts.

Step 2 · Make every failure look identical

List every way this can go wrong, then draw them all arriving at one arrow:

- no account with that email - account exists, wrong password - account exists, correct password, but disabled or unverified - too many attempts

Only the last one is allowed to look different, and only because it has to — you cannot rate-limit someone without telling them. Everything else gets the same status code, the same message, and ideally the same latency.

This is the step people skip, and skipping it is not a subtle mistake. A signup form that says "this email is already registered" combined with a login that says "no account with that email" is a free membership-checking API: feed it a leaked address list and it tells you who has an account here. Both messages are individually helpful and jointly a disclosure, which is exactly the kind of thing a diagram catches and a code review does not, because the two strings live in different files written months apart.

If your product genuinely needs to tell users their account is disabled, do it after the password is verified — at that point you are talking to the account owner, not to a stranger. On the diagram that is one arrow moved below a branch, and it is the whole fix.

Step 3 · Draw it

Describe it in sentences and let text2diagram lay it out — "the user posts an email and password, the service rate limits by email and by IP, loads the user, verifies the hash even when no user exists, and on success creates a 30-day session and sets an HttpOnly cookie; every failure returns the same 401" comes back as an editable sequenceDiagram with the alt blocks already nested correctly.

Or open one of the three below and rename the participants. The branch structure is the part worth keeping.

Login flow diagram examples

Three diagrams covering the three questions a login design actually has to answer: what happens at the door, what the thing you were given is worth over time, and how someone gets back in without it.

1 · Password sign-in, with the parts people leave out

Four details here are the reason to copy this one rather than draw your own from memory.

The rate limit is before the database lookup, and it names both subjects. Putting it after means an attacker still gets a free query per attempt, which is the expensive part.

run it even when there is no row looks like a note to an implementer, and it is, but it is also the difference between a login endpoint and a user-existence endpoint. Skip it and the timing tells the whole story.

The session arrow carries its attributes and its lifetime. That single label has settled more design arguments than any paragraph of prose next to it.

And the failure branch merges: no row and wrong password produce the same arrow, deliberately drawn as one. If you can find two distinguishable failure arrows in your own diagram, you have found a bug without running anything.

View the Mermaid source
sequenceDiagram
    autonumber
    participant User
    participant App as Web App
    participant Auth as Auth Service
    participant DB as User Store

    User->>App: email and password
    App->>Auth: sign in
    Auth->>Auth: rate limit check - 5 per email, 20 per ip, 15 min
    alt over the limit
        Auth-->>App: 429 with retry after
        App->>User: too many attempts, try again later
    else within the limit
        Auth->>DB: load the user by email
        DB-->>Auth: a row, or nothing
        Auth->>Auth: verify the hash - run it even when there is no row
        alt hash matches and the account is active
            Auth->>DB: create session, idle 30 min, absolute 30 days
            Auth-->>App: Set-Cookie sid, HttpOnly Secure SameSite=Lax
            App->>User: redirect to the dashboard
        else no row, wrong password, or account disabled
            Auth->>Auth: count this attempt against both limits
            Auth-->>App: 401 email or password is incorrect
            App->>User: one message for every failure above
        end
    end
A password login sequence diagram with per-account and per-IP rate limiting, constant-time hash verification, a session cookie with its attributes, and a single shared failure response.

2 · What the session does after login

A state diagram, because this part is not a conversation — it is one object aging. Drawing it separately is what stops "session" from being a word on an arrow.

The two expiries are the point. Idle is a sliding window that resets on every request; absolute does not reset, ever. Systems with only the sliding one issue sessions that live forever as long as a tab is open somewhere. Systems with only the absolute one log people out mid-task at an arbitrary moment. Almost everyone wants both, and almost nobody writes both down.

Revoked is the transition worth arguing about in review. When a user changes their password because they think someone else has it, the only response that matches their intent is killing every session everywhere — including the attacker's. If your diagram has no arrow from password changed to Revoked, then changing the password does nothing to whoever is already inside.

View the Mermaid source
stateDiagram-v2
    [*] --> Anonymous
    Anonymous --> Active: password verified, session created
    Active --> Active: request inside the idle window
    Active --> Idle: 30 minutes with no request
    Idle --> Active: a request arrives, window slides
    Idle --> Expired: idle window ran out
    Active --> Expired: 30 days since it was created
    Active --> Revoked: signed out, password changed, or admin action
    Expired --> Anonymous
    Revoked --> Anonymous
    note right of Revoked
        a password change revokes every session
        including the ones on devices we cannot see
    end note
A state diagram of a login session: active, idle with a sliding window, expired by idle or absolute timeout, and revoked by sign-out or a password change.

3 · Password reset — the other way to get a session

Draw this next to the login diagram, not in a separate document, because it grants exactly what login grants and is usually protected far less carefully.

The first response is the whole design in one arrow: 200 regardless of whether the account exists, sent before anything is looked up. Every other ordering leaks. The user-facing text has to match — "if that email is registered we sent a link" — and yes, it is slightly worse copy. It is also the only wording that does not turn this form into the enumeration endpoint your login page refused to be.

The token is single-use and short-lived, and the reason both matter is that reset links land in mailboxes, which get forwarded, backed up, and synced to devices nobody remembers owning.

The revocation arrow is the one most implementations forget. Someone resetting their password is very often someone who has already been compromised. If old sessions survive the reset, the reset accomplished nothing at all.

View the Mermaid source
sequenceDiagram
    autonumber
    participant User
    participant App as Web App
    participant Auth as Auth Service
    participant Mail as Email Service

    User->>App: I forgot my password, here is my email
    App->>Auth: start a reset
    Auth-->>App: 200 - the same answer whether or not it exists
    App->>User: if that email is registered we sent a link
    opt the account actually exists
        Auth->>Auth: mint a single use token, valid 30 minutes
        Auth->>Mail: send the reset link
        Mail->>User: reset link
        User->>App: open the link and choose a new password
        App->>Auth: redeem the token
        alt token unused and still inside the window
            Auth->>Auth: store the new hash, burn the token
            Auth->>Auth: revoke every existing session
            Auth-->>App: done, sign in again
        else token used, expired, or unknown
            Auth-->>App: 400 ask for a fresh link
        end
    end
A password reset sequence diagram with a non-enumerating response, a single-use time-limited token, and revocation of all existing sessions.

Read only the arrows pointing back at the user

Cover everything on the finished diagram except the arrows that go back to the user. Those are the only things an attacker can observe. Now read them as a list, ignoring which branch each came from.

If any two of them differ — different status, different wording, different obvious latency — for reasons the user is not entitled to know, you have found a disclosure. This is a two-minute exercise, it needs no tooling, and it catches the single most common real flaw in login systems, which is not weak hashing or missing HTTPS but a login page that will happily tell a stranger which of your users exist.

FAQ

Continue reading

Try text2diagram now

Open the tool
← Back to all tutorials