How OpenWork's Deep-Link Bridge Handles OAuth and Sign-In Flows
OpenWork's deep-link bridge is a custom event-based system that transfers OAuth callbacks and authentication URLs from the native Electron shell to the web UI using openwork:deep-link-native events and a window.__OPENWORK__ storage mechanism.
The OpenWork deep-link bridge solves a critical cross-platform challenge: how to capture custom protocol URLs (like openwork://) on desktop and forward them to the browser-based application code. This article explores the architecture, source code implementation, and practical usage of this bridge for OAuth and sign-in workflows.
Architecture Overview
The bridge operates across three layers:
- Native Electron layer – captures OS-level deep links and emits
openwork:deep-link-nativeevents - Bridge layer (
deep-link-bridge.ts) – normalizes URLs, stores them onwindow.__OPENWORK__, and dispatchesopenwork:deep-linkevents to the web UI - Application layer – consumes deep links via
subscribeDesktopDeepLinks()anddrainPendingDeepLinks()to complete authentication flows
The custom protocol scheme openwork is defined in readDesktopDistributionInfo() within apps/app/src/app/lib/desktop.ts (lines 21-33), enabling URLs like openwork://auth?code=abc123 for OAuth callbacks.
The Bridge Implementation: deep-link-bridge.ts
The core bridge logic lives in apps/app/src/app/lib/deep-link-bridge.ts. It defines two custom event types and provides functions to push and drain pending URLs.
Event Constants and Types
// apps/app/src/app/lib/deep-link-bridge.ts
export const deepLinkBridgeEvent = "openwork:deep-link";
export const nativeDeepLinkEvent = "openwork:deep-link-native";
export type DeepLinkBridgeDetail = { urls: string[] };
pushPendingDeepLinks() – Store and Broadcast URLs
When the native side receives a deep link, this function normalizes the URLs, appends them to window.__OPENWORK__.deepLinks, and fires a custom event:
// apps/app/src/app/lib/deep-link-bridge.ts
export function pushPendingDeepLinks(
target: Window,
urls: readonly string[]
): string[] {
const normalized = urls.flatMap(u => u.trim() ? [u.trim()] : []);
if (!normalized.length) return [];
target.__OPENWORK__ ??= {};
const pending = target.__OPENWORK__.deepLinks ?? [];
target.__OPENWORK__.deepLinks = [...pending, ...normalized];
target.dispatchEvent(
new CustomEvent<DeepLinkBridgeDetail>(deepLinkBridgeEvent, {
detail: { urls: normalized },
})
);
return normalized;
}
drainPendingDeepLinks() – Retrieve and Clear
Components call this to fetch any URLs that arrived before their event listener was registered:
// apps/app/src/app/lib/deep-link-bridge.ts
export function drainPendingDeepLinks(target: Window): string[] {
const pending = target.__OPENWORK__?.deepLinks ?? [];
if (target.__OPENWORK__) {
target.__OPENWORK__.deepLinks = [];
}
return [...pending];
}
Starting the Bridge: startup-deep-links.ts
The apps/app/src/react-app/shell/startup-deep-links.ts module initializes the bridge once per application lifecycle. It handles two environments: standard web browsers and the Electron desktop runtime.
// apps/app/src/react-app/shell/startup-deep-links.ts
import { pushPendingDeepLinks } from "../../app/lib/deep-link-bridge";
import { subscribeDesktopDeepLinks } from "../../app/lib/desktop";
import { isDesktopRuntime } from "../../app/utils";
let started = false;
export function startDeepLinkBridge(): void {
if (typeof window === "undefined" || started) return;
started = true;
// Standard web: treat current URL as a deep link
if (!isDesktopRuntime()) {
pushPendingDeepLinks(window, [window.location.href]);
return;
}
// Desktop: subscribe to native deep-link events
void (async () => {
try {
await subscribeDesktopDeepLinks((urls) => {
pushPendingDeepLinks(window, urls);
});
} catch {
// Silent failure on startup prevents blocking app launch
}
})();
}
Key behaviors:
- Non-desktop environments immediately push the current
window.location.hrefas a deep link - Desktop environments register an async listener via
subscribeDesktopDeepLinks()that forwards native events to the bridge
Desktop Integration: subscribeDesktopDeepLinks()
The subscribeDesktopDeepLinks() function in apps/app/src/app/lib/desktop.ts (lines 497-514) bridges the Electron preload script's event system to the web application's event bus. It listens for openwork:deep-link-native events dispatched by the native layer when the OS handles a custom protocol URL.
This function enables the following flow:
- User completes OAuth flow in external browser
- Redirect to
openwork://auth?code=...triggers OS protocol handler - Electron main process captures URL and forwards to preload script
- Preload emits
openwork:deep-link-nativewith the URL array subscribeDesktopDeepLinks()callback invokespushPendingDeepLinks()- Web UI receives
openwork:deep-linkevent and processes the authentication code
Consuming Deep Links in Application Code
React components or authentication services consume the bridge through event listeners and the drain function:
import { useEffect } from 'react';
import {
deepLinkBridgeEvent,
DeepLinkBridgeDetail,
drainPendingDeepLinks,
} from './app/lib/deep-link-bridge';
function useOAuthDeepLink() {
useEffect(() => {
const handler = (e: CustomEvent<DeepLinkBridgeDetail>) => {
e.detail.urls.forEach(url => {
// Match OAuth callback: openwork://auth?code=<token>
const match = url.match(/^openwork:\/\/auth\?code=(.+)$/);
if (match) {
const authCode = decodeURIComponent(match[1]);
completeOAuthSignIn(authCode); // Your auth logic
}
});
};
// Subscribe to future deep links
window.addEventListener(
deepLinkBridgeEvent,
handler as EventListener
);
// Process any links that arrived before mount
drainPendingDeepLinks(window).forEach(url => {
handler(new CustomEvent(deepLinkBridgeEvent, {
detail: { urls: [url] }
}));
});
return () => {
window.removeEventListener(
deepLinkBridgeEvent,
handler as EventListener
);
};
}, []);
}
OAuth and Sign-In Flow Integration
The deep-link bridge enables several authentication patterns:
| Flow | URL Pattern | Handler Action |
|---|---|---|
| OAuth authorization code | openwork://auth?code=...&state=... |
Exchange code for tokens, validate state |
| Magic link sign-in | openwork://login?token=... |
Validate token, establish session |
| Email verification | openwork://verify?email=...&code=... |
Confirm email address |
| Password reset | openwork://reset?token=... |
Redirect to reset form with token |
All flows share the same underlying mechanism: native capture → bridge normalization → web consumption.
Summary
- Deep-link bridge (
deep-link-bridge.ts) providespushPendingDeepLinks()anddrainPendingDeepLinks()functions withwindow.__OPENWORK__storage - Two event types coordinate across layers:
openwork:deep-link-native(Electron → web) andopenwork:deep-link(bridge → application) startDeepLinkBridge()instartup-deep-links.tsinitializes the system, adapting to desktop or browser environmentssubscribeDesktopDeepLinks()indesktop.tsconnects the native Electron event system to the bridge- The
openworkprotocol scheme enables custom URL handling for OAuth callbacks and authentication flows
Frequently Asked Questions
How does the OpenWork deep-link bridge differ from standard browser deep links?
Standard web deep links use standard https:// URLs that the browser handles directly. The OpenWork deep-link bridge specifically handles custom protocol URLs (openwork://) that require native OS integration through Electron. The bridge translates these native events into browser-compatible CustomEvent objects that the React application can consume.
What happens if a deep link arrives before the web UI is ready?
The bridge stores all incoming URLs in window.__OPENWORK__.deepLinks. When your component mounts, calling drainPendingDeepLinks(window) retrieves and clears this array. This pattern ensures no authentication callbacks are lost during application startup or navigation delays.
Can the deep-link bridge be used outside of OAuth flows?
Yes. Any feature that benefits from custom protocol URLs can use the bridge—email verification, password reset, referral codes, or content sharing. The DeepLinkBridgeDetail type accepts any URL array, and application code determines how to parse and route each URL pattern.
Is the deep-link bridge available in the web-only version of OpenWork?
The bridge functions in both environments, but behavior differs. In non-desktop builds, startDeepLinkBridge() immediately pushes window.location.href as a deep link. This allows shared routing logic between desktop and web without conditional branching throughout the codebase.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →