Skip to content

JoyID: authWithPopup fails on Brave/Firefox — authWithRedirect not accessible via @joyid/ckb #361

@toastmanAu

Description

@toastmanAu

Problem

The JoyID connect flow in @joyid/ckb uses authWithPopup() from @joyid/common, which relies on a WebSocket relay to pass the passkey result from phone to desktop.

This relay only works reliably in Chrome/Chromium. On Brave and Firefox:

  • The WebSocket relay is blocked or throttled by the browser
  • The desktop never receives the signed passkey result
  • Users must scan the QR 2–4 times before it sometimes succeeds
  • Often times out entirely, leaving users stuck

This affects any dapp using CCC's JoyID connector on desktop Brave/Firefox — which is a significant portion of the CKB developer/user community.

Root Cause

Chrome has Google's own FIDO2 cross-device transport (CTAP2) infrastructure built in. Brave and Firefox route through JoyID's relay server, which these browsers throttle or block.

authWithRedirect() and authCallback() already exist in @joyid/common and work in every browser (full-page redirect to app.joy.id, no WebSocket relay). However, they are not accessible through the CCC JoyID connector — CCC uses authWithPopup() directly.

Workaround

We implemented a custom connector that wraps @joyid/common directly with browser detection:

// Brave/Firefox: authWithRedirect() — full page nav to app.joy.id, no relay needed
// Chrome/mobile: authWithPopup() — existing behaviour unchanged
if (typeof navigator.brave !== 'undefined' || /Firefox/.test(navigator.userAgent)) {
  common.authWithRedirect(request); // redirects to app.joy.id
} else {
  return common.authWithPopup(request);
}

Result: Brave users go from 2–4 QR scan attempts + frequent timeouts → 1 Face ID tap, done.

Note: navigator.brave.isBrave is a Promise (async) — must use typeof navigator.brave !== 'undefined' for synchronous detection.

Suggested Fix

The CCC JoyID connector could detect the browser and fall back to authWithRedirect() on Brave/Firefox. Alternatively, expose a preferRedirect option.

We also filed nervina-labs/joyid-sdk-js#58 requesting that authWithRedirect, authCallback, and isRedirectFromJoyID be re-exported from @joyid/ckb directly — a one-line fix on their end.

Browser Scorecard (tested on wyltekindustries.com)

  • Chrome ✅ popup, 1 shot
  • Brave ✅ redirect flow (custom connector), 1 shot
  • Chromium ✅ redirect flow, 1 shot
  • Safari iOS ✅ 1 tap Face ID
  • Firefox ⚠ not supported (CTAP2 hybrid not available in Firefox — we show a clear message)

Impact

Any dapp using CCC + JoyID on desktop Brave/Firefox is affected. Brave has significant adoption in the Web3/crypto community.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions