Two-Factor Authentication (Security Keys) : tpm-fido : Could not read your security key : NotAllowedError #14907

Open
opened 2025-11-02 11:25:35 -06:00 by GiteaMirror · 0 comments
Owner

Originally created by @bobemoe on GitHub (Aug 27, 2025).

Description

Registration of a roaming security key fails because the WebAuthn request requires resident/discoverable credentials, which such authenticators don’t support.

Environment

  • Client OS: Artix Linux, KDE, Wayland
  • Browser: Firefox 141.0.3 (64-bit)
  • Authenticator: tpm-fido (Linux TPM → FIDO2 via UHID)
    • fido2-token -L shows:
      /dev/hidraw3: vendor=0x15d9, product=0x0a37 ( tpm-fido)
      

Steps to reproduce

  1. Start the authenticator bridge:
    tpm-fido
    
  2. On the Gitea demo site, open Settings → Security → Security Keys → Add Security Key.
  3. At this moment, the authenticator log prints:
    got VersionCmd
    
    No user-presence prompt appears.
  4. The browser shows:
    Could not read your security key.
    NotAllowedError: The request is not allowed by the user agent or the platform in the current context
    

Captured navigator.credentials.create() options (from DevTools on the failing page)

{
  "publicKey": {
    "rp": { "name": "xx", "id": "xx.co.uk" },
    "user": { "name": "xx", "displayName": "xx", "id": { "__type": "ArrayBuffer", "base64": "AgAAAAAAAAA=" } },
    "challenge": { "__type": "ArrayBuffer", "base64": "xxxx=" },
    "pubKeyCredParams": [
      { "type": "public-key", "alg": -7 }, { "type": "public-key", "alg": -35 },
      { "type": "public-key", "alg": -36 }, { "type": "public-key", "alg": -257 },
      { "type": "public-key", "alg": -258 }, { "type": "public-key", "alg": -259 },
      { "type": "public-key", "alg": -37 }, { "type": "public-key", "alg": -38 },
      { "type": "public-key", "alg": -39 }, { "type": "public-key", "alg": -8 }
    ],
    "timeout": 300000,
    "authenticatorSelection": { "residentKey": "required" },
    "attestation": "direct"
  }
}

Workarounds verified (in-page, DevTools console)

1) Change only resident key requirement → registration succeeds

(() => {
  const orig = navigator.credentials.create.bind(navigator.credentials);
  navigator.credentials.create = (opts) => {
    const sel = opts?.publicKey?.authenticatorSelection;
    if (sel && (sel.residentKey === 'required' || sel.requireResidentKey === true)) {
      opts.publicKey.authenticatorSelection = { ...sel, residentKey: 'preferred', requireResidentKey: false };
    }
    return orig(opts);
  };
})();

Result: user-presence prompt appears; firefox warns of collecting extra information; authenticator proceeds beyond got VersionCmd; key registers successfully.

2) Additionally set attestation to "none" → removes Firefox “extra information” consent; registration still succeeds

(() => {
  const orig = navigator.credentials.create.bind(navigator.credentials);
  navigator.credentials.create = (opts) => {
    if (opts?.publicKey) {
      if (opts.publicKey.authenticatorSelection?.residentKey === 'required' ||
          opts.publicKey.authenticatorSelection?.requireResidentKey === true) {
        opts.publicKey.authenticatorSelection = {
          ...opts.publicKey.authenticatorSelection,
          residentKey: 'preferred',
          requireResidentKey: false
        };
      }
      opts.publicKey.attestation = 'none';
    }
    return orig(opts);
  };
})();

Control test

Using the same client + authenticator, registration works on webauthn.io when configured for a security key with non-resident credentials and userVerification discouraged.

Fix / Request

Proposed fix

For the Security Keys (roaming key) MFA flow:

  • Use options compatible with external roaming authenticators:
    • authenticatorSelection: { residentKey: "preferred", authenticatorAttachment: "cross-platform", userVerification: "preferred", requireResidentKey: false }
    • attestation: "none" (removes extra-info prompts; still works)
  • Alternatively, expose the above as per-instance settings so admins can choose.

Optional UX improvement:

  • Provide two explicit buttons/flows with appropriate defaults:
    1. Add Security Key (USB/NFC) → for 2FA
      authenticatorSelection: {
        residentKey: "preferred",
        authenticatorAttachment: "cross-platform",
        userVerification: "preferred",
        requireResidentKey: false
      }
      attestation: "none"
      
    2. Add Passkey (this device) → for passwordless
      authenticatorSelection: {
        residentKey: "required",
        authenticatorAttachment: "platform",
        userVerification: "required"
      }
      attestation: "none" // or "indirect"
      

Gitea Version

1.24.5

Can you reproduce the bug on the Gitea demo site?

Yes

How are you running Gitea?

https://demo.gitea.com/

Originally created by @bobemoe on GitHub (Aug 27, 2025). ### Description Registration of a roaming security key fails because the WebAuthn request requires resident/discoverable credentials, which such authenticators don’t support. ## Environment - **Client OS:** Artix Linux, KDE, Wayland - **Browser:** Firefox 141.0.3 (64-bit) - **Authenticator:** `tpm-fido` (Linux TPM → FIDO2 via UHID) - `fido2-token -L` shows: ``` /dev/hidraw3: vendor=0x15d9, product=0x0a37 ( tpm-fido) ``` ## Steps to reproduce 1) Start the authenticator bridge: ```bash tpm-fido ``` 2) On the **Gitea demo site**, open **Settings → Security → Security Keys → Add Security Key**. 3) **At this moment**, the authenticator log prints: ``` got VersionCmd ``` No user-presence prompt appears. 4) The browser shows: ``` Could not read your security key. NotAllowedError: The request is not allowed by the user agent or the platform in the current context ``` ## Captured `navigator.credentials.create()` options (from DevTools on the failing page) ```json { "publicKey": { "rp": { "name": "xx", "id": "xx.co.uk" }, "user": { "name": "xx", "displayName": "xx", "id": { "__type": "ArrayBuffer", "base64": "AgAAAAAAAAA=" } }, "challenge": { "__type": "ArrayBuffer", "base64": "xxxx=" }, "pubKeyCredParams": [ { "type": "public-key", "alg": -7 }, { "type": "public-key", "alg": -35 }, { "type": "public-key", "alg": -36 }, { "type": "public-key", "alg": -257 }, { "type": "public-key", "alg": -258 }, { "type": "public-key", "alg": -259 }, { "type": "public-key", "alg": -37 }, { "type": "public-key", "alg": -38 }, { "type": "public-key", "alg": -39 }, { "type": "public-key", "alg": -8 } ], "timeout": 300000, "authenticatorSelection": { "residentKey": "required" }, "attestation": "direct" } } ``` ## Workarounds verified (in-page, DevTools console) **1) Change only resident key requirement → registration succeeds** ```js (() => { const orig = navigator.credentials.create.bind(navigator.credentials); navigator.credentials.create = (opts) => { const sel = opts?.publicKey?.authenticatorSelection; if (sel && (sel.residentKey === 'required' || sel.requireResidentKey === true)) { opts.publicKey.authenticatorSelection = { ...sel, residentKey: 'preferred', requireResidentKey: false }; } return orig(opts); }; })(); ``` _Result:_ user-presence prompt appears; firefox warns of collecting extra information; authenticator proceeds beyond `got VersionCmd`; key registers successfully. **2) Additionally set attestation to `"none"` → removes Firefox “extra information” consent; registration still succeeds** ```js (() => { const orig = navigator.credentials.create.bind(navigator.credentials); navigator.credentials.create = (opts) => { if (opts?.publicKey) { if (opts.publicKey.authenticatorSelection?.residentKey === 'required' || opts.publicKey.authenticatorSelection?.requireResidentKey === true) { opts.publicKey.authenticatorSelection = { ...opts.publicKey.authenticatorSelection, residentKey: 'preferred', requireResidentKey: false }; } opts.publicKey.attestation = 'none'; } return orig(opts); }; })(); ``` ## Control test Using the same client + authenticator, registration **works** on **webauthn.io** when configured for a **security key** with **non-resident** credentials and **userVerification discouraged**. ## Fix / Request **Proposed fix** For the **Security Keys (roaming key) MFA** flow: - Use options compatible with external roaming authenticators: - `authenticatorSelection: { residentKey: "preferred", authenticatorAttachment: "cross-platform", userVerification: "preferred", requireResidentKey: false }` - `attestation: "none"` (removes extra-info prompts; still works) - Alternatively, expose the above as per-instance settings so admins can choose. Optional UX improvement: - Provide two explicit buttons/flows with appropriate defaults: 1) **Add Security Key (USB/NFC)** → for 2FA ```js authenticatorSelection: { residentKey: "preferred", authenticatorAttachment: "cross-platform", userVerification: "preferred", requireResidentKey: false } attestation: "none" ``` 2) **Add Passkey (this device)** → for passwordless ```js authenticatorSelection: { residentKey: "required", authenticatorAttachment: "platform", userVerification: "required" } attestation: "none" // or "indirect" ``` ### Gitea Version 1.24.5 ### Can you reproduce the bug on the Gitea demo site? Yes ### How are you running Gitea? https://demo.gitea.com/
GiteaMirror added the topic/authenticationtype/bug labels 2025-11-02 11:25:35 -06:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/gitea#14907