diff --git a/LayoutTests/http/tests/identity/allow-attribute.https-expected.txt b/LayoutTests/http/tests/identity/allow-attribute.https-expected.txt
new file mode 100644
index 0000000000000..29967b1b6e95b
--- /dev/null
+++ b/LayoutTests/http/tests/identity/allow-attribute.https-expected.txt
@@ -0,0 +1,13 @@
+PASS is allowed to call get()
+PASS is not allowed to call get()
+PASS is allowed to call get()
+PASS is allowed to call get()
+PASS is allowed to call get()
+PASS is allowed to call get()
+PASS is not allowed to call get()
+PASS is not allowed to call get()
+PASS is not allowed to call get()
+PASS is allowed to call get()
+PASS is allowed to call get()
+PASS is not allowed to call get()
+
diff --git a/LayoutTests/http/tests/identity/allow-attribute.https.html b/LayoutTests/http/tests/identity/allow-attribute.https.html
new file mode 100644
index 0000000000000..183d6b6769915
--- /dev/null
+++ b/LayoutTests/http/tests/identity/allow-attribute.https.html
@@ -0,0 +1,133 @@
+
+
+
+
+ Test allow attribute with "digital-credentials-get" and
+ CredentialsContainer's .get() method
+
+
+
+
+
+
diff --git a/LayoutTests/http/tests/identity/resources/iframe.html b/LayoutTests/http/tests/identity/resources/iframe.html
new file mode 100644
index 0000000000000..398f9ac4e7603
--- /dev/null
+++ b/LayoutTests/http/tests/identity/resources/iframe.html
@@ -0,0 +1,33 @@
+
+
+
+Digital Credentials API
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/default-permissions-policy.https.sub-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/default-permissions-policy.https.sub-expected.txt
new file mode 100644
index 0000000000000..4eb103f9c0c3f
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/default-permissions-policy.https.sub-expected.txt
@@ -0,0 +1,3 @@
+
+PASS Permissions-Policy is by default 'self'.
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/default-permissions-policy.https.sub.html b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/default-permissions-policy.https.sub.html
new file mode 100644
index 0000000000000..34a40bdcfe746
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/default-permissions-policy.https.sub.html
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/disabled-by-permissions-policy.https.sub-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/disabled-by-permissions-policy.https.sub-expected.txt
new file mode 100644
index 0000000000000..c9abd2a0657ad
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/disabled-by-permissions-policy.https.sub-expected.txt
@@ -0,0 +1,5 @@
+
+
+FAIL Permissions-Policy header digital-credentials-get=() disallows the top-level document. promise_rejects_dom: function "function() { throw e }" threw object "TypeError: At least one provider must be specified." that is not a DOMException NotAllowedError: property "code" is equal to undefined, expected 0
+FAIL Permissions-Policy header digital-credentials-get=() disallows same-origin iframes. assert_false: Digital Credential API expected false got true
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/disabled-by-permissions-policy.https.sub.html b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/disabled-by-permissions-policy.https.sub.html
new file mode 100644
index 0000000000000..65b58066349da
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/disabled-by-permissions-policy.https.sub.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/disabled-by-permissions-policy.https.sub.html.headers b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/disabled-by-permissions-policy.https.sub.html.headers
new file mode 100644
index 0000000000000..02a76b7c3f289
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/disabled-by-permissions-policy.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: digital-credentials-get=()
diff --git a/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/enabled-on-self-origin-by-permissions-policy.https.sub-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/enabled-on-self-origin-by-permissions-policy.https.sub-expected.txt
new file mode 100644
index 0000000000000..2a904d018e058
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/enabled-on-self-origin-by-permissions-policy.https.sub-expected.txt
@@ -0,0 +1,6 @@
+
+PASS Permissions-Policy header digital-credentials-get=(self) allows the top-level document.
+PASS Permissions-Policy header digital-credentials-get=(self) allows same-origin iframes.
+PASS Permissions-Policy header digital-credentials-get=(self) disallows cross-origin iframes.
+PASS Permissions-Policy header digital-credentials-get=(self) gets overridden by allow attribute.
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/enabled-on-self-origin-by-permissions-policy.https.sub.html b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/enabled-on-self-origin-by-permissions-policy.https.sub.html
new file mode 100644
index 0000000000000..019be25fa2d90
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/enabled-on-self-origin-by-permissions-policy.https.sub.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/enabled-on-self-origin-by-permissions-policy.https.sub.html.headers b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/enabled-on-self-origin-by-permissions-policy.https.sub.html.headers
new file mode 100644
index 0000000000000..1207d9e29a111
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/enabled-on-self-origin-by-permissions-policy.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: digital-credentials-get=(self)
diff --git a/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/override-permissions-policy.https.sub-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/override-permissions-policy.https.sub-expected.txt
new file mode 100644
index 0000000000000..889badd382c60
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/override-permissions-policy.https.sub-expected.txt
@@ -0,0 +1,5 @@
+
+
+PASS Header-set policy is overridden in cross-origin iframe using allow attribute.
+FAIL Setting digital-credentials-get=(self) disallows the API in same-origin iframes. assert_false: Digital Credential API expected false got true
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/override-permissions-policy.https.sub.html b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/override-permissions-policy.https.sub.html
new file mode 100644
index 0000000000000..393949f4116d2
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/override-permissions-policy.https.sub.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/override-permissions-policy.https.sub.html.headers b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/override-permissions-policy.https.sub.html.headers
new file mode 100644
index 0000000000000..02a76b7c3f289
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/digital-credentials/override-permissions-policy.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: digital-credentials-get=()
diff --git a/LayoutTests/imported/w3c/web-platform-tests/permissions-policy/resources/digital-credentials-get.html b/LayoutTests/imported/w3c/web-platform-tests/permissions-policy/resources/digital-credentials-get.html
new file mode 100644
index 0000000000000..4b212756c2291
--- /dev/null
+++ b/LayoutTests/imported/w3c/web-platform-tests/permissions-policy/resources/digital-credentials-get.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+ Digital Credentials iframe
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/permissions-policy/resources/permissions-policy.js b/LayoutTests/imported/w3c/web-platform-tests/permissions-policy/resources/permissions-policy.js
index d700cb086b362..cfc6d3caab103 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/permissions-policy/resources/permissions-policy.js
+++ b/LayoutTests/imported/w3c/web-platform-tests/permissions-policy/resources/permissions-policy.js
@@ -30,7 +30,7 @@ function assert_permissions_policy_supported() {
// promise. Used by test_feature_availability_with_post_message_result()
function test_feature_availability(
feature_descriptionOrObject, test, src, expect_feature_available, feature_name,
- allowfullscreen, is_promise_test = false) {
+ allowfullscreen, is_promise_test = false, needs_focus = false) {
if (feature_descriptionOrObject && feature_descriptionOrObject instanceof Object) {
const {
@@ -41,6 +41,7 @@ function test_feature_availability(
feature_name,
allowfullscreen,
is_promise_test,
+ needs_focus,
} = feature_descriptionOrObject;
return test_feature_availability(
feature_description,
@@ -49,7 +50,8 @@ function test_feature_availability(
expect_feature_available,
feature_name,
allowfullscreen,
- is_promise_test
+ is_promise_test,
+ needs_focus,
);
}
@@ -84,6 +86,9 @@ function test_feature_availability(
window.addEventListener('message', resolve);
}).then(expectFeatureAvailable);
document.body.appendChild(frame);
+ if (needs_focus) {
+ frame.focus();
+ }
return promise;
}
diff --git a/LayoutTests/platform/glib/TestExpectations b/LayoutTests/platform/glib/TestExpectations
index 08b1954dec2e1..b6ec8c2ff0c16 100644
--- a/LayoutTests/platform/glib/TestExpectations
+++ b/LayoutTests/platform/glib/TestExpectations
@@ -2805,6 +2805,7 @@ imported/w3c/web-platform-tests/credential-management/ [ Skip ]
# Digital Crendentials API
http/wpt/identity/ [ Skip ]
+http/tests/identity/ [ Skip ]
imported/w3c/web-platform-tests/digital-credentials/ [ Skip ]
# WebGL2
diff --git a/LayoutTests/platform/mac-site-isolation/TestExpectations b/LayoutTests/platform/mac-site-isolation/TestExpectations
index 44577274a23d9..2ae2f6e77f962 100644
--- a/LayoutTests/platform/mac-site-isolation/TestExpectations
+++ b/LayoutTests/platform/mac-site-isolation/TestExpectations
@@ -5195,6 +5195,7 @@ http/wpt/html/semantics/scripting-1/the-script-element/module/module-meta-url-re
http/wpt/html/semantics/scripting-1/the-script-element/module/module-meta-url-with-fragment.html [ Skip ]
http/wpt/html/semantics/text-level-semantics/the-a-element/a-download-click-404.html [ Skip ]
http/wpt/identity/identitycredentialscontainer-create-basics.https.html [ Skip ]
+http/tests/identity/allow-attribute.https.html [ Skip ]
http/wpt/identity/identitycredentialscontainer-get-basics.https.html [ Skip ]
http/wpt/identity/identitycredentialscontainer-store-basics.https.html [ Skip ]
http/wpt/identity/idl.https.html [ Skip ]
diff --git a/LayoutTests/platform/mac-wk1/TestExpectations b/LayoutTests/platform/mac-wk1/TestExpectations
index bf49b40b02eb9..b5a56d7993cd8 100644
--- a/LayoutTests/platform/mac-wk1/TestExpectations
+++ b/LayoutTests/platform/mac-wk1/TestExpectations
@@ -1822,6 +1822,7 @@ imported/w3c/web-platform-tests/credential-management/ [ Skip ]
# Skip Digital Credentials API
http/wpt/identity/ [ Skip ]
+http/tests/identity/ [ Skip ]
imported/w3c/web-platform-tests/digital-credentials/ [ Skip ]
webkit.org/b/182554 transitions/transition-display-property.html [ Pass ImageOnlyFailure ]
diff --git a/LayoutTests/platform/win/TestExpectations b/LayoutTests/platform/win/TestExpectations
index 680d1957c1b99..6ec62760c4128 100644
--- a/LayoutTests/platform/win/TestExpectations
+++ b/LayoutTests/platform/win/TestExpectations
@@ -1701,6 +1701,7 @@ http/wpt/css/css-highlight-api [ Skip ]
http/wpt/entries-api [ Skip ]
http/wpt/geometry [ Skip ]
http/wpt/identity [ Skip ]
+http/tests/identity [ Skip ]
http/wpt/loading/redirect-headers.html [ Skip ] # Failure
diff --git a/Source/WebCore/Modules/identity/IdentityCredentialsContainer.cpp b/Source/WebCore/Modules/identity/IdentityCredentialsContainer.cpp
index fd61ff72fc4f8..2eeed44c83ec2 100644
--- a/Source/WebCore/Modules/identity/IdentityCredentialsContainer.cpp
+++ b/Source/WebCore/Modules/identity/IdentityCredentialsContainer.cpp
@@ -51,6 +51,11 @@ void IdentityCredentialsContainer::get(CredentialRequestOptions&& options, Crede
return;
RefPtr document = this->document();
+ if (!PermissionsPolicy::isFeatureEnabled(PermissionsPolicy::Feature::DigitalCredentialsGetRule, *document, PermissionsPolicy::ShouldReportViolation::No)) {
+ promise.reject(Exception { ExceptionCode::NotAllowedError, "Third-party iframes are not allowed to call .get() unless explicitly allowed via Permissions Policy (digital-credentials-get)"_s });
+ return;
+ }
+
if (!document->hasFocus()) {
promise.reject(Exception { ExceptionCode::NotAllowedError, "The document is not focused."_s });
return;
diff --git a/Source/WebCore/html/PermissionsPolicy.cpp b/Source/WebCore/html/PermissionsPolicy.cpp
index 0d10bb914d774..ce3c0f64120e7 100644
--- a/Source/WebCore/html/PermissionsPolicy.cpp
+++ b/Source/WebCore/html/PermissionsPolicy.cpp
@@ -77,6 +77,8 @@ static ASCIILiteral toFeatureNameForLogging(PermissionsPolicy::Feature feature)
#if ENABLE(WEB_AUTHN)
case PermissionsPolicy::Feature::PublickeyCredentialsGetRule:
return "PublickeyCredentialsGet"_s;
+ case PermissionsPolicy::Feature::DigitalCredentialsGetRule:
+ return "DigitalCredentialsGet"_s;
#endif
#if ENABLE(WEBXR)
case PermissionsPolicy::Feature::XRSpatialTracking:
@@ -117,6 +119,7 @@ static std::pair readFeatureIdentifier(S
#endif
#if ENABLE(WEB_AUTHN)
constexpr auto publickeyCredentialsGetRuleToken { "publickey-credentials-get"_s };
+ constexpr auto digitalCredentialsGetRuleToken { "digital-credentials-get"_s };
#endif
#if ENABLE(WEBXR)
constexpr auto xrSpatialTrackingToken { "xr-spatial-tracking"_s };
@@ -171,6 +174,9 @@ static std::pair readFeatureIdentifier(S
} else if (value.startsWith(publickeyCredentialsGetRuleToken)) {
feature = PermissionsPolicy::Feature::PublickeyCredentialsGetRule;
remainingValue = value.substring(publickeyCredentialsGetRuleToken.length());
+ } else if (value.startsWith(digitalCredentialsGetRuleToken)) {
+ feature = PermissionsPolicy::Feature::DigitalCredentialsGetRule;
+ remainingValue = value.substring(digitalCredentialsGetRuleToken.length());
#endif
#if ENABLE(WEBXR)
} else if (value.startsWith(xrSpatialTrackingToken)) {
@@ -213,6 +219,7 @@ static ASCIILiteral defaultAllowlistValue(PermissionsPolicy::Feature feature)
#endif
#if ENABLE(WEB_AUTHN)
case PermissionsPolicy::Feature::PublickeyCredentialsGetRule:
+ case PermissionsPolicy::Feature::DigitalCredentialsGetRule:
#endif
#if ENABLE(WEBXR)
case PermissionsPolicy::Feature::XRSpatialTracking:
diff --git a/Source/WebCore/html/PermissionsPolicy.h b/Source/WebCore/html/PermissionsPolicy.h
index 331340b332068..577f8a2270878 100644
--- a/Source/WebCore/html/PermissionsPolicy.h
+++ b/Source/WebCore/html/PermissionsPolicy.h
@@ -63,6 +63,7 @@ class PermissionsPolicy {
#endif
#if ENABLE(WEB_AUTHN)
PublickeyCredentialsGetRule,
+ DigitalCredentialsGetRule,
#endif
#if ENABLE(WEBXR)
XRSpatialTracking,
diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
index 2553619355c0b..54bfa4555c6dd 100644
--- a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
+++ b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
@@ -8320,6 +8320,7 @@ struct WebCore::OwnerPermissionsPolicyData {
#endif
#if ENABLE(WEB_AUTHN)
PublickeyCredentialsGetRule,
+ DigitalCredentialsGetRule,
#endif
#if ENABLE(WEBXR)
XRSpatialTracking,