Skip to content

Commit 03c0f2b

Browse files
author
Mo Jamal
committed
Add Webauthn remoteClientDataJSON extension explainer
1 parent a648e5b commit 03c0f2b

File tree

2 files changed

+339
-0
lines changed

2 files changed

+339
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
name: WebAuthn remoteClientDataJSON Extension
3+
about: new issue
4+
title: "[WebAuthn remoteClientDataJSON] <TITLE HERE>"
5+
labels: WebAuthn RemoteclientDataJSON Extension
6+
assignees: bobomb
7+
8+
---
9+
10+
Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
# WebAuthn `remoteClientDataJSON` Extension
2+
3+
Authors: [Akshay Kumar](mailto:Akshay.Kumar@microsoft.com), [Zach Dixon](mailto:Zachary.Dixon@microsoft.com), [Mo Jamal](mailto:jamalmo@microsoft.com)
4+
5+
## Status of this Document
6+
7+
This document is a starting point for engaging the community and standards
8+
bodies in developing collaborative solutions fit for standardization. As the
9+
solutions to problems described in this document progress along the
10+
standards-track, we will retain this document as an archive and use this
11+
section to keep the community up-to-date with the most current standards
12+
venue and content location of future work and discussions.
13+
14+
* This document status: **`ACTIVE`**
15+
* Expected venue: [W3C Web Authentication Working Group](https://www.w3.org/groups/wg/webauthn/)
16+
* **Current version: this document**
17+
* Related spec PR: [w3c/webauthn#2375](https://github.com/w3c/webauthn/pull/2375)
18+
* Related issue: [w3c/webauthn#1577](https://github.com/w3c/webauthn/issues/1577)
19+
20+
## Introduction
21+
22+
The [Web Authentication API](https://www.w3.org/TR/webauthn-3/) (WebAuthn) enables strong, phishing-resistant authentication on the web using public-key cryptography. During a WebAuthn ceremony, the browser constructs a JSON object called `clientDataJSON` from values such as the origin, challenge, and ceremony type. This object is signed by the authenticator and later verified by the relying party.
23+
24+
Remote desktop web clients present a challenge for this model. When a user initiates a WebAuthn ceremony within a remote desktop session, the request originates from the remote host (e.g., `https://accounts.example.com`) but is executed in the context of the local web client (e.g., `https://myrdc.example`). The browser constructs `clientDataJSON` using the *local* client's origin rather than the *remote* host's origin. Meanwhile, the remote desktop host passes its own `clientDataJSON` (with the remote origin) to the platform authenticator API (e.g., the Windows WebAuthn API). This mismatch between the browser-constructed and host-provided `clientDataJSON` causes signature validation to fail.
25+
26+
The existing [`remoteDesktopClientOverride`](https://w3c.github.io/webauthn/#sctn-remoteDesktopClientOverride-extension) extension partially addresses this by allowing remote desktop clients to override the `origin` and `crossOrigin` fields. However, it still relies on the browser to *construct* `clientDataJSON` from component values, which may differ from the `clientDataJSON` that the remote host passed to the platform API. Any structural differences -- field ordering, additional fields, whitespace -- will produce a different hash and break signature verification.
27+
28+
The `remoteClientDataJSON` extension solves this by allowing an authorized remote desktop web client to provide the *complete* `clientDataJSON` string, which the browser passes through verbatim without modification.
29+
30+
## Background
31+
32+
### Current WebAuthn Flow in Remote Desktop when using a Web based client
33+
34+
1. A user visits `https://accounts.example.com` within a remote desktop session hosted on a remote machine.
35+
2. The relying party at `https://accounts.example.com` initiates a WebAuthn ceremony.
36+
3. The remote desktop host intercepts the request and forwards it to the local client via the Remote Desktop Protocol (RDP) WebAuthn virtual channel.
37+
4. The local remote desktop web client (e.g., `https://myrdc.example`) calls the WebAuthn API in the local browser.
38+
5. The browser constructs its own `clientDataJSON` using the local client's context.
39+
6. The authenticator signs a hash of this browser-constructed `clientDataJSON`.
40+
7. The response is sent back to the remote host, which attempts to verify the signature against the `clientDataJSON` it originally provided to the platform API.
41+
8. **Verification fails** because the two `clientDataJSON` objects differ.
42+
43+
### Existing `remoteDesktopClientOverride` Extension
44+
45+
Chromium already supports a [`remoteDesktopClientOverride`](https://w3c.github.io/webauthn/#sctn-remoteDesktopClientOverride-extension) extension that allows overriding the `origin` and `sameOriginWithAncestors` values used when constructing `clientDataJSON`:
46+
47+
```js
48+
navigator.credentials.get({
49+
publicKey: {
50+
challenge: ...,
51+
rpId: "example.com",
52+
allowCredentials: [...],
53+
extensions: {
54+
remoteDesktopClientOverride: {
55+
origin: "https://accounts.example.com",
56+
sameOriginWithAncestors: false,
57+
},
58+
},
59+
},
60+
});
61+
```
62+
63+
This extension corrects the origin and cross-origin flag, but the browser still constructs `clientDataJSON` itself. The resulting JSON may differ from what the remote host passed to the Windows WebAuthn API in field ordering, optional fields, or formatting -- any of which causes a hash mismatch and signature verification failure.
64+
65+
## Goals
66+
67+
- Enable remote desktop web clients to provide a complete `clientDataJSON` string that the browser passes through to the authenticator without modification, ensuring hash consistency with the remote host.
68+
- Maintain the existing security model: per-origin authorization via enterprise policy or explicit user opt-in.
69+
- Support both `navigator.credentials.create()` (registration) and `navigator.credentials.get()` (authentication) ceremonies.
70+
- Support non-managed device scenarios where enterprise policy is impractical, via browser flag configuration.
71+
72+
## Non-Goals
73+
74+
- Deprecating or removing the existing `remoteDesktopClientOverride` extension. Both extensions will coexist.
75+
- Modifying the behavior of WebAuthn for non-remote-desktop use cases.
76+
- Implementing a general-purpose mechanism for arbitrary `clientDataJSON` injection outside of remote desktop scenarios.
77+
- Defining platform-specific authenticator behavior. The extension operates entirely at the client (browser) level.
78+
79+
## Use Cases
80+
81+
### Scenario 1: RDP Web Client with Windows WebAuthn API
82+
83+
A user connects to a remote Windows desktop via a web-based RDP client (`https://myrdc.example`). The remote desktop application on the host calls the Windows WebAuthn API, which accepts a complete `clientDataJSON` object. The RDP virtual channel forwards the WebAuthn request -- including the host's `clientDataJSON` -- to the web client. The web client uses `remoteClientDataJSON` to pass this exact JSON to the browser, ensuring the authenticator signs the same data that the remote host will use for verification.
84+
85+
### Scenario 2: Non-Managed Personal Device
86+
87+
A user accesses a corporate remote desktop from their personal laptop. Since the device is not enterprise-managed, configuring enterprise policy for WebAuthn remote desktop support is impractical. The user enables a browser flag (`chrome://flags`) and adds the remote desktop client's origin to the allowlist, enabling WebAuthn passkey authentication within the remote session.
88+
89+
### Scenario 3: Third-Party Remote Desktop Provider
90+
91+
A third-party remote desktop service (`https://remoteapp.example`) needs WebAuthn support for its web client. Using `remoteClientDataJSON`, the provider can forward the exact `clientDataJSON` from the remote host without worrying about browser-specific JSON construction differences across different Chromium-based browsers.
92+
93+
## Proposed Solution
94+
95+
### API Surface
96+
97+
A new WebAuthn client extension, `remoteClientDataJSON`, accepts a complete `clientDataJSON` as a `DOMString`:
98+
99+
```js
100+
// The remote desktop web client at https://myrdc.example provides
101+
// the exact clientDataJSON from the remote host.
102+
const remoteJSON = JSON.stringify({
103+
type: "webauthn.get",
104+
challenge: "base64url-encoded-challenge",
105+
origin: "https://accounts.example.com",
106+
crossOrigin: false,
107+
});
108+
109+
navigator.credentials.get({
110+
publicKey: {
111+
challenge: ...,
112+
rpId: "example.com",
113+
allowCredentials: [...],
114+
extensions: {
115+
remoteClientDataJSON: remoteJSON,
116+
},
117+
},
118+
});
119+
```
120+
121+
The value is a JSON-serialized string containing the standard `clientDataJSON` fields (`type`, `challenge`, `origin`, `crossOrigin`). The browser passes this string through to the authenticator without modification.
122+
123+
### WebIDL
124+
125+
Per [w3c/webauthn PR #2375](https://github.com/w3c/webauthn/pull/2375):
126+
127+
**Client Extension Input:**
128+
129+
```webidl
130+
partial dictionary AuthenticationExtensionsClientInputs {
131+
DOMString remoteClientDataJSON;
132+
};
133+
134+
partial dictionary AuthenticationExtensionsClientInputsJSON {
135+
DOMString remoteClientDataJSON;
136+
};
137+
```
138+
139+
**Client Extension Output:**
140+
141+
```webidl
142+
partial dictionary AuthenticationExtensionsClientOutputs {
143+
boolean remoteClientDataJson;
144+
};
145+
146+
partial dictionary AuthenticationExtensionsClientOutputsJSON {
147+
boolean remoteClientDataJson;
148+
};
149+
```
150+
151+
> Note: The input uses `remoteClientDataJSON` (uppercase `JSON`) while the output uses `remoteClientDataJson` (camelCase `Json`), per the naming in the W3C spec PR.
152+
153+
### Processing Steps
154+
155+
When `remoteClientDataJSON` is present in the extension inputs:
156+
157+
1. **Permission check**: Verify that the calling origin is authorized to use this extension (via enterprise policy, browser flag allowlist, or permissions policy).
158+
2. **Parse the JSON**: Parse the provided `remoteClientDataJSON` string. If parsing fails, throw `NotSupportedError`.
159+
3. **Extract the remote origin**: Read the `"origin"` field from the parsed JSON.
160+
4. **Validate RP ID**: Verify that the requested `rpId` is a valid registrable domain suffix of the extracted remote origin. If validation fails, throw `SecurityError`.
161+
5. **Skip `clientDataJSON` construction**: The browser MUST NOT construct its own `clientDataJSON`. The provided string is used as-is.
162+
6. **Compute the hash**: Compute `SHA-256` of the provided `clientDataJSON` string for the authenticator.
163+
7. **Return verbatim**: The `clientDataJSON` in the response is the exact string provided by the caller, with no additions, removals, or modifications.
164+
165+
### Precedence
166+
167+
If both `remoteClientDataJSON` and `remoteDesktopClientOverride` are present in the same request, `remoteClientDataJSON` takes priority. The `remoteDesktopClientOverride` fields are ignored without raising an error.
168+
169+
### Permissions Policy
170+
171+
The W3C spec PR defines a permissions policy feature:
172+
173+
- **Feature identifier:** `publickey-credentials-remote-client-data-json`
174+
- **Default allowlist:** `'none'`
175+
176+
This is designated as a [powerful feature](https://w3c.github.io/permissions/#powerful-feature) with a default permission state of `"denied"`.
177+
178+
### Example: Registration (Create)
179+
180+
```js
181+
// Remote desktop web client at https://myrdc.example
182+
const clientDataJSON = JSON.stringify({
183+
type: "webauthn.create",
184+
challenge: "SGVsbG8gV29ybGQ", // base64url-encoded challenge from the remote host
185+
origin: "https://accounts.example.com",
186+
crossOrigin: false,
187+
});
188+
189+
const credential = await navigator.credentials.create({
190+
publicKey: {
191+
rp: { name: "Example Corp", id: "example.com" },
192+
user: {
193+
id: new Uint8Array([1, 2, 3, 4]),
194+
name: "user@example.com",
195+
displayName: "User",
196+
},
197+
challenge: new Uint8Array([/* challenge bytes */]),
198+
pubKeyCredParams: [{ type: "public-key", alg: -7 }],
199+
extensions: {
200+
remoteClientDataJSON: clientDataJSON,
201+
},
202+
},
203+
});
204+
205+
// credential.response.clientDataJSON contains the exact string
206+
// provided above, enabling signature verification on the remote host.
207+
```
208+
209+
### Example: Authentication (Get)
210+
211+
```js
212+
// Remote desktop web client at https://myrdc.example
213+
const clientDataJSON = JSON.stringify({
214+
type: "webauthn.get",
215+
challenge: "dGVzdENoYWxsZW5nZQ",
216+
origin: "https://accounts.example.com",
217+
crossOrigin: false,
218+
});
219+
220+
const assertion = await navigator.credentials.get({
221+
publicKey: {
222+
rpId: "example.com",
223+
challenge: new Uint8Array([/* challenge bytes */]),
224+
allowCredentials: [...],
225+
extensions: {
226+
remoteClientDataJSON: clientDataJSON,
227+
},
228+
},
229+
});
230+
```
231+
232+
## Authorization Model
233+
234+
This extension requires explicit per-origin authorization. Three mechanisms are supported:
235+
236+
### 1. Enterprise Policy (Managed Devices)
237+
238+
On managed devices, administrators configure the `WebAuthnRemoteDesktopAllowedOrigins` enterprise policy with a list of authorized origins. This is the recommended approach for enterprise deployments.
239+
240+
### 2. Browser Flags (Non-Managed Devices)
241+
242+
For personal or non-managed devices, users can enable WebAuthn remote desktop support via browser flags:
243+
244+
1. Navigate to `chrome://flags#webauthn-remote-client-data-json`.
245+
2. Enter the authorized origin(s) (e.g., `https://myrdc.example`).
246+
3. Restart the browser.
247+
248+
The flags page includes a standard warning about enabling experimental features and their potential security implications.
249+
250+
### 3. Permissions Policy (Future)
251+
252+
The W3C spec PR defines integration with the [Permissions API](https://w3c.github.io/permissions/) and [Permissions Policy](https://w3c.github.io/permissions-policy/). When standardized, this will provide a web-standard mechanism for sites to declare permission via HTTP headers:
253+
254+
```
255+
Permissions-Policy: publickey-credentials-remote-client-data-json=(self "https://myrdc.example")
256+
```
257+
258+
## Considered Alternatives
259+
260+
### Alternative 1: Extend `remoteDesktopClientOverride` with Additional Fields
261+
262+
Adding more fields (e.g., `challenge`, `type`) to the existing `remoteDesktopClientOverride` extension to cover all `clientDataJSON` components.
263+
264+
**Rejected because:**
265+
- Requires redundant parsing: the remote host already has the complete JSON, and decomposing it into individual fields only to have the browser reassemble them introduces unnecessary complexity and potential for divergence.
266+
- Future additions to `clientDataJSON` would require corresponding changes to the extension interface.
267+
- Does not guarantee byte-for-byte equivalence with the remote host's JSON, since the browser may serialize fields differently.
268+
269+
### Alternative 2: Accept a Pre-Computed Hash Instead of the Full JSON
270+
271+
Allow the caller to provide only the `SHA-256` hash of `clientDataJSON`, rather than the full string.
272+
273+
**Rejected because:**
274+
- The relying party expects the full `clientDataJSON` in the authentication response for verification. Providing only a hash would require a separate channel to transmit the full JSON.
275+
- The browser would lose the ability to validate the RP ID against the origin in the JSON, weakening the security model.
276+
277+
278+
## Privacy and Security Considerations
279+
280+
### Security
281+
282+
#### Origin Substitution
283+
284+
The `remoteClientDataJSON` extension allows the calling origin to supply a `clientDataJSON` containing a different `origin` value than the local browser context. This is inherent to the remote desktop use case, but it means the browser must trust the caller to provide an accurate remote origin. This trust is mitigated by the per-origin authorization requirement.
285+
286+
#### RP ID Validation
287+
288+
The browser parses the provided `clientDataJSON` and validates the requested `rpId` against the `origin` extracted from the JSON, using the standard registrable domain suffix check. This ensures that even with a complete JSON override, the caller cannot make requests for arbitrary relying parties unrelated to the specified origin.
289+
290+
#### Per-Origin Authorization
291+
292+
User agents MUST NOT grant this permission globally. The extension is only available to origins explicitly authorized via:
293+
- Enterprise device management policy, or
294+
- Explicit user opt-in through browser flags with a per-origin allowlist.
295+
296+
This ensures that arbitrary web pages cannot use this extension to forge `clientDataJSON`.
297+
298+
#### Interaction with `remoteDesktopClientOverride`
299+
300+
When both extensions are present, `remoteClientDataJSON` takes precedence. This is safe because `remoteClientDataJSON` provides a strict superset of the functionality of `remoteDesktopClientOverride`, and the same authorization model applies to both.
301+
302+
### Privacy
303+
304+
This extension does not introduce new privacy concerns beyond those already present in the `remoteDesktopClientOverride` extension. The `clientDataJSON` string provided by the caller contains only the standard fields (`type`, `challenge`, `origin`, `crossOrigin`) that the browser would normally construct itself. No additional user data is exposed.
305+
306+
The extension is not available by default and cannot be used for fingerprinting, as it requires explicit per-origin authorization that is not detectable by unauthorized origins.
307+
308+
## Open Questions
309+
310+
1. **Permissions API integration**: The W3C spec PR (#2375) defines `remoteClientDataJSON` as a [powerful feature](https://w3c.github.io/permissions/#powerful-feature) with a custom permission descriptor. Ongoing review ([kreichgauer, April 2026](https://github.com/w3c/webauthn/pull/2375)) suggests the custom descriptor may be unnecessary. The scope of Permissions API integration depends on the resolution of this review.
311+
312+
2. **Feature identifier naming**: Should the permissions policy feature use `remote-client-data-json` or `publickey-credentials-remote-client-data-json` to align with existing WebAuthn permission feature naming conventions?
313+
314+
3. **Related origin requests**: When `remoteClientDataJSON` is present and RP ID validation is performed against the extracted origin, should [related origin requests](https://w3c.github.io/webauthn/#sctn-related-origins) also be evaluated, or should they be skipped?
315+
316+
4. **User communication**: The spec recommends that user agents clearly communicate to users when a remote-desktop-proxied WebAuthn operation is in progress. The form and requirements of this communication are not yet defined.
317+
318+
## References
319+
320+
- [W3C Web Authentication Level 3 Specification](https://www.w3.org/TR/webauthn-3/)
321+
- [W3C WebAuthn PR #2375: `remoteClientDataJSON` Extension](https://github.com/w3c/webauthn/pull/2375)
322+
- [W3C WebAuthn Issue #1577: Remote Desktop Support](https://github.com/w3c/webauthn/issues/1577)
323+
- [W3C WebAuthn Wiki: Explainer -- Remote Desktop Support](https://github.com/w3c/webauthn/wiki/Explainer:-Remote-Desktop-Support)
324+
- [Existing `remoteDesktopClientOverride` Extension Spec](https://w3c.github.io/webauthn/#sctn-remoteDesktopClientOverride-extension)
325+
- Chromium CLs for existing extension:
326+
- [Add `remoteDesktopClientOverride` extension IDL (CL 3499163)](https://chromium-review.googlesource.com/c/chromium/src/+/3499163)
327+
- [Wire up `RemoteDesktopClientOverride` client extension (CL 3577285)](https://chromium-review.googlesource.com/c/chromium/src/+/3577285)
328+
- [Add `remoteDesktopClientOverride` support on Android (CL 6281085)](https://chromium-review.googlesource.com/c/chromium/src/+/6281085)
329+
- [Add `remoteDesktopClientOverride` when proxying requests (CL 3588862)](https://chromium-review.googlesource.com/c/chromium/src/+/3588862)

0 commit comments

Comments
 (0)