An architecture diagram shows who talks to whom. It cannot show in which order, or who waits for whom, and for many problems that order is the whole story. Sign-in flows are the classic case: the same five messages in a different order are a security bug.
This guide teaches sequence diagram notation on one flow most engineers meet sooner or later: a single-page app that signs a user in with the OAuth 2.0 authorization code flow and PKCE, then calls an API.
What a sequence diagram shows
Time runs downward. Each participant gets a lifeline, a box with a dashed line below it, and each message is a horizontal arrow from sender to receiver. Reading top to bottom gives you the order of events; reading across tells you who is involved in each step.
The notation, from the UML 2.5.1 specification:
| Element | Drawn as | Means |
|---|---|---|
| Lifeline | A box with a dashed line down | A system, service or component taking part |
| Actor | A stick figure | A person or an external role |
| Synchronous message | Solid line, filled arrowhead | A call; the sender waits for the answer |
| Asynchronous message | Solid line, open arrowhead | A message the sender does not wait for |
| Reply | Dashed line | The answer to an earlier message |
| Combined fragment | A box with an operator: alt, opt, loop, par |
A part that runs conditionally, repeatedly or in parallel |
| Note | A box with a folded corner | A comment, such as a check one participant makes |
The flow: authorization code with PKCE
A single-page app is a public client: everything it ships to the browser can be read, so it cannot keep a client secret. PKCE, defined in RFC 7636, protects the authorization code anyway: the app proves that whoever exchanges the code is the same instance that started the flow. The OAuth 2.0 security best current practice, RFC 9700, requires PKCE for public clients, recommends it for all others, and says clients should not use the implicit grant.
The steps:
- The user selects Sign in.
- The app creates a code verifier and a challenge. The
code_verifieris a random string of 43 to 128 characters. Thecode_challengeisBASE64URL(SHA256(code_verifier)), the S256 method. The app also stores a randomstate. - The app sends the browser to the authorization endpoint with the challenge:
GET /authorize?response_type=code
&client_id=orders-spa
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&scope=orders.read
&state=af0ifjsldkj
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256 HTTP/1.1
Host: auth.example.com
- The authorization server signs the user in and asks for consent.
- It redirects back to the
redirect_uriwith a short-livedcodeand the samestate. - The app checks
stateagainst the value it stored. - The app exchanges the code at the token endpoint, sending the verifier it kept:
POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&client_id=orders-spa&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
- The authorization server hashes the verifier and compares the result with the challenge from step 3. If they match, it returns an access token, and a refresh token if it issues one.
- The app calls the API with
Authorization: Bearer <access token>. - The API validates the token, for example its signature, issuer, audience, expiry and scope, and answers.
The verifier and challenge above are the example values from RFC 7636, so you can check the S256 calculation yourself.
The diagram
Diagram contents
- User
- Browser app
- Authorization server
- API
- [access token expired]
- 1 Sign in
- 2 GET /authorize + code_challenge, state
- 3 Sign-in and consent page
- 4 Credentials, consent
- 5 Redirect: code, state
- 6 POST /token + code, code_verifier
- 7 access_token (+ refresh_token)
- 8 GET /orders, Bearer access_token
- 9 200 OK
- 10 GET /orders, expired token
- 11 401 invalid_token
- 12 POST /token + refresh_token
- 13 New access and refresh tokens
- 14 Retry with the new token
How to read it:
- Four participants in one row: the user as an actor, then lifelines for the browser app, the authorization server and the API. Every message is a horizontal arrow at its own height, numbered in order.
- Messages 2 to 7 are the authorization code flow. The notes show the two checks that make it safe: the app compares
stateafter the redirect, and the authorization server compares the hashed verifier with the challenge. - Messages 8 and 9 are the API call. Replies are dashed with open arrowheads.
- The
optfragment covers the case where the access token has expired: a 401, a refresh, and a retry.
Show the failure path, not only the happy path
Most sequence diagrams stop at "200 OK". The interesting bugs live in the branches, so draw at least the one that happens every day. Use alt when the diagram shows several mutually exclusive branches, each with a guard, and opt for one part that runs only when its guard is true. The refresh here is an opt: it happens only when the access token has expired.
The refresh branch has rules of its own. For browser apps, refresh tokens are usually bearer tokens, so RFC 9700 and RFC 10017, the best current practice for browser-based apps published in August 2026, require the authorization server to rotate them on every use or bind them to the client, and to limit their lifetime. Message 13 returns a new refresh token for that reason.
RFC 10017 also ranks the architectures for browser apps by security. A backend-for-frontend that keeps tokens on the server is the strongest; a browser app acting as the OAuth client, as in this diagram, is the simplest and the most exposed to malicious JavaScript. If you choose the browser pattern, the diagram is a good place to state why.
Common mistakes in sequence diagrams
- Too many lifelines. Past six or seven, labels collide and readers lose the thread. Split the flow, or group internal services behind one lifeline.
- Unlabeled replies. "Response" says nothing. Write the status or the payload: "302 with code", "401 invalid_token".
- Mixed levels of detail. HTTP parameters on one arrow and "user is happy" on the next confuse both audiences. Pick a level and keep it.
- Only the happy path. Timeouts, retries and expired credentials are where diagrams pay for themselves.
- Every parameter. Show the ones the reader must check, such as
state,code_challengeandcode_verifier, and leave the rest to the API reference.
When to use one, and when not
Use a sequence diagram for protocols, handshakes, retries, timeouts, races and incident timelines: anything where order and waiting matter. Use something else for static structure (an architecture or C4 diagram), for event fan-out across many consumers (an event-driven architecture diagram), and for security reviews of where data crosses trust boundaries (a data flow diagram for threat modeling).
Build it in Archboard
- Sign in with Google or GitHub and create a diagram.
- From the Sequence pack, add an Actor for the user and three Lifeline nodes for the browser app, the authorization server and the API, in one row with the same height.
- Draw each message as a straight edge between two lifelines, top to bottom, with a numbered label. Make replies dashed.
- Add a Fragment around messages 10 to 14, set its operator to
optand its label to "[access token expired]". - Add UML pack Note nodes for the checks:
state, the hashed verifier and token validation.
The example uses 5 diagram nodes, within the Free plan. Archboard's own MCP server signs AI apps in with this flow, the authorization code grant with PKCE (S256); see how to create architecture diagrams with AI agents.
FAQ
Is PKCE only for mobile apps? No. It was designed for native apps, but RFC 9700 requires it for all public clients, including single-page apps, and recommends it for confidential clients too.
Should a single-page app use the implicit flow? No. RFC 9700 says clients should not use the implicit grant. Use the authorization code flow with PKCE.
Is OAuth 2.1 a finished standard? Not at the time of writing (October 2026). It is still an IETF Internet-Draft that consolidates OAuth 2.0 and its security practices, including PKCE.
What is the difference between alt and opt?
alt holds two or more mutually exclusive branches, each with a guard. opt holds one part that runs only when its guard is true.
How many messages fit on one sequence diagram? As many as stay readable at the size people view it, usually 15 to 20. Split longer flows into several diagrams, one per phase.