Authors: Akshay Kumar, Zach Dixon, Mo Jamal
This document is a starting point for engaging the community and standards bodies in developing collaborative solutions fit for standardization. As the solutions to problems described in this document progress along the standards-track, we will retain this document as an archive and use this section to keep the community up-to-date with the most current standards venue and content location of future work and discussions.
- This document status:
ACTIVE - Expected venue: W3C Web Authentication Working Group
- Current version: this document
- Related spec PR: w3c/webauthn#2375 — approved by the Working Group; pending merge. Editorial polish is expected to land as follow-up PRs.
- Related issue: w3c/webauthn#1577
- Approving reviewers: @pascoej, @emlun, @ve7jtb, @timcappalli, @MasterKale
The Web Authentication API (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.
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.
A preexisting Chromium-only extension, remoteDesktopClientOverride, partially addresses this by allowing remote desktop clients to override the origin and crossOrigin fields. It has never been standardized in the W3C WebAuthn specification. Even where supported, it 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.
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. It is the first remote-desktop WebAuthn extension to be standardized in the W3C spec (via PR #2375).
- A user visits
https://accounts.example.comwithin a remote desktop session hosted on a remote machine. - The relying party at
https://accounts.example.cominitiates a WebAuthn ceremony. - The remote desktop host intercepts the request and forwards it to the local client via the Remote Desktop Protocol (RDP) WebAuthn virtual channel.
- The local remote desktop web client (e.g.,
https://myrdc.example) calls the WebAuthn API in the local browser. - The browser constructs its own
clientDataJSONusing the local client's context. - The authenticator signs a hash of this browser-constructed
clientDataJSON. - The response is sent back to the remote host, which attempts to verify the signature against the
clientDataJSONit originally provided to the platform API. - Verification fails because the two
clientDataJSONobjects differ.
Chromium already supports a remoteDesktopClientOverride extension that allows overriding the origin and sameOriginWithAncestors values used when constructing clientDataJSON. Note that this extension is a Chromium-specific implementation; it is not defined in the published W3C WebAuthn specification:
navigator.credentials.get({
publicKey: {
challenge: ...,
rpId: "example.com",
allowCredentials: [...],
extensions: {
remoteDesktopClientOverride: {
origin: "https://accounts.example.com",
sameOriginWithAncestors: false,
},
},
},
});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.
- Enable remote desktop web clients to provide a complete
clientDataJSONstring that the browser passes through to the authenticator without modification, ensuring hash consistency with the remote host. - Maintain the existing security model: per-origin authorization via enterprise policy or explicit user opt-in.
- Support both
navigator.credentials.create()(registration) andnavigator.credentials.get()(authentication) ceremonies. - Support non-managed device scenarios where enterprise policy is impractical, via browser flag configuration.
- Deprecating or removing Chromium's existing (non-standard)
remoteDesktopClientOverrideextension. Both extensions will coexist in Chromium, withremoteClientDataJSONtaking priority when both are present. - Modifying the behavior of WebAuthn for non-remote-desktop use cases.
- Implementing a general-purpose mechanism for arbitrary
clientDataJSONinjection outside of remote desktop scenarios. - Defining platform-specific authenticator behavior. The extension operates entirely at the client (browser) level.
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.
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.
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.
A new WebAuthn client extension, remoteClientDataJSON, accepts a complete clientDataJSON as a DOMString:
// The remote desktop web client at https://myrdc.example provides
// the exact clientDataJSON from the remote host.
const remoteJSON = JSON.stringify({
type: "webauthn.get",
challenge: "base64url-encoded-challenge",
origin: "https://accounts.example.com",
crossOrigin: false,
});
navigator.credentials.get({
publicKey: {
challenge: ...,
rpId: "example.com",
allowCredentials: [...],
extensions: {
remoteClientDataJSON: remoteJSON,
},
},
});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.
Per w3c/webauthn PR #2375 (approved):
Client Extension Input:
partial dictionary AuthenticationExtensionsClientInputs {
DOMString remoteClientDataJSON;
};
partial dictionary AuthenticationExtensionsClientInputsJSON {
DOMString remoteClientDataJSON;
};Client Extension Output:
partial dictionary AuthenticationExtensionsClientOutputs {
boolean remoteClientDataJson;
};
partial dictionary AuthenticationExtensionsClientOutputsJSON {
boolean remoteClientDataJson;
};Note: The input uses
remoteClientDataJSON(uppercaseJSON) while the output usesremoteClientDataJson(camelCaseJson), per the current spec PR naming. The output is simply a booleantrueindicating the extension was acted upon. Earlier drafts also returned aremoteDesktopClientOriginstring in the output; that field was removed during review because the origin is already conveyed insideclientDataJSON.
When remoteClientDataJSON is present in the extension inputs, the algorithm replaces the standard "establish the RP ID" and "construct collectedClientData" steps of the registration / authentication ceremonies with the following (per the approved spec PR):
- Permission check: If the current permission state for
"publickey-credentials-remote-client-data-json"and the current settings object is not"granted", throwNotAllowedError. - RP ID presence: If
publicKey.rp.id(registration) /publicKey.rpId(authentication) is not present, throwNotAllowedError. The caller MUST supply an explicit RP ID — the browser does not default it to the calling origin. - Parse the JSON: Parse the provided
remoteClientDataJSONstring as a JSON value (using the Infra "parse a JSON string to an Infra value" algorithm). If parsing fails:- For
navigator.credentials.create(), throwEncodingError. - For
navigator.credentials.get(), throwNotSupportedError.
Note: the two ceremonies use different exception types in the current spec text; this may be aligned in a follow-up editorial PR.
- For
- Extract the remote origin: Read the
"origin"key from the parsed JSON; call thisremoteOrigin. - Skip the registrable-domain-suffix check: The browser does not verify that
rpIdis a registrable domain suffix ofremoteOrigin. RP ID validation is delegated to the remote client, which has the full context needed to evaluate related origins and platform-specific app-deployment models. - Skip
clientDataJSONconstruction: The browser MUST NOT build its owncollectedClientData; the parsed JSON from step 3 is used directly. - Pass the JSON through verbatim: In the "serialize client data" step, set
clientDataJSONto the exactremoteClientDataJSONstring supplied by the caller. The user agent MUST NOT add, remove, or modify any of its contents (doing so would invalidate the remote machine's hash and cause signature verification to fail at the RP). - Compute the hash: Compute
SHA-256of the verbatim string for the authenticator.
The client extension output is simply true, signaling to the RP that the extension was acted upon. The earlier draft also returned a remoteDesktopClientOrigin field; that was removed in response to review feedback from @MasterKale so that origin information travels only inside clientDataJSON.
remoteDesktopClientOverride is not part of the W3C spec and interaction between the two extensions is therefore a Chromium implementation detail. In Chromium, if both extensions are present in the same request, remoteClientDataJSON takes priority and remoteDesktopClientOverride is ignored without raising an error.
The approved spec PR defines the extension as both a powerful feature and a policy-controlled feature, identified by the same token:
- Feature identifier:
publickey-credentials-remote-client-data-json - Default allowlist (Permissions Policy):
'none'— disabled for all origins by default. - Default permission state (Permissions API):
"denied"— the extension is unavailable until explicitly granted per-origin. - Permission descriptor type: defaults to
PermissionDescriptor(no additional aspects).
A remote desktop web client can feature-detect whether the user agent has been configured to allow the extension for its origin using the standard Permissions API:
const status = await navigator.permissions.query({
name: "publickey-credentials-remote-client-data-json",
});
if (status.state === "granted") {
// Proceed with the remoteClientDataJSON flow.
}The step numbered 1 in the Processing Steps section calls getting the current permission state for this feature; a state other than "granted" causes the WebAuthn call to reject with NotAllowedError.
User agents MUST only expose per-origin configuration mechanisms (enterprise policy, managed-profile policy, or per-origin user opt-in in client settings); a "permit all origins" switch is explicitly forbidden by the spec.
// Remote desktop web client at https://myrdc.example
const clientDataJSON = JSON.stringify({
type: "webauthn.create",
challenge: "SGVsbG8gV29ybGQ", // base64url-encoded challenge from the remote host
origin: "https://accounts.example.com",
crossOrigin: false,
});
const credential = await navigator.credentials.create({
publicKey: {
rp: { name: "Example Corp", id: "example.com" },
user: {
id: new Uint8Array([1, 2, 3, 4]),
name: "user@example.com",
displayName: "User",
},
challenge: new Uint8Array([/* challenge bytes */]),
pubKeyCredParams: [{ type: "public-key", alg: -7 }],
extensions: {
remoteClientDataJSON: clientDataJSON,
},
},
});
// credential.response.clientDataJSON contains the exact string
// provided above, enabling signature verification on the remote host.// Remote desktop web client at https://myrdc.example
const clientDataJSON = JSON.stringify({
type: "webauthn.get",
challenge: "dGVzdENoYWxsZW5nZQ",
origin: "https://accounts.example.com",
crossOrigin: false,
});
const assertion = await navigator.credentials.get({
publicKey: {
rpId: "example.com",
challenge: new Uint8Array([/* challenge bytes */]),
allowCredentials: [...],
extensions: {
remoteClientDataJSON: clientDataJSON,
},
},
});This extension requires explicit per-origin authorization. Three mechanisms are supported:
On managed devices, administrators configure the WebAuthnRemoteDesktopAllowedOrigins enterprise policy with a list of authorized origins. This is the recommended approach for enterprise deployments.
For personal or non-managed devices, users can enable WebAuthn remote desktop support via browser flags:
- Navigate to
chrome://flags#webauthn-remote-client-data-json. - Enter the authorized origin(s) (e.g.,
https://myrdc.example). - Restart the browser.
The flags page includes a standard warning about enabling experimental features and their potential security implications.
The approved spec PR integrates the extension with both the Permissions API and Permissions Policy. Once the spec is merged and published, sites can declare the extension via an HTTP header:
Permissions-Policy: publickey-credentials-remote-client-data-json=(self "https://myrdc.example")
Web-exposed feature detection is available via navigator.permissions.query({ name: "publickey-credentials-remote-client-data-json" }), which returns "granted" only when the calling origin has been authorized by one of the mechanisms above.
Per the spec, this configuration MUST remain per-origin: user agents are forbidden from offering a single toggle that permits the extension for all origins.
Adding more fields (e.g., challenge, type) to the existing remoteDesktopClientOverride extension to cover all clientDataJSON components.
Rejected because:
- 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.
- Future additions to
clientDataJSONwould require corresponding changes to the extension interface. - Does not guarantee byte-for-byte equivalence with the remote host's JSON, since the browser may serialize fields differently.
Allow the caller to provide only the SHA-256 hash of clientDataJSON, rather than the full string.
Rejected because:
- The relying party expects the full
clientDataJSONin the authentication response for verification. Providing only a hash would require a separate channel to transmit the full JSON. - The browser would lose the ability to validate the RP ID against the origin in the JSON, weakening the security model.
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.
The approved spec PR skips the usual "is the rpId a registrable domain suffix of the origin?" check on the local client. The registrable-domain-suffix test is instead the responsibility of the remote client, because only the remote side has the full context required: related origins, platform-specific app-deployment models (e.g., Android asset links, iOS associated domains), and the remote RP's allowed-origin configuration. Any user agent that grants this permission to an origin MUST therefore trust that origin to have performed RP ID validation honestly and correctly. This makes the per-origin authorization step (below) the primary defense.
User agents MUST NOT grant this permission globally. The spec requires that configuration mechanisms be per-origin, via either:
- Enterprise / managed-device / managed-profile policy, or
- Explicit per-origin user opt-in in user-agent settings (e.g., a browser flag with a per-origin allowlist).
A "permit all origins" option is explicitly forbidden. This is the load-bearing security boundary, since the local client no longer performs the registrable-domain-suffix check itself.
remoteDesktopClientOverride is not a standardized extension, so their interaction is a Chromium implementation detail. When both are present in a Chromium request, remoteClientDataJSON takes precedence. This is safe because remoteClientDataJSON is a strict superset of the functionality of remoteDesktopClientOverride, and the same authorization model applies.
This extension does not introduce new privacy concerns beyond those already present in a normal WebAuthn ceremony. The clientDataJSON string provided by the caller contains only the standard fields (type, challenge, origin, crossOrigin) that the browser would otherwise construct itself. No additional user data is exposed.
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.
Several points from earlier drafts of this explainer were resolved in the approved version of PR #2375:
-
Permission descriptor shape (RESOLVED): Earlier drafts proposed a custom
PermissionDescriptorsubtype. Per review feedback from @kreichgauer, the custom descriptor was dropped; the feature now uses the defaultPermissionDescriptortype, queried with{ name: "publickey-credentials-remote-client-data-json" }. -
Feature identifier naming (RESOLVED): The feature identifier
publickey-credentials-remote-client-data-jsonwas chosen, consistent with the existingpublickey-credentials-create/publickey-credentials-getPermissions Policy features. -
RP ID validation location (RESOLVED): The WG accepted the proposal that the local client delegates the registrable-domain-suffix check (and related-origin evaluation) to the remote client, because only the remote side has the full context (related origins, app-deployment-specific origin linking). This is reflected in the Processing Steps above.
-
remoteDesktopClientOriginoutput field (RESOLVED): The earlier draft returned aremoteDesktopClientOriginDOMString inAuthenticationExtensionsClientOutputs. Per review by @MasterKale, it was removed — the output is now just aboolean remoteClientDataJsonflag. The origin is already insideclientDataJSON, so echoing it in the output was redundant.
-
User communication: The spec recommends that user agents clearly communicate to users when a remote-desktop-proxied WebAuthn operation is in progress, so users understand their authenticator is being used on behalf of a remotely hosted RP. The exact form of this UI (indicator, prompt, chrome decoration) is left to user agents and is not yet defined.
-
Exception parity between
create()andget(): The current spec text throwsEncodingErroron JSON parse failure increate()butNotSupportedErroringet(). @emlun noted this may be tidied up in a follow-up editorial PR. -
End-to-end sequence diagram: @MasterKale contributed a sequence diagram illustrating a full passkey flow using the extension (remote browser → remote platform → RDP channel → local RDP web client → local browser → local authenticator). The diagram is likely to land either in the spec itself or in the associated explainer as a follow-up.
- W3C Web Authentication Level 3 Specification
- W3C WebAuthn PR #2375:
remoteClientDataJSONExtension - W3C WebAuthn Issue #1577: Remote Desktop Support
- W3C WebAuthn Wiki: Explainer -- Remote Desktop Support
- Chromium-only
remoteDesktopClientOverrideextension (not part of the W3C spec). Chromium CLs for that extension: