Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
158737 stories
·
33 followers

AI vs. Real People—Helping Teams Avoid Information Overload | Havva Sevay

1 Share

Havva Sevay: AI vs. Real People—Helping Teams Avoid Information Overload

Read the full Show Notes and search through the world's largest audio library on Agile and Scrum directly on the Scrum Master Toolbox Podcast website: http://bit.ly/SMTP_ShowNotes.

 

"It's still a tool. It can make mistakes, it can hallucinate. People don't really question it—and that's the danger." - Havva Sevay

 

This week's coaching conversation tackles a challenge Havva—and many Scrum Masters—are living right now: AI vs. real people. For some, AI is a useful tool; for others, it's a magic oracle that solves everything and makes people replaceable. Havva sees the real risk in teams that accept AI's confident answers without double-checking, and in leaders who use AI to generate massive documents and dump them on teams as finished decisions. Vasco pushes the conversation into the practical: when a flood of AI-generated information, requirements, and tool changes lands on a busy team, how do you help them cope? Havva's answer is to step back and ask the human questions first—what is the epic? what does the stakeholder actually want? what do we really need right now? Then she pulls out a deliberately low-tech move: forget AI for one second. Her team uses the Eisenhower matrix manually to separate what's important now from what can wait. AI is a great tool—but the filtering of what matters is still human work.

 

Self-reflection Question: When AI floods your team with information and options, what is your practice for helping them separate what matters now from the noise?

 

[The Scrum Master Toolbox Podcast Recommends]

🔥In the ruthless world of fintech, success isn't just about innovation—it's about coaching!🔥

Angela thought she was just there to coach a team. But now, she's caught in the middle of a corporate espionage drama that could make or break the future of digital banking. Can she help the team regain their mojo and outwit their rivals, or will the competition crush their ambitions? As alliances shift and the pressure builds, one thing becomes clear: this isn't just about the product—it's about the people.

 

🚨 Will Angela's coaching be enough? Find out in Shift: From Product to People—the gripping story of high-stakes innovation and corporate intrigue.

 

Buy Now on Amazon

 

[The Scrum Master Toolbox Podcast Recommends]

 

About Havva Sevay

 

Havva is a people-focused organizational development expert with a Master's in Business Administration and certification as a Scrum Master. She empowers teams and leaders through agile methodologies, modern leadership, and a strong feedback culture, fostering psychological safety and collaboration. Passionate about HR initiatives, Havva shapes people strategies, enhances employee experience, and drives inclusive, high-performing workplaces built on trust and engagement.

 

You can link with Havva Sevay on LinkedIn.





Download audio: https://traffic.libsyn.com/secure/scrummastertoolbox/20260805_Havva_Sevay_W.mp3?dest-id=246429
Read the whole story
alvinashcraft
just a second ago
reply
Pennsylvania, USA
Share this story
Delete

Vanishing Culture #6: What We've Learned with Vida Vojić & Alice Bridgwood

1 Share

What does it mean to preserve culture in an age of disappearing websites, platform-controlled media, and fragile digital memories? In the final episode of our special six-part series on Vanishing Culture, Future Knowledge hosts Dave Hansen and Chris Freeland sit down with musician and series host Vida Vojić and producer Alice Bridgwood to reflect on the conversations, ideas, and lessons that emerged throughout the series.

Read Vanishing Culture for free at the Internet Archive or purchase in print: https://archive.org/details/vanishing-culture-2026





Download audio: https://media.transistor.fm/d96c23cc/8ac24b22.mp3
Read the whole story
alvinashcraft
just a second ago
reply
Pennsylvania, USA
Share this story
Delete

Real-Time Collaborative Editing in a React Block Editor Using Yjs

1 Share

Real-Time Collaborative Editing in a React Block Editor Using Yjs

TL;DR: Learn how to add real-time collaboration to a React Block Editor using Yjs and WebSockets. This guide walks through building a shared editing experience with live document synchronization, user presence, and remote cursors without implementing custom conflict-resolution logic. You’ll also explore provider selection, production considerations, and best practices for creating reliable multi-user editing experiences.

Most developers think collaborative editing is simple, until they try building it.

Allowing multiple users to edit the same document in real-time involves much more than syncing text. You need to:

  • Handle concurrent changes,
  • Keep document state consistent,
  • Show active users,
  • Display remote cursors, and
  • Recover from connection interruptions without losing data.

That’s why features that feel effortless in tools like Google Docs are surprisingly difficult to implement.

If you’re building documentation portals, product specifications, incident reports, contracts, or knowledge bases, real-time collaboration is often a user expectation today.

The good news is that you don’t have to solve these challenges from scratch. The Syncfusion® React Block Editor provides a collaboration module designed to integrate with Yjs, a CRDT-based framework that manages synchronization and conflict resolution automatically, letting you focus on the editing experience rather than the underlying complexity.

In this guide, we’ll build a real-time collaborative editor using React, TypeScript, Yjs, and WebSockets. We’ll cover document synchronization, user presence, remote cursors, choosing the right Yjs provider, and key considerations for production deployments.

When does real-time collaboration make sense?

Real-time collaboration is ideal when multiple users need to edit the same document simultaneously while seeing live updates, presence indicators, and remote cursors.

Common use cases include:

  • Product specifications and PRDs,
  • Legal drafts and contract reviews,
  • Incident reports and postmortems,
  • Launch plans and project documentation,
  • OKR and team planning documents.

However, this approach may not be the best fit for:

  • Large wiki-style document networks,
  • Fully offline mobile applications, and
  • Scenarios that require direct device-to-device CRDT synchronization without a server.

Understanding what “real-time collaboration” actually means

Before diving into the implementation, it’s useful to understand a few concepts that power the collaborative experience.

CRDTs: The foundation of conflict-free editing

At the heart of Yjs is a Conflict-Free Replicated Data Type (CRDT). A CRDT allows multiple users to edit shared content simultaneously while ensuring every participant eventually sees the same document state.

The practical benefit is simple: two users can make changes at the same time without accidentally overwriting one another’s work.

Awareness: Knowing who’s doing what

Collaboration isn’t just about synchronizing content. Users also need context about other participants.

Yjs uses an awareness layer to share temporary information such as:

  • Cursor positions,
  • Text selections,
  • User names, and
  • Avatar information.

Because awareness data is temporary, it disappears when a user disconnects and doesn’t become part of the document itself.

Shared document state

Actual document content lives inside a shared Y.Doc file. Unlike awareness data, modifications stored in the document persist and can be synchronized across reconnects and future editing sessions.

Together, the shared document and awareness layer create the experience users expect from modern collaborative applications.

Why real-time collaboration matters

Modern editors need to support more than rich text. Users expect teams to create, review, and update content together without worrying about version conflicts or overwritten changes.

The Syncfusion React Block Editor treats content as independent blocks, such as paragraphs, headings, tables, callouts, and code snippets, making it easier to edit and organize content while maintaining a smooth writing experience. When combined with Yjs, both content changes and document structure stay synchronized across connected users.

This enables two key capabilities:

  • Edit simultaneously without conflicts: Yjs automatically resolves concurrent changes, so that multiple users can work in the same document at the same time.
  • See collaboration in real-time: Remote cursors, selections, and user presence indicators make it easy to understand who is editing and where changes are happening.

What you get out of the box

The collaboration module builds on Yjs and works alongside existing Block Editor features such as slash commands, rich text formatting, drag-and-drop, mentions, labels, paste cleanup, and accessibility support.

Key capabilities include:

  • Real-time multi-user editing with automatic conflict resolution.
  • Live user presence, selections, and remote cursors.
  • Per-user undo and redo, allowing users to revert only their own changes.
  • Synchronized rich text formatting, including headings, lists, links, colors, alignment, and inline styles.
  • Mention and label synchronization with metadata preserved across all users.
  • Support for multiple Yjs providers, including y-websocket, y-webrtc, Hocuspocus, Liveblocks, PartyKit, and more.

Whether someone is updating text, reordering sections, or adding a new callout block, every connected user sees changes reflected in real-time.

How real-time collaboration works

Behind the scenes, collaboration relies on three components: a shared Yjs document, a provider that synchronizes connected clients, and the Block Editor that renders and updates content.

Yjs collaboration

The process is straightforward:

  1. Each client initializes a Y.Doc file and creates a shared Y.XmlFragment called blockeditor.
  2. A YjsAdapter provides the editor with access to the Yjs runtime and the shared fragment.
  3. A Yjs provider connects all clients to the same collaboration room.
  4. The React Block Editor renders content from the shared fragment and writes local changes back to it. Yjs then automatically synchronizes those changes across all connected clients.
  5. When awareness is enabled, cursor positions, selections, and user information are exchanged through a separate channel.

As a result, multiple users can edit the same document simultaneously while keeping content, structure, and collaboration state synchronized.

Choosing the right Yjs provider

The Yjs provider you choose determines how clients connect, synchronize data, and handle persistence. The best option depends on your deployment requirements, scalability needs, and whether you want to manage the infrastructure yourself.

Provider Transport Persistence Signaling/Auth Best for
y-webrtc Peer-to-peer None by default Public signaling by default; no auth Local development, demos, single-session prototypes
y-websocket WebSocket None by default You provide the server and auth Self-hosted staging and small production
Hocuspocus WebSocket Pluggable (Redis, Postgres) Token-based auth, extensions Scalable self-hosting with persistence and auth
Liveblocks Managed WebSocket Hosted Hosted auth, REST API Teams that want a fully managed backend with devtools
PartyKit Serverless on Cloudflare Optional Durable Object persistence Cloudflare auth Serverless deployments, prototypes with persistence
y-indexeddb None (local) Browser only None Offline persistence in a single browser

For production environments:

  • y-websocket offers maximum control,
  • Hocuspocus adds persistence and authentication capabilities, and
  • Liveblocks provides a managed collaboration infrastructure with minimal operational overhead.

Build it yourself or start with existing collaboration support?

When planning collaborative editing, it’s easy to underestimate how much work exists beyond the editor UI. Synchronization, conflict handling, user presence, offline recovery, and persistence often require significantly more effort than the editing experience itself.

The table below compares some of the key responsibilities involved in building a collaborative editor from scratch versus using the Syncfusion React Block Editor with Yjs.

Feature Build yourself Syncfusion + Yjs
CRDT Design and implement CRDT, merge strategies, and conflict resolution from scratch. Uses Yjs’s production-tested CRDT with automatic conflict-free synchronization.
Real-time synchronization Build custom synchronization, diffing, patch generation, and nested content updates. Automatic incremental synchronization for content, properties, and document structure.
Presence & collaboration Implement cursors, selections, user awareness, and presence using custom protocols. Built-in real-time cursors, selections, user presence, and awareness through Yjs.
Provider & offline sync Build custom WebSocket messaging, offline persistence, and multi-device synchronization. Built-in WebSocket providers, offline persistence, and seamless multi-device synchronization.
Production readiness Requires validation for scalability, offline support, conflict recovery, and performance. Enterprise-ready with proven scalability, offline synchronization, and automatic recovery.

Building a collaborative editor involves much more than rendering content. By combining the Syncfusion React Block Editor with Yjs, you can focus on creating user-facing features while relying on a proven foundation for synchronization, presence, and shared editing experiences.

Building a real-time collaborative React Block Editor using Yjs

Let’s build a collaborative editor using Vite, React, TypeScript, Yjs, and the Block Editor.

Step 1: Create the project

Start by scaffolding a new React TypeScript application and installing the required packages:

npm create vite@latest collab-editor -- --template react-ts    
cd collab-editor    
npm install @syncfusion/ej2-react-blockeditor yjs y-websocket

Step 2: Configure the editor theme

Next, replace the contents of the src/index.css file with the following imports:

@import "@syncfusion/ej2-base/styles/tailwind3.css"; 
@import "@syncfusion/ej2-inputs/styles/tailwind3.css"; 
@import "@syncfusion/ej2-popups/styles/tailwind3.css";
@import "@syncfusion/ej2-buttons/styles/tailwind3.css"; 
@import "@syncfusion/ej2-splitbuttons/styles/tailwind3.css";
@import "@syncfusion/ej2-navigations/styles/tailwind3.css";
@import "@syncfusion/ej2-dropdowns/styles/tailwind3.css";
@import "@syncfusion/ej2-react-blockeditor/styles/tailwind3.css";

If your application already uses a different design system, replace tailwind3 with themes such as fluent, material, bootstrap5, material-dark, or bootstrap5-dark to match the rest of your UI.

Step 3: Create a collaboration hook

To keep the editor integration clean, create a dedicated collaboration hook. This hook manages the Y.Doc, shared Y.XmlFragment, Yjs provider, and the collaboration adapter throughout the component’s lifecycle, and automatically cleans up resources when the component is unmounted.

Refer to the code in the src/hooks/useCollaboration.ts. file

Step 4: Connect the editor

With the collaboration hook in place, the final step is to connect it to the Block Editor.

The following src/App.tsx file brings everything together by integrating the collaboration hook, rendering the editor, and displaying collaboration details such as connection status and active users. Once configured, multiple clients connected to the same room can edit the document in real-time.

Refer to the code in the src/App.tsx file and run the application.

Step 5: Run a local WebSocket server

To synchronize changes across multiple browser sessions, you’ll need a y-websocket server running locally.

First, install the WebSocket server:

npm install -g @y/websocket-server

Then, start the server in a separate terminal:

npx y-websocket

By default, the server runs on ws://localhost:1234. The connection URL configured in the App.tsx file already points to this address, so the editor can connect and begin synchronizing changes immediately.

Step 6: Test the real-time collaboration experience

With both npm run dev and npx y-websocket running, it’s time to verify that collaboration is working as expected.

  1. Open the application in two browser windows at http://localhost:5173.
  2. Make sure both windows display the same initial content and show the Connected status.
  3. In the first window, edit any paragraph. The changes should appear in the second window almost instantly.
  4. In the second window, place the cursor in a different location. The first window should display the user’s presence, including their remote cursor and participant information.
  5. Refresh both windows and reconnect. If your chosen provider supports persistence, the shared document state will be restored automatically.
Real-time collaborative editing in React Block Editor using Yjs
Real-time collaborative editing in React Block Editor using Yjs

At this point, you have a working collaborative editor with real-time synchronization, user presence, and shared editing capabilities.

Real-world scenario: Managing a product launch document

Consider a product team preparing for a major release. The product manager maintains the launch plan, the engineering lead documents technical risks, the design team updates messaging and assets, and the legal team reviews compliance requirements. Instead of passing documents back and forth, everyone contributes to the same document simultaneously.

Using the React Block Editor with Yjs, the team built a React application where each section, such as headings, paragraphs, tables, callouts, and lists, is represented as an editable block within a shared document. The editor connects to a y-websocket server, allowing changes to synchronize instantly across all participants.

With collaboration awareness enabled, team members can see active users, remote cursors, and selection highlights in real-time. This makes it easy to identify who is working on which section and reduces duplicate effort during reviews and updates.

The outcome

  • Faster document creation: Multiple contributors can draft content simultaneously instead of waiting for handoffs.
  • Fewer editing conflicts: Changes are synchronized automatically, and collaboration-aware undo/redo ensures users only revert their own edits.
  • Reusable collaboration pattern: The same approach can be applied to other team scenarios, including incident reports, quarterly planning documents, and contract reviews.

For teams that regularly collaborate on shared content, real-time editing helps reduce coordination overhead and keeps everyone working from a single source of truth.

Best practices for real-time collaborative editing

A few implementation choices can make a significant difference as your collaborative editor grows from a prototype to a production application:

  • Choose the right provider for your environment: Use y-webrtc or PartyKit for development and experimentation, y-websocket or Hocuspocus for self-hosted deployments, and Liveblocks if you prefer a managed service.
  • Use consistent room identifiers: Each room ID should uniquely map to a single document to ensure users join the correct collaboration session.
  • Integrate with your identity system: Usernames, avatars, and colors should come from the same identity source used throughout your application for a consistent experience.
  • Consider offline support: Pairing Yjs with y-indexeddb helps preserve changes locally and improves resilience during temporary connectivity issues.
  • Test real-world collaboration scenarios: Open multiple browser windows and simulate network delays to validate synchronization, cursor accuracy, undo/redo behavior, and reconnection handling.
  • Clean up resources properly: Always dispose of the provider and Y.Doc when the component unmounts to avoid lingering connections and stale awareness states.

Common issues and how to fix them

Even with a straightforward setup, a few common configuration issues can prevent collaboration features from working as expected.

Issue Possible cause Solution
Cursors don’t appear, and remote changes aren’t visible Awareness is disabled, or the selected provider doesn’t support awareness. Enable enableAwareness and verify that your provider supports awareness features.
Remote usernames are missing on cursors User information isn’t provided in the user’s configuration. Populate the user field for all participants, including the local user.
Changes sync locally but not across clients Clients are connected to different rooms or the provider is disconnected. Ensure all clients use the same room ID and verify the connection in the browser’s network panel.
Adapter or runtime imports fail The installed package version exposes APIs differently. Check the package documentation and installed type definitions. The collaboration adapter should provide yRuntime and yXmlFragment.
WebSocket connections disconnect frequently The server endpoint is unreachable or reconnect settings aren’t configured. Validate the WebSocket URL, enable provider retry options, and display connection status in the UI.

For more advanced troubleshooting and configuration details, refer to the official React Block Editor collaboration documentation.

Preparing for production

A collaborative editor that works locally isn’t always ready for real-world usage. Before deploying, consider the following:

  • Use secure WebSocket connections (wss://): Most browsers block unencrypted WebSocket connections in production environments.
  • Protect document access: Authenticate users and validate access to collaboration rooms using signed tokens or your existing identity system.
  • Add server-side rate limiting: This prevents a faulty or malicious client from overwhelming the collaboration channel.
  • Persist shared documents: Without persistence, recent edits can be lost if the server restarts. Solutions such as Hocuspocus with database storage or Yjs persistence adapters can help retain document state.
  • Capture operational telemetry: Track connection, disconnection, and error events to simplify troubleshooting.
  • Monitor connection health: A connection status indicator in the UI helps users understand when synchronization issues occur.
  • Load test early: Simulate multiple concurrent users to validate synchronization performance, cursor latency, and conflict resolution behavior.

Performance tips

As collaboration scales, a few optimizations can improve the user experience:

  • Disable awareness when needed: Presence updates are lightweight, but they still consume bandwidth. Consider disabling them in low-bandwidth environments.
  • Lazy-load the editor: In frameworks such as Next.js, dynamically loading the editor can improve initial page load times.
  • Optimize bundle size: Import only the components and modules you use to reduce the amount of JavaScript shipped to the browser.

Accessibility considerations

Collaboration features introduce accessibility requirements beyond the editor itself.

  • Announce presence changes: Use ARIA live regions so screen readers can notify users when collaborators join or leave.
  • Respect reduced-motion preferences: Apply prefers-reduced-motion to presence indicators and collaboration-related animations.
  • Maintain focus stability: Awareness updates should never unexpectedly move keyboard focus within the editor.

While the Block Editor follows WCAG 2.1 accessibility patterns, collaboration-specific experiences should also be reviewed as part of your application’s overall accessibility strategy.

Browser compatibility

Collaborative editing relies on web technologies that are widely supported in modern browsers:

  • y-websocket and Hocuspocus require WebSocket support, which is universal in modern browsers.
  • y-webrtc relies on WebRTC support available in current Chromium, Firefox, and Safari browsers.
  • y-indexeddb uses IndexedDB for local persistence and works across modern browsers that support progressive web applications.

Build Powerful Content Editing Experiences in React

From rich text editing and document formatting to media embedding and collaborative content creation, Syncfusion React Block Editor equips developers with everything needed to deliver modern, intuitive content authoring experiences.

Explore React Block Editor Features

Frequently Asked Questions

How does the React Block Editor handle simultaneous edits to the same block?

The React Block Editor uses Yjs CRDTs to synchronize changes. Edits to different blocks merge automatically, while concurrent edits at the same position are resolved deterministically. Undo and redo actions affect only the local user’s changes without impacting other collaborators.

Can I use the React Block Editor collaboration features without a backend?

Yes. For development and prototypes, you can use providers that require little or no backend infrastructure. For staging and production environments, a WebSocket-based provider is recommended for reliable synchronization and persistence.

How do I show who is currently editing a document?

Enable the enableAwareness property in the React Block Editor’s collaborationSettings, provide user details such as names and avatar colors, and set the local user’s ID. The editor automatically displays remote cursors and selections, while active user information can be retrieved from the provider’s awareness state.

Can I disable collaboration for certain documents?

Yes. Collaboration is optional. If you don’t configure collaborationSettings, the editor functions as a standard single-user editor.

Does collaboration affect performance?

Collaboration features are designed to be lightweight, but they do introduce additional network traffic. If user presence isn’t needed, disabling enableAwareness can help reduce overhead.

Can I switch providers later?

Yes. You can start with a provider such as y-webrtc during development and move to y-websocket or a managed service later. The shared Y.Doc and collaboration setup remain the same.

GitHub reference

For more details, refer to the example for real-time collaborative editing in React Block Editor using Yjs on the GitHub repository.

Bring real-time collaboration to your next React project

Building real-time collaboration means solving challenges such as synchronization, conflict resolution, and user presence. By combining the Syncfusion React Block Editor with Yjs, you can add these capabilities without building the collaboration layer from scratch.

Start with a local y-websocket server, connect multiple clients, and see how edits, cursors, and document updates stay synchronized in real-time. As your application grows, you can extend the same foundation with authentication, persistence, and production-scale infrastructure.

Ready to explore collaborative editing in your own application? Check out the resources below:

Read the whole story
alvinashcraft
20 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Passing custom parameters through OpenIddict's client authorization request

1 Share

In my passthrough authentication post, the login endpoint set a provider value on AuthenticationProperties so the OpenIddict server would know whether to challenge GitHub or ADFS:

app.MapGet("login/{provider}", (string provider) =>
    Results.Challenge(new AuthenticationProperties
    {
        RedirectUri = "/",
        Items = { ["provider"] = provider }
    }, [OpenIddictClientAspNetCoreDefaults.AuthenticationScheme]));

Run that as-is and the server never sees it. Items round-trips through your own app's correlation cookie — it was never meant to become part of the outgoing OAuth2 request.

Why this doesn't just work

AuthenticationProperties.Items is an ASP.NET Core concept. It's how the authentication middleware remembers things like the redirect URI across the round trip to an external provider and back. The OpenIddict client builds the actual /connect/authorize request from a completely different object — an OpenIddictRequest — and nothing copies one into the other automatically. If you want something in Items to show up as a query parameter on the real authorization request, you have to move it there yourself.

That's what OpenIddictClientEvents.PrepareAuthorizationRequestContext is for: it fires right before the client builds the outgoing authorization request, and it's the one place where you still have both the AuthenticationProperties from the challenge and the OpenIddictRequest that's about to be sent.

Registering the handler

This is still client-side config, in the same AddClient() block from the passthrough post:

builder.Services.AddOpenIddict()
    .AddClient(options =>
    {
        // ... AllowAuthorizationCodeFlow, registrations, etc. from before ...

        options.AddEventHandler<OpenIddictClientEvents.PrepareAuthorizationRequestContext>(builder =>
            builder.UseInlineHandler(context =>
            {
                var properties = context.Transaction.GetProperty<AuthenticationProperties>(
                    typeof(AuthenticationProperties).FullName!);

                if (properties is not null &&
                    properties.Items.TryGetValue("provider", out var provider) &&
                    !string.IsNullOrEmpty(provider))
                {
                    context.Request["provider"] = provider;
                }

                return default;
            }));
    });

context.Transaction is the OpenIddict client's per-request state. GetProperty<T> is how the ASP.NET Core integration exposes the original AuthenticationProperties from the challenge inside that transaction. From there it's a plain lookup: read provider out of Items, and set it directly on context.RequestOpenIddictRequest behaves like a dictionary, so this becomes an actual provider=github (or adfs) parameter on the /connect/authorize URL.

Remark: this only forwards the parameter on the way out. If your OpenIddict server redirects back through the client with its own extra parameters, that's a different context (OpenIddictClientEvents.PrepareTokenRequestContext or a validation-side handler) — don't assume one handler covers both directions.

Using the built-in OpenIdConnect handler instead

Not every client uses OpenIddict.Client — plenty just use the built-in Microsoft.AspNetCore.Authentication.OpenIdConnect package against the OpenIddict server, since it's still a standard OIDC endpoint. The equivalent hook there is OpenIdConnectEvents.OnRedirectToIdentityProvider, which fires just before the outgoing request and hands you both the AuthenticationProperties and the OpenIdConnectMessage being built:

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = "OpenIddict";
})
.AddCookie()
.AddOpenIdConnect("OpenIddict", options =>
{
    options.Authority = "https://auth.contoso.com/";
    options.ClientId = "client_app";
    options.ClientSecret = builder.Configuration["OpenIddict:ClientSecret"];
    options.ResponseType = "code";
    options.SaveTokens = true;
    options.Scope.Add("email");
    options.Scope.Add("profile");
    options.Scope.Add("offline_access");

    options.Events.OnRedirectToIdentityProvider = context =>
    {
        if (context.Properties!.Items.TryGetValue("provider", out var provider) &&
            !string.IsNullOrEmpty(provider))
        {
            context.ProtocolMessage.Parameters["provider"] = provider;
        }

        return Task.CompletedTask;
    };
});

The login endpoint doesn't change at all — it's still challenging with AuthenticationProperties.Items["provider"], just against the "OpenIddict" scheme name instead of OpenIddictClientAspNetCoreDefaults.AuthenticationScheme.

It's really the same idea with different names:

  OpenIddict.Client Built-in OpenIdConnect
Hook PrepareAuthorizationRequestContext OnRedirectToIdentityProvider Reading
Reading the properties context.Transaction.GetProperty context.Properties directly
Outgoing request object OpenIddictRequest OpenIdConnectMessage
Remark: pick one package for the client, not both. They solve the same problem, and mixing them just for this one feature isn't worth the added complexity.

Reading it back on the server

This is the half that was already in the passthrough post's Authorize action — worth restating so the two ends of the wire are next to each other. It's identical no matter which client package sent the request:

var provider = Request.Query["provider"].ToString() switch
{
    "github" => "GitHub",
    "adfs" => "ADFS",
    _ => throw new InvalidOperationException("Unknown provider.")
};

Nothing OpenIddict-specific there — by the time it reaches the server, provider is just a regular query string value.

Tip: if Request.Query["provider"] still comes back empty after wiring up the handler, check the handler actually got registered on the same AddClient() options as the registration you're challenging. It's easy to add it to the wrong builder when there's more than one client registration in play.

That's it!

More information

Read the whole story
alvinashcraft
27 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Web Weekly #197

1 Share

Guten Tag! Guten Tag! 👋

Are you ready for the closedby attribute? Will you measure elements with containertiming? And do you use CSS infinity?

Turn on the Web Weekly tune and find some answers below. Enjoy!

::: song by="Paweł" title="GUTS 'METIS'" youtube="8RK6NKTKYUg" This one was recommended to me by Apple Music while driving back home last week. The moment I heard it for the first time I put it on loop and it was playing for the rest of the journey (1hr). Really positive vibe. :::

Do you want to share your favorite song with the Web Weekly community? Hit reply; there are five more songs left in the queue.


Let's open this issue by looking at two developer surveys worth your time.

The State of Devs 2026

First, the State of Devs survey is open for participation. And if you have a moment, you should fill it out. I sound like a broken record, but things are changing. There's a lot of uncertainty and, frankly, occasionally I'm navigating a full-blown identity crisis. I'd love to see how the majority and all of you feel.

A graph from the State of CSS survey showing that anchor positioning is the favorite new CSS feature.

And second, the State of CSS survey results are out! 🎉 As always it's a great read to discover new features and get a feeling for how "cutting edge" everybody is out there.

And to everyone who mentioned me in the resources section, thank you! I'm very humbled to be on this list of great people in the web dev community. 🥹


::: highlight sponsored

Building an AI Workflow UI in React? Start With JointJS

The JointJS AI Workflow Builder: a node-based canvas wiring Text Input, Markdown File, AI Agent, Search Reddit, and Formatted Output nodes into a flow.

Most teams building AI workflow UIs start with a lightweight node graph library. Quick to a demo, but you hit a ceiling once the product gets real: UX gaps and slowdowns on large diagrams.

JointJS for React starts where that ceiling is. On UX, you get a full diagramming toolkit: a drag and drop canvas with editable nodes, validation, undo/redo, keyboard shortcuts, snaplines, and accessibility. On performance, rendering is optimized to stay smooth as pipelines grow to hundreds of nodes.

The JointJS AI Workflow Builder template gives you ~90% of the app, full source included. Wire up your execution backend and ship. Already trusted in production by teams at UiPath, DocuSign, and Bloomberg.

<a class="btn btn__small" href="https://www.jointjs.com/ai-workflow-builders?utm_source=webweekly&utm_medium=sponsored-ad">Start building</a>

<small>Web Weekly is open for sponsorships. When you want to reach 6k developers, <a href="https://webweekly.email/advertise">you know what to do</a>!</small> :::

Web Weekly Housekeeping

This week's summer bag of karma points goes to Zerde, who started to support Web Weekly financially. This brings the supporter count to the amazing number of 54.

After subtracting the cost of sending and hosting, Web Weekly now makes around $150 per month. Thank you all for supporting this newsletter! ❤️

So, if you enjoy Web Weekly, give back with a small monthly donation on Patreon or GitHub Sponsors. It really makes a difference for me in these hard times of AI slop and low-effort web creation.

Something that made me smile this week

A green button labeled "Button".

Guess what you'll find at clickclickclick.click. I can't help it; I just love people who put out silly things on silly domains. ❤️

<a class="btn btn__small" href="https://clickclickclick.click">Click!</a>

No code

Browser Performance Timing APIs

img elementtiming=product-image ...  section containertiming=product-summary   ... /section

Harry explained the new containertiming attribute, which is currently running as a Chrome Origin trial. If you're not knee-deep into perf topics, the post includes more than one rabbit hole to jump into. For example: Have you used the elementtiming attribute to get render information of image or text nodes? Or, do you use the User Timing API to mark certain render/performance milestones?

<a class="btn btn__small" href="https://csswizardry.com/2026/07/meaasuring-component-performance-with-the-container-timing-api/">Measure!</a>

Promise.all but for good old objects

const {   shape,   color,   mass, } = await Promise.allKeyed({   shape: getShape(),   color: getColor(),   mass: getMass(), });

The "Await dictionary of Promises" ECMAScript proposal moved to stage three so that we'll finally be able to await objects. Can't wait!

<a class="btn btn__small" href="https://github.com/tc39/proposal-await-dictionary">Wait for the properties</a>

On standards, processes, and specifications

IMO ponyfills are just userland libraries with better marketing.

Lea makes a strong case for the usefulness of polyfills. If you want to learn more about the current state of polyfills, ponyfills, and prollyfills (I hadn't heard that one before), this post includes tons of background info.

<a class="btn btn__small" href="https://lea.verou.me/blog/2026/polyfills/">Fill the platform gaps</a>

CSS Route and Navigation Matching

/* Going from home to about? Slide left! */ @navigation (from: --home) and (to: --about) {   @view-transition {     navigation: auto;     types: slide-all-to-left;   } }

Bramus is working on new ways to make view transitions easier to handle in an MPA scenario. This is in its very early stages, but look at this funky CSS.

Bramus is looking for feedback!

<a class="btn btn__small" href="https://www.bram.us/2026/07/30/styling-the-navigation-declarative-route-and-navigation-matching-in-css/">Peek into the possible future</a>

The wonderful weird web – Dustin's website

A classical operating system dialog showing different programs: blog, click, globe, etc.

Well, that's what I call yet another fancy personal website. 👏

<a class="btn btn__small" href="https://dustin.works/">Get to know Dustin</a>

CSS infinity

.tippy-top-of-stacking-context {   z-index: calc(infinity) }

How could you stack on top of an element with the highest possible z-index (2147483647)? Correct! You use CSS infinity to get on top of the highest stack. Adam lists some more creative infinity use cases.

<a class="btn btn__small" href="https://nerdy.dev/css-infinity-use-cases">Stack on top!</a>

Follow the OS font size

.button {   font-size: calc(16px * env(preferred-text-scale)); }

Back in Web Weekly 182, I included the new text-scale meta element which enables sites to react to OS font size changes. I didn't realize that there's more to this topic.

Apparently, there's also the preferred-text-scale CSS env variable. Josh was involved in the spec and shares how a particular BBC problem led to this new font size approach.

<a class="btn btn__small" href="https://www.joshtumath.uk/posts/2026-07-02-lets-fix-the-webs-text-size/">Respect the OS</a>

Scale text automatically

p {   text-fit: grow per-line-all; }

Speaking of text scaling, apparently Chrome 150 shipped the new text-fit property. There are no real MDN docs, and the spec would be the best we've got if it weren't for Krijn, who documented all the options with visual examples.

<a class="btn btn__small" href="https://krijnhoetmer.nl/log/2026/07/playing-with-text-fit">Scale automatically</a>

Measure SPA navigations

const observer = new PerformanceObserver(console.log); observer.observe({ type: "soft-navigation", buffered: true });

With Chrome 151, soft navigations entered the mainstream. If you haven't heard the term, a soft navigation is anything that:

  • is initiated by a user action.
  • results in a visible URL change to the user.
  • results in a visible paint.

So, we're talking about a new way to monitor and measure classical SPA navigations.

<a class="btn btn__small" href="https://developer.chrome.com/docs/web-platform/soft-navigations">Measure the navigation</a>

Side note: if you're using the web-vitals library, soft navigations are now supported with v6.

Random MDN – closedby

HTML snippet showing  on a  element.

From the unlimited MDN knowledge archive...

We're not entirely there yet in terms of browser support, but the new closedby property ships in Chromium, Firefox and is already included in Safari TP, so it's about time to look into it.

<a class="btn btn__small" href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/closedBy">Close it with anything</a>

TIL recap – use Intl to format and localize units!

console.log(   new Intl.NumberFormat('fr-FR', {     style: 'unit',     unit: 'kilobyte',     unitDisplay: 'long',   }).format(123456) ); // "123 456 kilooctets"

Here's a quick party trick: did you know that you can use Intl to format numeric values with their units?

<a class="btn btn__small" href="https://www.stefanjudis.com/today-i-learned/intl-can-localize-units-too/">Format with style</a>

::: highlight info Find more short web development learnings in my "Today I learned" section. :::

New on the baseline

Widely available: .something {     animation-timing-function: linear(0, 0.25 25% 75%, 1);   } Newly available: const german = new Intl.Locale("DE-de");   console.log(german.getTimeZones());   // Array [ "Europe/Berlin", "Europe/Busingen" ]

The linear() easing function made it into Baseline widely available territory.

And since Firefox 153, all recent browsers support new info methods like getTimeZones, getTextInfo, or getHourCycles on Intl.Locale objects.

Three valuable projects to have a look at

Thought of the week

This is by far my biggest concern with the "new world" we're in. As Koshy says, it's never been so easy to pretend without understanding what's going on.

::: highlight quote

[AI] makes it easy to simulate competence without building competence. :::

Did you learn something from this issue?

❤️ If so, join 54 other Web Weekly supporters and give back with a small monthly donation on Patreon or GitHub Sponsors.

This is all, friends!

Loved this email? Hated this email? I want to hear about it!

If you think something needs improvement or something sparked some joy, reply to this email because I want to know more!


And with that, take care of yourself - mentally, physically, and emotionally.

I'll see you next week! 👋

Read the whole story
alvinashcraft
46 seconds ago
reply
Pennsylvania, USA
Share this story
Delete

Explorers, exploiters, and the myth of the 100x engineer​​​​‌‍​‍​‍‌‍‌​‍‌‍‍‌‌‍‌‌‍‍‌‌‍‍​‍​‍​‍‍​‍​‍‌​‌‍​‌‌‍‍‌‍‍‌‌‌​‌‍‌​‍‍‌‍‍‌‌‍​‍​‍​‍​​‍​‍‌‍‍​‌​‍‌‍‌‌‌‍‌‍​‍​‍​‍‍​‍​‍‌‍‍​‌‌​‌‌​‌​​‌​​‍‍​‍​‍‌‍​‌‍‌‌​​‍‍‌​‌‌​‌‍​‌‌‍​‌‍‍‌‍‌‌‍‌‍‌‌‌​‍‌‍‌‍‌‍​‌‍‌‌​‍‍‌‍​‌‍​‍‌‍‍‌‌‍‍‌‌​‌‍‌‌‌‍‍‌‌​​‍‌‍‌‌‌‍‌​‌‍‍‌‌‌​​‍‌‍‌‌‍‌‍‌​‌‍‌‌​‌‌​​‌​‍‌‍‌‌‌​‌‍‌‌‌‍‍‌‌​‌‍​‌‌‌​‌‍‍‌‌‍‌‍‍​‍‌‍‍‌‌‍‌​​‌​‌​‌‍‌​​​​‌‍‌‍​‍​‌‌‍‌‍‌‍‌‌​‍‌​‍​‌‍‌‍​‌​‌​​‍‌​‌​​‌​‌‍​‍​​​‍‌​‍‌​​‌‌‍‌​‌‍​‍​‍‌‌‍​‌‌‍​‍‌‍​​‌‌‌‍‌​​‌​‌‍‌‌‌‍​​‌‌‌‍‌​​‍‌​‍‌​‍‌‌​‌‍‌‌​​‌‍‌‌​‌‌‍​‍‌‍​‌‍‌‍‌‌‌​​‌‍‌​‌‌​​‍‌​​‌‍​‌‌‌​‌‍‍​​‌‌‌​‌‍‍‌‌‌​‌‍​‌‍‌‌​‌‍​‍‌‍​‌‌​‌‍‌‌‌‌‌‌‌​‍‌‍​​‌‌‍‍​‌‌​‌‌​‌​​‌​​‍‌‌​​‌​​‌​‍‌‌​​‍‌​‌‍​‍‌‌​​‍‌​‌‍‌‍​‌‍‌‌​​‍‍‌​‌‌​‌‍​‌‌‍​‌‍‍‌‍‌‌‍‌‍‌‌‌​‍‌‍‌‍‌‍​‌‍‌‌​‍‍‌‍​‌‍​‍‌‍‌‍‍‌‌‍‌​​‌​‌​‌‍‌​​​​‌‍‌‍​‍​‌‌‍‌‍‌‍‌‌​‍‌​‍​‌‍‌‍​‌​‌​​‍‌​‌​​‌​‌‍​‍​​​‍‌​‍‌​​‌‌‍‌​‌‍​‍​‍‌‌‍​‌‌‍​‍‌‍​​‌‌‌‍‌​​‌​‌‍‌‌‌‍​​‌‌‌‍‌​​‍‌​‍‌​‍‌‍‌‌​‌‍‌‌​​‌‍‌‌

1 Share
The “find the special ones and promote their traits” approach isn’t the best or only way to drive AI adoption and productivity on an engineering team. ​​​​‌‍​‍​‍‌‍‌​‍‌‍‍‌‌‍‌‌‍‍‌‌‍‍​‍​‍​‍‍​‍​‍‌​‌‍​‌‌‍‍‌‍‍‌‌‌​‌‍‌​‍‍‌‍‍‌‌‍​‍​‍​‍​​‍​‍‌‍‍​‌​‍‌‍‌‌‌‍‌‍​‍​‍​‍‍​‍​‍‌‍‍​‌‌​‌‌​‌​​‌​​‍‍​‍​‍‌‍​‌‍‌‌​​‍‍‌​‌‌​‌‍​‌‌‍​‌‍‍‌‍‌‌‍‌‍‌‌‌​‍‌‍‌‍‌‍​‌‍‌‌​‍‍‌‍​‌‍​‍‌‍‍‌‌‍‍‌‌​‌‍‌‌‌‍‍‌‌​​‍‌‍‌‌‌‍‌​‌‍‍‌‌‌​​‍‌‍‌‌‍‌‍‌​‌‍‌‌​‌‌​​‌​‍‌‍‌‌‌​‌‍‌‌‌‍‍‌‌​‌‍​‌‌‌​‌‍‍‌‌‍‌‍‍​‍‌‍‍‌‌‍‌​​‌​‌​‌‍‌​​​​‌‍‌‍​‍​‌‌‍‌‍‌‍‌‌​‍‌​‍​‌‍‌‍​‌​‌​​‍‌​‌​​‌​‌‍​‍​​​‍‌​‍‌​​‌‌‍‌​‌‍​‍​‍‌‌‍​‌‌‍​‍‌‍​​‌‌‌‍‌​​‌​‌‍‌‌‌‍​​‌‌‌‍‌​​‍‌​‍‌​‍‌‌​‌‍‌‌​​‌‍‌‌​‌‌‍​‍‌‍​‌‍‌‍‌‌‌​​‌‍‌​‌‌​​‍‌​​‌‍​‌‌‌​‌‍‍​​‌‌‍‌‌‌‍​‌‍​‌‍‌‌‌​‍‌​​‌‌​​‌‍​‍‌‍​‌‌​‌‍‌‌‌‌‌‌‌​‍‌‍​​‌‌‍‍​‌‌​‌‌​‌​​‌​​‍‌‌​​‌​​‌​‍‌‌​​‍‌​‌‍​‍‌‌​​‍‌​‌‍‌‍​‌‍‌‌​​‍‍‌​‌‌​‌‍​‌‌‍​‌‍‍‌‍‌‌‍‌‍‌‌‌​‍‌‍‌‍‌‍​‌‍‌‌​‍‍‌‍​‌‍​‍‌‍‌‍‍‌‌‍‌​​‌​‌​‌‍‌​​​​‌‍‌‍​‍​‌‌‍‌‍‌‍‌‌​‍‌​‍​‌‍‌‍​‌​‌​​‍‌​‌​​‌​‌‍​‍​​​‍‌​‍‌​​‌‌‍‌​‌‍​‍​‍‌‌‍​‌‌‍​‍‌‍​​‌‌‌‍‌​​‌​‌‍‌‌‌‍​​‌‌‌‍‌​​‍‌​‍‌​‍‌‍‌‌​‌‍‌‌​​‌‍‌‌​‌‌‍​‍‌‍​‌‍‌‍‌‌‌​​‌‍‌​‌‌​​‍‌‍‌​​‌‍​‌‌‌​‌‍‍​​‌‌‍‌‌‌‍​‌‍​‌‍‌‌‌​‍‌​​‌‌​​‍‌‍‌​​‌‍‌‌‌​‍‌​‌​​‌‍‌‌‌‍​‌‌​‌‍‍‌‌‌‍‌‍‌‌​‌‌​​‌‌‌‌‍​‍‌‍​‌‍‍‌‌​‌‍‍​‌‍‌‌‌‍‌​​‍​‍‌‌
Read the whole story
alvinashcraft
1 hour ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories