Sequence Diagram Example: The OAuth 2.0 Authorization Code Flow with PKCE

Learn sequence diagram notation on a flow most engineers meet: a browser app signing a user in with the OAuth 2.0 authorization code flow and PKCE, then calling an API.

· Founder & developer

Published

Sequence Diagram Example: The OAuth 2.0 Authorization Code Flow with PKCE

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:

  1. The user selects Sign in.
  2. The app creates a code verifier and a challenge. The code_verifier is a random string of 43 to 128 characters. The code_challenge is BASE64URL(SHA256(code_verifier)), the S256 method. The app also stores a random state.
  3. 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
  1. The authorization server signs the user in and asks for consent.
  2. It redirects back to the redirect_uri with a short-lived code and the same state.
  3. The app checks state against the value it stored.
  4. 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
  1. 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.
  2. The app calls the API with Authorization: Bearer <access token>.
  3. 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

Sequence diagram with four lifelines: user, browser app, authorization server and API. Fourteen numbered messages run top to bottom, replies are dashed, notes show the state and verifier checks, and an opt fragment covers the refresh after a 401 response.

9 components · 14 connections

Open in Archboard
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
The authorization code flow with PKCE as a UML sequence diagram: a browser app gets a code, exchanges it with the code verifier for tokens, calls an API, and refreshes an expired access token inside an opt fragment.

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 state after 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 opt fragment 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_challenge and code_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

  1. Sign in with Google or GitHub and create a diagram.
  2. 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.
  3. Draw each message as a straight edge between two lifelines, top to bottom, with a numbered label. Make replies dashed.
  4. Add a Fragment around messages 10 to 14, set its operator to opt and its label to "[access token expired]".
  5. 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.

Start free — one seat, no credit card.

Related posts

← Back to blog

Open a canvas in a minute

Sign in with Google or GitHub. Free for a single seat. Upgrade when the team joins.