Skip to main content
September 22, 2026
Question

Firefox: related-origin passkeys silently fall back to the browser (FetcherError in related-origins-fetcher)

  • September 22, 2026
  • 3 replies
  • 11 views

Setup

Firefox 155.0.1 on Linux, 1Password in the browser 8.12.32.33 (current AMO build). Firefox on any OS is affected. Chrome is not.

Symptom

On a site that uses WebAuthn related origins, 1Password takes over navigator.credentials.get() and then hands it back to Firefox without showing anything. The user gets Firefox's native prompt; on Linux that is only "Touch your security key". Our case: page origin https://app.example.com, rpId auth.example.com, https://auth.example.com/.well-known/webauthn served with 200, application/json, access-control-allow-origin: *, and https://app.example.com listed in origins.

Background console:

[Webauthn] Failed to core.webAuthnRPValidate: ⛔ Core error code: {"type":"FetcherError"}
[Webauthn] Failed to _handleGetCredential: bad-rp-id
[Webauthn] Failed to _handleGetCredential while unlocked: bad-rp-id

No Related-origins fetch failed warning is logged.

Cause

background/webauthn/related-origins-fetcher.ts, around lines 75 to 87. The fetcher wraps the content-script fetch in a DNR session rule:

await chrome.declarativeNetRequest.updateSessionRules({ addRules: [rule] });
try { return await fetchViaContentScript(url); }
finally { await chrome.declarativeNetRequest.updateSessionRules({ removeRuleIds: [id] }).catch(warn); }

In Firefox, the MV2 chrome.* namespace is callback-only and returns undefined for these calls. The await on the add call passes, the fetch succeeds, then the finally block does .catch on undefined:

TypeError: can't access property "catch", t.updateSessionRules(...) is undefined

That rejection replaces the successful result. Core maps it to FetcherError, the sign-in handler maps that to bad-rp-id, and the page shim falls back to the browser. The only warning in that path is inside the .catch that never runs.

Verified separately: the content-script fetch returns the document (200, application/json), and browser.declarativeNetRequest.updateSessionRules accepts the same rule.

Repro (temporary add-on via about:debugging)

manifest.json:

{ "manifest_version": 2, "name": "dnr-repro", "version": "0.1",
"permissions": ["<all_urls>", "declarativeNetRequestWithHostAccess"],
"background": { "scripts": ["bg.js"] } }

bg.js:

const rule = { id: 1, priority: 1,
action: { type: "modifyHeaders", requestHeaders: [{ header: "sec-fetch-site", operation: "set", value: "none" }] },
condition: { requestDomains: ["auth.example.com"], urlFilter: "/.well-known/webauthn", resourceTypes: ["xmlhttprequest"] } };

console.log(typeof chrome.declarativeNetRequest.updateSessionRules({ addRules: [rule] }));
// Firefox: "undefined" Chrome: "object"

browser.declarativeNetRequest.updateSessionRules({ removeRuleIds: [1] })
.then(() => console.log("browser.* returns a promise and accepts the rule"));

Fix

Use browser.declarativeNetRequest (or the polyfill) in the fetcher, or guard the return value before calling .catch.

Impact

Every related-origin site, get and create, Firefox only. Because the fallback is silent, users read it as "1Password did not show up" and blame the site or Firefox.

3 replies

1P_ChrisBurgin
1Password Employee
1Password Employee
September 28, 2026

​@thunkar Thanks for reporting this! I am a developer on the browser extension team. I wanted to let you know that we just merged a fix for this and it should be available in the next release.

 

Please do reach out if you have any other issues!

thunkarAuthor
September 28, 2026

​@1P_ChrisBurgin Awesome, thanks for the quick fix!