How Fluxer Implements Desktop Handoff for Seamless Authentication Between Instances

Fluxer implements desktop handoff using a cache-backed temporary code system where the source instance generates an 8-character code, stores it in cache for 5 minutes, and the target instance polls for completion to receive a one-time authentication token via Electron IPC.

Fluxer's desktop handoff feature enables users to start an authentication flow in one desktop instance and seamlessly finish it in another without re-entering credentials. This architecture relies on a three-layer system comprising the DesktopHandoffService for business logic, a generic ICacheService for temporary state storage, and Electron IPC handlers for cross-instance communication.

Generating the Handoff Code

The process begins in packages/api/src/auth/services/DesktopHandoffService.tsx where the initiateHandoff method creates a human-readable code and stores it in cache.

// packages/api/src/auth/services/DesktopHandoffService.tsx
export class DesktopHandoffService {
  async initiateHandoff(userAgent?: string): Promise<{code: string; expiresAt: Date}> {
    const code = generateHandoffCode();                     // 8-character code, formatted as XXXX-XXXX
    const normalizedCode = normalizeHandoffCode(code);      // removes hyphens/spaces, forces upper-case
    const handoffData: HandoffData = { createdAt: Date.now(), userAgent };
    await this.cacheService.set(
      `${HANDOFF_CODE_PREFIX}${normalizedCode}`,          // "desktop-handoff:{CODE}"
      handoffData,
      seconds('5 minutes')                               // expiration
    );
    return { code, expiresAt: new Date(Date.now() + ms('5 minutes')) };
  }
}

The generateHandoffCode function uses a restricted alphabet (ABCDEFGHJKMNPQRSTUVWXYZ23456789) to eliminate ambiguous characters like "I", "1", "O", and "0". The service stores metadata including createdAt and optional userAgent under the desktop-handoff: prefix with a 5-minute TTL.

Completing the Handoff on the Source Instance

Once the user confirms the handoff, the source instance calls completeHandoff to validate the code and prepare the authentication token for the target instance.

// packages/api/src/auth/services/DesktopHandoffService.tsx
async completeHandoff(code: string, token: string, userId: string): Promise<void> {
  const normalizedCode = normalizeHandoffCode(code);
  assertValidHandoffCode(normalizedCode);
  const handoffData = await this.cacheService.get<HandoffData>(`${HANDOFF_CODE_PREFIX}${normalizedCode}`);
  if (!handoffData) throw new InvalidHandoffCodeError();

  const remainingSeconds = Math.max(
    0,
    seconds('5 minutes') - Math.floor((Date.now() - handoffData.createdAt) / 1000),
  );
  if (remainingSeconds <= 0) throw new HandoffCodeExpiredError();

  // Store a one-time token that the target instance can later retrieve
  await this.cacheService.set(
    `${HANDOFF_TOKEN_PREFIX}${normalizedCode}`,        // "desktop-handoff-token:{CODE}"
    { token, userId },
    remainingSeconds,
  );
  await this.cacheService.delete(`${HANDOFF_CODE_PREFIX}${normalizedCode}`);
}

This method validates the code has not expired, stores the one-time token under desktop-handoff-token:{CODE}, and immediately deletes the pending code entry to prevent reuse.

Polling for Handoff Status

The target instance monitors progress via getHandoffStatus, which the AuthController exposes at GET /auth/handoff/:code/status.

// packages/api/src/auth/services/DesktopHandoffService.tsx
async getHandoffStatus(code: string) {
  const normalizedCode = normalizeHandoffCode(code);
  assertValidHandoffCode(normalizedCode);
  const tokenData = await this.cacheService.getAndDelete<HandoffTokenData>(`${HANDOFF_TOKEN_PREFIX}${normalizedCode}`);
  if (tokenData) {
    return { status: 'completed', token: tokenData.token, userId: tokenData.userId };
  }
  const handoffData = await this.cacheService.get<HandoffData>(`${HANDOFF_CODE_PREFIX}${normalizedCode}`);
  return handoffData ? { status: 'pending' } : { status: 'expired' };
}

The method uses getAndDelete to ensure the token can only be retrieved once, preventing replay attacks. It returns one of three statuses: pending, completed, or expired.

API Orchestration and HTTP Endpoints

The AuthRequestService in packages/api/src/auth/AuthRequestService.tsx bridges the handoff service with the broader authentication stack and session management.

// packages/api/src/auth/AuthRequestService.tsx
async completeHandoff({data, request}: AuthHandoffCompleteRequest): Promise<void> {
  const {token: handoffToken, userId} = await this.authService.createAdditionalAuthSessionFromToken({
    token: data.token,
    expectedUserId: data.user_id,
    request,
  });
  await this.desktopHandoffService.completeHandoff(data.code, handoffToken, userId);
}

