You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
OAuth and OpenID Connect are easy to use and hard to picture. Who redirects whom? Which token goes where? What does the API actually check?
To address that, we've added a new section to the Duende docs: Protocols: Identity Visualized. It brings illustrated walkthroughs covering OAuth 2.x, OpenID Connect, DPoP, PAR, SAML and passkeys.
Each page shows the flow as an interactive diagram you can step through. Every step comes with:
the HTTP message on the wire
what to look at, and why it matters
a link to the section of the spec it comes from
We also say where it gets subtle: why revoking a token isn't the same as logging out, what PKCE does and doesn't protect, and why a valid token isn't the same as permission.
The diagrams also appear in our product docs where they help. Next to the IdentityServer configuration for PAR, DPoP or SAML, you can see what happens on the wire.
Reviewer focus
Structure, code, ...
@khalidabuhakmeh@ProgrammerAL Can you try running things locally, and provide feedback on structure when running this, look through code, ...? Very open to making changes here.
OIDC nonce: we say the RP checks the nonce only if it sent one (Core 3.1.3.7). Should we instead tell readers to always send one, or is "optional in the code flow" the right message? /protocols/openid-connect/openid-connect/, step 5
Refresh token reuse: after a stolen refresh token is detected, we say the client needs a new authorization grant, not that the user must sign in again. Is that the right framing? /protocols/oauth-2x-core/refresh-tokens/, steps 5 and 7
SAML signing: we say a signed Response can protect its assertions (Errata 05, E26). Should we recommend signing the assertion itself, since that's what IdentityServer does by default and many SPs expect? /protocols/saml-ws-fed/saml-sso/, step 4 and Notes
Introspection: we say active: false covers revoked, expired and unknown tokens, so it isn't a revocation flag. Is that clear enough, and is the example API's policy (require aud, exp and scope) good advice? /protocols/tokens/introspection/, steps 3 and 5, and /protocols/tokens/token-revocation/, steps 5 and 7
PKCE: we say a matching verifier ties the token request to the authorization request, but doesn't authenticate a public client. Is that the right line to draw for learners? /protocols/oauth-2x-core/pkce/, step 6
Scopes: there's no consent step, because consent isn't a protocol mechanism. Do learners need one anyway, since IdentityServer has a consent screen? /protocols/oauth-2x-core/scopes/, step 2 and Notes
Failure paths: these are numbered steps titled "If ..." or "Alternative: ...". Does that read clearly, or would you rather see failures outside the numbered flow?
For example /protocols/oauth-2x-core/client-credentials/, steps 5 to 7, and /protocols/oauth-2x-core/scopes/, steps 6 and 7
In general, do the page titles work for you? You can see them all on /protocols/.
There are a few drafts in this PR as well, let's keep those out of scope for now.
Twenty illustrated, step-by-step explainers of OAuth 2.x, OpenID Connect,
DPoP, PAR, SAML and passkeys under /protocols/, grouped with _meta.yml.
- Flow, Cite and Sources components, with a spec registry for citations
- Monthly spec check script and workflow (schedule disabled for now)
- README authoring guidance for protocol pages
- Home page section and resources chip
- Embedded flows on product pages where they add a picture
- Glossary and terminology links to the protocol pages
- Five pages renamed .md to .mdx for embeds (URLs unchanged)
- Key management: move the discovery flow after the options example, with a client-side lead-in
- API scopes: move the scopes flow after the scope authorization section
- Clients: add a lead-in sentence before the PKCE flow
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
The purported offline validation can pass despite registry drift, and the token walkthrough incorrectly retains discarded tokens in its displayed holdings.
Adds “Protocols: Identity Visualized,” an illustrated learning section with interactive protocol walkthroughs, specification citations, and links to existing product documentation.
Changes:
Add protocol explainers, specification registries, and validated flow data.
Introduce reusable walkthrough and citation components, integrated with navigation and the homepage.
Embed walkthroughs in product documentation, repair internal links, and add specification-monitoring commands and a manual workflow.
This pull request requires changes. Unresolved issues affect offline validation, token-holdings state, accessible message routes, keyboard flow selection, multi-audience token guidance, and logout/revocation guidance. A homepage grammar and style nit also remains.
- Workflow: run the offline registry check with --local so drift fails the job
- Flow holdings: an entry starting with '-' removes an item, so replaced
tokens (refresh rotation, JWKS cache, revoked token, ended OP session)
no longer stay listed
- Home page: fix the protocols heading grammar and Title Case
- Rename 'The Four OAuth Roles' to 'The OAuth Roles' and explain why the
diagram has three lanes
maartenba
added
preview
Spins up a preview of the Pull Request for review
and removed
preview
Spins up a preview of the Pull Request for review
labels
Oct 28, 2026
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Unresolved accessibility and keyboard-navigation defects hide arrow direction from screen-reader users at wide layouts and can cause arrow keys to advance a less-visible diagram.
At wide diagram sizes, flow.css hides .fl-path with display: none, removing the sender/receiver description from the accessibility tree. The step button and live announcement include only the title, so screen-reader users cannot reliably determine the arrow's direction. Include from and to in the accessible step name so this information remains available at every layout size.
Update visibility tracking for accurate keyboard diagram targeting
astro/src/components/protocols/flow.ts:44
The default observer threshold of 0 leaves stored intersection ratios stale while diagrams remain visible. On pages with two embeds, such as the passkeys page, Left/Right can therefore advance a less-visible diagram and scroll back to it. Observe intermediate thresholds or measure current visibility when choosing the keyboard target.
Distinguish redirect delivery from client execution environment
Authorization-code exchange keeps tokens out of the authorization redirect, but it does not necessarily keep them out of the browser. The example is a public client, which can be a browser-based SPA; in that case the token response is received in the browser. Distinguish redirect delivery from where the client runs so readers do not infer that code flow alone gives them backend-only token storage.
Describe token recipients as roles, not a single recipient
A token does not necessarily have exactly one recipient. Access tokens can name multiple resource servers in aud, as the resource-indicators walkthrough explains, and the UserInfo endpoint mentioned below is also a possible recipient. Describe these as recipient roles rather than a single-recipient protocol requirement.
Avoid claiming ID tokens cannot contain a scope claim
OpenID Connect Core section 2 permits additional ID-token claims, so an ID token can contain a custom scope claim. Its absence is not guaranteed and should not be taught as a distinction between token types. State that Core does not define scope for ID tokens, while keeping the audience and token-type checks as the reasons an API must reject them.
Qualify blanket statement about refresh tokens after logout
This blanket statement contradicts step 6, which correctly explains that back-channel logout recommends revoking session-associated refresh tokens issued without offline_access. Qualify the statement so readers do not conclude that refresh tokens always survive logout.
Clarify conditional access-token revocation in introspection example
Step 2 revoked refresh token R7..., but this request introspects access token AT1..., whose revocation is conditional in step 3. Showing active: false without stating that condition can suggest that introspection always detects refresh-token revocation as access-token invalidation. State that this example assumes the AS also revoked AT1, which could otherwise remain active even without caching.
- Flow: include sender and receiver in each step's accessible name and
live announcement, since the path text is hidden at wide sizes
- Flow: observe several visibility thresholds so arrow keys pick the
diagram that is most in view
- Token types and PKCE: the code exchange keeps tokens out of redirect
URLs, not out of the browser for browser-based apps
- Token types: describe recipients as roles, and say Core defines no
scope claim for ID tokens
- Logout: qualify that back-channel logout may revoke refresh tokens
- Revocation: state that the introspection example assumes AT1 was revoked
Addressed the 7 previously missed issues from the second Copilot review in e9310fb:
Accessible step names: each step button and the live announcement now include the sender and receiver (for example "App → Browser · through the browser"), so the direction is available when the path text is hidden at wide sizes.
Keyboard targeting: the IntersectionObserver now observes several thresholds, so visibility ratios stay current and Left/Right goes to the diagram most in view.
Token delivery (token-types step 2, PKCE step 7): now says the code exchange keeps tokens out of redirect URLs, and that a browser-based app still receives them in the browser.
Token recipients (token-types step 6): "exactly one recipient" is now "meant for a different kind of recipient".
ID token scope (token-types Notes): now says OpenID Connect Core defines no scope claim for ID tokens.
Refresh tokens after logout (oidc-logout Notes): qualified with the back-channel logout rule for tokens issued without offline_access.
Introspection example (token-revocation step 5): now states that it assumes the AS also revoked AT1, and that otherwise AT1 stays active until it expires.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed to evaluate unpublished concerns about signature-verification byte consistency and required relying-party origin checks in the passkey walkthrough.
The copy on some of these pages is "vague" and unsatisfying from a reader's perspective. The first paragraph should answer what folks are looking for, or at least give them a strong grounding in the topic. Many of these opening paragraphs are coy or bury the lead.
For example:
This page helps you pick a grant. After reading it you will know which one fits a user-facing app, a background service, or a device with limited input, and which two to avoid.
"Which two to avoid?! I'm scared now!"
Visualizations
General Feedback
The visualizations are good, but when you click the Details ↓ button, each section should link back to the visualization, which may need another design pass as well.
styling issues on mobile aspect
Now Holding
This section is really confusing to me as it only shows on specific steps. Is the swimlane holding it, am I holding it, is it on the entire request lifecycle?
Build With Duende
This is odd "markety" stuff in a documentation site that doesn't need it. Rename or remove these sections entirely.
Don't Confuse With
This section really jars me. It's like telling our readers to "not think about the pink elephants". I'd rather keep these pages focused on educating readers about the topic; if there is confusion, maybe add an internal link to disambiguate or clarify.
Conclusion
There still needs another pass of polish I believe. I think I would start with one page, refine one of these then apply it across all the pages. It's a good start but one more pass would fix a lot of these issues.
Based on review feedback that the copy was vague and read like marketing.
- Open each page with the answer, not a teaser
- Topic-specific headings (Why PKCE Exists, How PKCE Works, PKCE Step by Step)
- Requirement levels move into the step they apply to
- Replace Notes, Use It When, Don't Confuse With and Build with Duende with
named sections and See Also
- Remove contrast constructions and review language
- PKCE: recommend it for every authorization code flow
- Replace example Basic credentials with a placeholder
- Remove the holds data from flow steps
- Remove the Now holding line
- Add a Back to the diagram button under each step section
- Use Starlight arrow icons in the diagram buttons and embed link
- Find the step section by headings ending in Step by Step
- Fix the control row and card width on narrow screens
- Landing page: state what the section covers and where to start, and drop
the New to this? card
- README: describe the page structure, heading names and tone
Every page now opens with the answer, with no teasers. Choose the Right OAuth Flow, for example, opens with the list of which grant to use and which ones to avoid.
Headings name the topic, for example "Why PKCE Exists", "How PKCE Works" and "PKCE Step by Step".
Requirement levels now sit in the step they apply to, instead of in a Notes section.
I removed the "X, not Y" constructions and other review language across all pages.
Sections
Build with Duende is gone. Its links are in See Also, and product facts such as RequirePkce are in the text where they apply.
Don't Confuse With is gone. Where a distinction matters, it's one sentence with an inline link.
Visualizations
Now holding is removed.
Each step section has a "Back to the diagram" button that selects that step and scrolls back up.
The diagram buttons use the same Starlight arrow icons as the home page.
On narrow screens, the control row no longer has a half-drawn background, and the step card uses the full width.
- The diagram card renders backticked text in step summaries as code
- Mark parameter, claim and error names in all step summaries with backticks,
as the page prose does
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Inline flows render incorrectly because schema transformations are discarded, specification retrieval failures can falsely pass the workflow, and passkey guidance misstates required backup-eligibility checks.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
The passkey guidance incorrectly makes a required backup-eligibility consistency check conditional on application policy, and the monthly workflow can report success despite specification-fetch failures.
- Flow: use the parsed flow, so string actors are normalized before rendering
- Monthly spec check: exit with an error when a spec can't be fetched
- Passkey sign-in: separate the always-required BS check from the
policy-dependent BE and BS checks
The PKCE page recommends PKCE for every authorization code flow, so the
examples should show it.
- OAuth Roles: code_challenge in the authorization request, code_verifier in
the token request, and the AS check in step 6
- Scopes: code_challenge and code_verifier in steps 1 and 3
- DPoP: code_verifier in the public client's token request
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed for unpublished findings involving an undefined buffer in the passkey signature-verification example and missing search-topic metadata for the new Protocols section.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Human assessment is needed to evaluate fragment-navigation synchronization and scrolling gaps, along with missing accessible semantics on the focusable stepper host.
No open issues 🎉
1 file not reviewed
astro/package-lock.json: Generated file
Review effort: Balanced
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
previewSpins up a preview of the Pull Request for review
3 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What are we adding?
OAuth and OpenID Connect are easy to use and hard to picture. Who redirects whom? Which token goes where? What does the API actually check?
To address that, we've added a new section to the Duende docs: Protocols: Identity Visualized. It brings illustrated walkthroughs covering OAuth 2.x, OpenID Connect, DPoP, PAR, SAML and passkeys.
Each page shows the flow as an interactive diagram you can step through. Every step comes with:
We also say where it gets subtle: why revoking a token isn't the same as logging out, what PKCE does and doesn't protect, and why a valid token isn't the same as permission.
The diagrams also appear in our product docs where they help. Next to the IdentityServer configuration for PAR, DPoP or SAML, you can see what happens on the wire.
Reviewer focus
Structure, code, ...
@khalidabuhakmeh @ProgrammerAL Can you try running things locally, and provide feedback on structure when running this, look through code, ...? Very open to making changes here.
Content
@josephdecock @wcabus (and @khalidabuhakmeh @ProgrammerAL if you like), please review added content (mostly in
/protocols. I'd value your take on accuracy and on whether they teach well.A few that deserve some attention:
/protocols/openid-connect/openid-connect/, step 5/protocols/oauth-2x-core/refresh-tokens/, steps 5 and 7/protocols/saml-ws-fed/saml-sso/, step 4 and Notesactive: falsecovers revoked, expired and unknown tokens, so it isn't a revocation flag. Is that clear enough, and is the example API's policy (requireaud,expandscope) good advice?/protocols/tokens/introspection/, steps 3 and 5, and/protocols/tokens/token-revocation/, steps 5 and 7/protocols/oauth-2x-core/pkce/, step 6/protocols/oauth-2x-core/scopes/, step 2 and NotesFor example
/protocols/oauth-2x-core/client-credentials/, steps 5 to 7, and/protocols/oauth-2x-core/scopes/, steps 6 and 7/protocols/.There are a few drafts in this PR as well, let's keep those out of scope for now.