nextcloud / nextcloud/twofactor_webauthn
Security key login fails with DataCloneError: Proxy object could not be cloned
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 59
- Forks
- 11
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 16
Description
Steps to reproduce
- Register a security key as a second factor
- Log out, log in, pick the security key
- Nothing happens and the browser console shows the error below
Actual behaviour
[ERROR] twofactor_webauthn: challenge failed
Object { app: "twofactor_webauthn", uid: "…", level: 2, error: DOMException }
error: DOMException: Proxy object could not be cloned.
Cause
Challenge.vue passes credentialRequestOptions straight into startAuthentication():
authResponse = await startAuthentication({
optionsJSON: this.credentialRequestOptions,
})
The value arrives from the Pinia store, so under Vue 3 it is a reactive Proxy. startAuthentication() forwards it to navigator.credentials.get(), which structured-clones its argument — and a Proxy cannot be cloned.
The frontend moved to Vue 3 in 2.2.0, which is when this would have started.
Suggested fix
Unwrap before the call:
import { toRaw } from 'vue'
authResponse = await startAuthentication({
optionsJSON: structuredClone(toRaw(this.credentialRequestOptions)),
})
optionsJSON is a PublicKeyCredentialRequestOptionsJSON, so it holds JSON values only — the challenge and credential IDs are base64url strings, not ArrayBuffers. A deep clone loses nothing.
What I verified
I patched the built bundle on my instance:
ij({optionsJSON:n.credentialRequestOptions})
→ ij({optionsJSON:JSON.parse(JSON.stringify(n.credentialRequestOptions))})
Security key login works after that.
Registration takes the same code path in login-setup.js and settings.js, but there the options come straight from the server response, so no Proxy is involved and I saw no failure.
Versions
- twofactor_webauthn 2.7.0
- Nextcloud 34.0.3
- Firefox
This does not hit every user — whether it fails depends on how strictly the browser enforces structured cloning on the argument, so a Chromium test would be worth adding to this report.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in Challenge.vue at the startAuthentication() call and inspect how credentialRequestOptions is passed to the browser credential API. Confirm the request options are no longer a reactive Proxy, then verify that security key login completes without the DataCloneError; login-setup.js and settings.js provide the related registration paths for comparison.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- authentication
- Issue type
- Bug
- Difficulty
- 1/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 90/100