Before calling DesktopHandoffService.completeHandoff, this service creates an additional authentication session from the source token using createAdditionalAuthSessionFromToken, which verifies that the supplied source token matches the expected user_id to prevent unauthorized handoffs.

The AuthController located at packages/api/src/auth/AuthController.tsx registers four HTTP endpoints:

  • POST /auth/handoff/initiate – Generates a new handoff code and returns it with expiration
  • POST /auth/handoff/complete – Source instance validates code and deposits the one-time token
  • GET /auth/handoff/:code/status – Target instance polls for completion status
  • DELETE /auth/handoff/:code – Cancels a pending handoff and cleans up cache entries

Desktop Client Integration via Electron IPC

In the Electron desktop app, the handoff code transfers between instances through IPC handlers defined in fluxer_desktop/src/main/IpcHandlers.tsx.

When a user selects "Switch Instance," the main process stores the code in a module-level variable:

// fluxer_desktop/src/main/IpcHandlers.tsx
let pendingDesktopHandoffCode: string | null = null;

ipcMain.handle('switch-instance-url', async (_event, options) => {
  // … window management logic …
  pendingDesktopHandoffCode = options.desktopHandoffCode ?? null;
  // … load the new instance URL …
});

The target instance retrieves this code through the preload script exposed to the renderer:

// fluxer_desktop/src/preload/index.tsx
consumeDesktopHandoffCode: (): Promise<string | null> =>
  ipcRenderer.invoke('consume-desktop-handoff-code'),

A typical React implementation in the target instance polls the API after retrieving the code:

// Target instance implementation
const handoffCode = await window.electron.consumeDesktopHandoffCode();

if (handoffCode) {
  let status = 'pending';
  while (status === 'pending') {
    const resp = await fetch(`/auth/handoff/${handoffCode}/status`);
    const data = await resp.json();
    status = data.status;
    
    if (status === 'completed') {
      localStorage.setItem('authToken', data.token);
      // Authentication complete - proceed as authenticated user
    }
    await new Promise(r => setTimeout(r, 1000));
  }
}

Security Architecture

Fluxer's desktop handoff implements several security layers to protect the authentication flow:

  • Code entropy: 8-character codes from a 32-character alphabet provide approximately 32^8 possible combinations while remaining human-readable
  • Single-use tokens: The getAndDelete operation in getHandoffStatus prevents token replay attacks
  • Time-bound validity: 5-minute expiration with explicit HandoffCodeExpiredError handling prevents stale code exploitation
  • User verification: createAdditionalAuthSessionFromToken validates that the source token matches the expected user_id before completing the handoff
  • Cleanup: Both the DELETE endpoint and automatic cache deletion in completeHandoff ensure no orphaned entries remain

Summary

Fluxer's desktop handoff implementation provides seamless cross-instance authentication through:

  • Short-lived codes: 8-character alphanumeric codes stored for 5 minutes in DesktopHandoffService under the desktop-handoff: prefix
  • Orchestrated flow: AuthRequestService coordinates between the handoff service and session management via createAdditionalAuthSessionFromToken
  • HTTP polling: Target instances poll /auth/handoff/:code/status until receiving status: "completed" with the one-time token
  • Electron IPC: IpcHandlers.tsx and preload/index.tsx enable secure code transfer between browser windows using switch-instance-url and consumeDesktopHandoffCode
  • Security: Single-use tokens, time limits, and user verification prevent unauthorized access while maintaining a frictionless user experience

Frequently Asked Questions

How long does a Fluxer desktop handoff code remain valid?

The handoff code expires after 5 minutes from creation. The DesktopHandoffService sets a TTL on the cache entry when calling initiateHandoff and validates the remaining time in completeHandoff, throwing HandoffCodeExpiredError if the window has passed.

Can the same handoff code be used multiple times?

No. Once the source instance calls completeHandoff, the service deletes the pending code entry using cacheService.delete. When the target instance retrieves the token via getHandoffStatus, the implementation uses getAndDelete to atomically retrieve and remove the token from cache, ensuring it cannot be reused.

What prevents unauthorized users from guessing a handoff code?

The code uses an 8-character string from a restricted alphabet of 32 characters (deliberately excluding ambiguous characters like I, 1, O, and 0), providing approximately 1.1 trillion possible combinations. Additionally, codes are single-use and expire after 5 minutes, making brute-force attacks computationally infeasible within the validity window.

How does the desktop client transfer the code between instances?

The Electron main process stores the code in a module-level variable via the switch-instance-url IPC handler when the user initiates a switch. When the target instance loads, it calls consumeDesktopHandoffCode through the preload script, which retrieves and immediately clears the pending code from the main process memory, ensuring secure one-time delivery.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →