bug 1332681 - part 4/4 - convert authentication.getAssertion to credentials.get r=jcj,qdot
authorDavid Keeler <dkeeler@mozilla.com>
Tue, 23 May 2017 14:55:10 -0700
changeset 411409 3c876e859603f37750de4725546d2c1dddf05e31
parent 411408 3c0d57fec9e5bb5c6eb71389d62129d7f8a2baa8
child 411410 c4e74cfbf7e9d8e297e214478d25e3456f858cea
child 411411 bbdd2add81ecdb7340e604130e39f990f8129bd5
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjcj, qdot
bugs1332681
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 1332681 - part 4/4 - convert authentication.getAssertion to credentials.get r=jcj,qdot MozReview-Commit-ID: 13EqlQVQApx
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/credentialmanagement/CredentialsContainer.cpp
dom/credentialmanagement/CredentialsContainer.h
dom/webauthn/WebAuthentication.cpp
dom/webauthn/WebAuthentication.h
dom/webauthn/WebAuthnManager.cpp
dom/webauthn/WebAuthnManager.h
dom/webauthn/moz.build
dom/webauthn/tests/test_webauthn_get_assertion.html
dom/webauthn/tests/test_webauthn_loopback.html
dom/webauthn/tests/test_webauthn_make_credential.html
dom/webauthn/tests/test_webauthn_no_token.html
dom/webauthn/tests/test_webauthn_sameorigin.html
dom/webidl/CredentialManagement.webidl
dom/webidl/Navigator.webidl
dom/webidl/WebAuthentication.webidl
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -44,17 +44,16 @@
 #include "mozilla/dom/Presentation.h"
 #include "mozilla/dom/ServiceWorkerContainer.h"
 #include "mozilla/dom/StorageManager.h"
 #include "mozilla/dom/TCPSocket.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "mozilla/dom/VRDisplay.h"
 #include "mozilla/dom/VRDisplayEvent.h"
 #include "mozilla/dom/VRServiceTest.h"
-#include "mozilla/dom/WebAuthentication.h"
 #include "mozilla/dom/workers/RuntimeService.h"
 #include "mozilla/Hal.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/SSE.h"
 #include "mozilla/StaticPtr.h"
 #include "Connection.h"
 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
 #include "nsGlobalWindow.h"
@@ -201,17 +200,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAuthentication)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCredentials)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPresentation)
@@ -1998,25 +1996,16 @@ Navigator::GetPresentation(ErrorResult& 
       return nullptr;
     }
     mPresentation = Presentation::Create(mWindow);
   }
 
   return mPresentation;
 }
 
-WebAuthentication*
-Navigator::Authentication()
-{
-  if (!mAuthentication) {
-    mAuthentication = new WebAuthentication(GetWindow());
-  }
-  return mAuthentication;
-}
-
 CredentialsContainer*
 Navigator::Credentials()
 {
   if (!mCredentials) {
     mCredentials = new CredentialsContainer(GetWindow());
   }
   return mCredentials;
 }
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -37,17 +37,16 @@ class systemMessageCallback;
 class MediaDevices;
 struct MediaStreamConstraints;
 class WakeLock;
 class ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams;
 class ServiceWorkerContainer;
 class DOMRequest;
 struct FlyWebPublishOptions;
 struct FlyWebFilter;
-class WebAuthentication;
 class CredentialsContainer;
 } // namespace dom
 } // namespace mozilla
 
 //*****************************************************************************
 // Navigator: Script "navigator" object
 //*****************************************************************************
 
@@ -221,17 +220,16 @@ public:
                               MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
                               NavigatorUserMediaErrorCallback& aOnError,
                               uint64_t aInnerWindowID,
                               const nsAString& aCallID,
                               ErrorResult& aRv);
 
   already_AddRefed<ServiceWorkerContainer> ServiceWorker();
 
-  mozilla::dom::WebAuthentication* Authentication();
   mozilla::dom::CredentialsContainer* Credentials();
 
   void GetLanguages(nsTArray<nsString>& aLanguages);
 
   bool MozE10sEnabled();
 
   StorageManager* Storage();
 
@@ -291,17 +289,16 @@ private:
   RefPtr<nsPluginArray> mPlugins;
   RefPtr<Permissions> mPermissions;
   RefPtr<Geolocation> mGeolocation;
   RefPtr<DesktopNotificationCenter> mNotification;
   RefPtr<battery::BatteryManager> mBatteryManager;
   RefPtr<Promise> mBatteryPromise;
   RefPtr<PowerManager> mPowerManager;
   RefPtr<network::Connection> mConnection;
-  RefPtr<WebAuthentication> mAuthentication;
   RefPtr<CredentialsContainer> mCredentials;
   RefPtr<MediaDevices> mMediaDevices;
   RefPtr<time::TimeManager> mTimeManager;
   RefPtr<ServiceWorkerContainer> mServiceWorkerContainer;
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   RefPtr<Presentation> mPresentation;
   RefPtr<GamepadServiceTest> mGamepadServiceTest;
   nsTArray<RefPtr<Promise> > mVRGetDisplaysPromises;
--- a/dom/credentialmanagement/CredentialsContainer.cpp
+++ b/dom/credentialmanagement/CredentialsContainer.cpp
@@ -30,16 +30,24 @@ CredentialsContainer::~CredentialsContai
 
 JSObject*
 CredentialsContainer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return CredentialsContainerBinding::Wrap(aCx, this, aGivenProto);
 }
 
 already_AddRefed<Promise>
+CredentialsContainer::Get(const CredentialRequestOptions& aOptions)
+{
+  RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
+  MOZ_ASSERT(mgr);
+  return mgr->GetAssertion(mParent, aOptions.mPublicKey);
+}
+
+already_AddRefed<Promise>
 CredentialsContainer::Create(const CredentialCreationOptions& aOptions)
 {
   RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
   MOZ_ASSERT(mgr);
   return mgr->MakeCredential(mParent, aOptions.mPublicKey);
 }
 
 } // namespace dom
--- a/dom/credentialmanagement/CredentialsContainer.h
+++ b/dom/credentialmanagement/CredentialsContainer.h
@@ -26,16 +26,18 @@ public:
   {
     return mParent;
   }
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   already_AddRefed<Promise>
+  Get(const CredentialRequestOptions& aOptions);
+  already_AddRefed<Promise>
   Create(const CredentialCreationOptions& aOptions);
 
 private:
   ~CredentialsContainer();
 
   nsCOMPtr<nsPIDOMWindowInner> mParent;
 };
 
deleted file mode 100644
--- a/dom/webauthn/WebAuthentication.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "mozilla/dom/WebAuthentication.h"
-#include "mozilla/dom/WebAuthnManager.h"
-
-namespace mozilla {
-namespace dom {
-
-// Only needed for refcounted objects.
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebAuthentication, mParent)
-NS_IMPL_CYCLE_COLLECTING_ADDREF(WebAuthentication)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(WebAuthentication)
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebAuthentication)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-WebAuthentication::WebAuthentication(nsPIDOMWindowInner* aParent) :
-  mParent(aParent)
-{
-  MOZ_ASSERT(aParent);
-}
-
-WebAuthentication::~WebAuthentication()
-{}
-
-JSObject*
-WebAuthentication::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
-  return WebAuthenticationBinding::Wrap(aCx, this, aGivenProto);
-}
-
-already_AddRefed<Promise>
-WebAuthentication::GetAssertion(const ArrayBufferViewOrArrayBuffer& aChallenge,
-                                const AssertionOptions& aOptions)
-{
-  RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
-  MOZ_ASSERT(mgr);
-  return mgr->GetAssertion(mParent, aChallenge, aOptions);
-}
-
-} // namespace dom
-} // namespace mozilla
deleted file mode 100644
--- a/dom/webauthn/WebAuthentication.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et cindent: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_WebAuthentication_h
-#define mozilla_dom_WebAuthentication_h
-
-#include "mozilla/dom/WebAuthenticationBinding.h"
-
-namespace mozilla {
-namespace dom {
-
-struct Account;
-class ArrayBufferViewOrArrayBuffer;
-struct AssertionOptions;
-struct ScopedCredentialOptions;
-struct ScopedCredentialParameters;
-
-} // namespace dom
-} // namespace mozilla
-
-namespace mozilla {
-namespace dom {
-
-class WebAuthentication final : public nsISupports
-                              , public nsWrapperCache
-{
-public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebAuthentication)
-
-  explicit WebAuthentication(nsPIDOMWindowInner* aParent);
-
-  nsPIDOMWindowInner*
-  GetParentObject() const
-  {
-    return mParent;
-  }
-
-  virtual JSObject*
-  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-
-  already_AddRefed<Promise>
-  GetAssertion(const ArrayBufferViewOrArrayBuffer& assertionChallenge,
-               const AssertionOptions& options);
-private:
-  ~WebAuthentication();
-
-  already_AddRefed<Promise> CreatePromise();
-  nsresult GetOrigin(/*out*/ nsAString& aOrigin);
-
-  nsCOMPtr<nsPIDOMWindowInner> mParent;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_WebAuthentication_h
--- a/dom/webauthn/WebAuthnManager.cpp
+++ b/dom/webauthn/WebAuthnManager.cpp
@@ -451,18 +451,17 @@ void
 WebAuthnManager::StartSign() {
   if (mChild) {
     mChild->SendRequestSign(mInfo.ref());
   }
 }
 
 already_AddRefed<Promise>
 WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent,
-                              const ArrayBufferViewOrArrayBuffer& aChallenge,
-                              const AssertionOptions& aOptions)
+                              const PublicKeyCredentialRequestOptions& aOptions)
 {
   MOZ_ASSERT(aParent);
 
   MaybeClearTransaction();
 
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
 
   ErrorResult rv;
@@ -477,21 +476,21 @@ WebAuthnManager::GetAssertion(nsPIDOMWin
     promise->MaybeReject(rv);
     return promise.forget();
   }
 
   // If timeoutSeconds was specified, check if its value lies within a
   // reasonable range as defined by the platform and if not, correct it to the
   // closest value lying within that range.
 
-  double adjustedTimeout = 30.0;
-  if (aOptions.mTimeoutSeconds.WasPassed()) {
-    adjustedTimeout = aOptions.mTimeoutSeconds.Value();
-    adjustedTimeout = std::max(15.0, adjustedTimeout);
-    adjustedTimeout = std::min(120.0, adjustedTimeout);
+  uint32_t adjustedTimeout = 30000;
+  if (aOptions.mTimeout.WasPassed()) {
+    adjustedTimeout = aOptions.mTimeout.Value();
+    adjustedTimeout = std::max(15000u, adjustedTimeout);
+    adjustedTimeout = std::min(120000u, adjustedTimeout);
   }
 
   nsCString rpId;
   if (!aOptions.mRpId.WasPassed()) {
     // If rpId is not specified, then set rpId to callerOrigin, and rpIdHash to
     // the SHA-256 hash of rpId.
     rpId.Assign(NS_ConvertUTF16toUTF8(origin));
   } else {
@@ -529,17 +528,17 @@ WebAuthnManager::GetAssertion(nsPIDOMWin
     return promise.forget();
   }
 
   // Use assertionChallenge, callerOrigin and rpId, along with the token binding
   // key associated with callerOrigin (if any), to create a ClientData structure
   // representing this request. Choose a hash algorithm for hashAlg and compute
   // the clientDataJSON and clientDataHash.
   CryptoBuffer challenge;
-  if (!challenge.Assign(aChallenge)) {
+  if (!challenge.Assign(aOptions.mChallenge)) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
     return promise.forget();
   }
 
   nsAutoCString clientDataJSON;
   srv = AssembleClientData(origin, challenge, clientDataJSON);
   if (NS_WARN_IF(NS_FAILED(srv))) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
@@ -555,23 +554,23 @@ WebAuthnManager::GetAssertion(nsPIDOMWin
   srv = HashCString(hashService, clientDataJSON, clientDataHash);
   if (NS_WARN_IF(NS_FAILED(srv))) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
     return promise.forget();
   }
 
   // Note: we only support U2F-style authentication for now, so we effectively
   // require an AllowList.
-  if (!aOptions.mAllowList.WasPassed()) {
+  if (aOptions.mAllowList.Length() < 1) {
     promise->MaybeReject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
     return promise.forget();
   }
 
   nsTArray<WebAuthnScopedCredentialDescriptor> allowList;
-  for (const auto& s: aOptions.mAllowList.Value()) {
+  for (const auto& s: aOptions.mAllowList) {
     WebAuthnScopedCredentialDescriptor c;
     CryptoBuffer cb;
     cb.Assign(s.mId);
     c.id() = cb;
     allowList.AppendElement(c);
   }
 
   // TODO: Add extension list building
@@ -579,17 +578,17 @@ WebAuthnManager::GetAssertion(nsPIDOMWin
   // client platform, to produce the extension data that needs to be sent to the
   // authenticator. If an error is encountered while processing an extension,
   // skip that extension and do not produce any extension data for it. Call the
   // result of this processing clientExtensions.
   nsTArray<WebAuthnExtension> extensions;
 
   WebAuthnTransactionInfo info(rpIdHash,
                                clientDataHash,
-                               10000,
+                               adjustedTimeout,
                                allowList,
                                extensions);
   RefPtr<MozPromise<nsresult, nsresult, false>> p = GetOrCreateBackgroundActor();
   p->Then(AbstractThread::MainThread(), __func__,
           []() {
             WebAuthnManager* mgr = WebAuthnManager::Get();
             if (!mgr) {
               return;
--- a/dom/webauthn/WebAuthnManager.h
+++ b/dom/webauthn/WebAuthnManager.h
@@ -73,18 +73,17 @@ public:
   Cancel(const nsresult& aError);
 
   already_AddRefed<Promise>
   MakeCredential(nsPIDOMWindowInner* aParent,
                  const MakeCredentialOptions& aOptions);
 
   already_AddRefed<Promise>
   GetAssertion(nsPIDOMWindowInner* aParent,
-               const ArrayBufferViewOrArrayBuffer& aAssertionChallenge,
-               const AssertionOptions& aOptions);
+               const PublicKeyCredentialRequestOptions& aOptions);
 
   void StartRegister();
   void StartSign();
 
   // nsIIPCbackgroundChildCreateCallback methods
   void ActorCreated(PBackgroundChild* aActor) override;
   void ActorFailed() override;
   void ActorDestroyed();
--- a/dom/webauthn/moz.build
+++ b/dom/webauthn/moz.build
@@ -15,33 +15,31 @@ EXPORTS.mozilla.dom += [
     'AuthenticatorAssertionResponse.h',
     'AuthenticatorAttestationResponse.h',
     'AuthenticatorResponse.h',
     'NSSU2FTokenRemote.h',
     'PublicKeyCredential.h',
     'U2FSoftTokenManager.h',
     'U2FTokenManager.h',
     'U2FTokenTransport.h',
-    'WebAuthentication.h',
     'WebAuthnManager.h',
     'WebAuthnRequest.h',
     'WebAuthnTransactionChild.h',
     'WebAuthnTransactionParent.h',
     'WebAuthnUtil.h'
 ]
 
 UNIFIED_SOURCES += [
     'AuthenticatorAssertionResponse.cpp',
     'AuthenticatorAttestationResponse.cpp',
     'AuthenticatorResponse.cpp',
     'NSSU2FTokenRemote.cpp',
     'PublicKeyCredential.cpp',
     'U2FSoftTokenManager.cpp',
     'U2FTokenManager.cpp',
-    'WebAuthentication.cpp',
     'WebAuthnManager.cpp',
     'WebAuthnTransactionChild.cpp',
     'WebAuthnTransactionParent.cpp',
     'WebAuthnUtil.cpp'
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/dom/webauthn/tests/test_webauthn_get_assertion.html
+++ b/dom/webauthn/tests/test_webauthn_get_assertion.html
@@ -11,100 +11,119 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 
   <h1>Tests for GetAssertion for W3C Web Authentication</h1>
   <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1309284">Mozilla Bug 1309284</a>
 
   <script class="testbody" type="text/javascript">
-   "use strict";
-
-   // Execute the full-scope test
-   SimpleTest.waitForExplicitFinish();
+    "use strict";
 
-   function arrivingHereIsBad(aResult) {
-     ok(false, "Bad result! Received a: " + aResult);
-     return Promise.resolve();
-   }
+    // Execute the full-scope test
+    SimpleTest.waitForExplicitFinish();
 
-   function expectNotAllowedError(aResult) {
-     ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
-     return Promise.resolve();
-   }
+    function arrivingHereIsBad(aResult) {
+      ok(false, "Bad result! Received a: " + aResult);
+      return Promise.resolve();
+    }
 
-   function expectTypeError(aResult) {
-     ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
-     return Promise.resolve();
-   }
+    function expectNotAllowedError(aResult) {
+      ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
+      return Promise.resolve();
+    }
 
-   SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
-                                      ["security.webauth.webauthn_enable_softtoken", true],
-                                      ["security.webauth.webauthn_enable_usbtoken", false]]},
-                             runTests);
+    function expectTypeError(aResult) {
+      ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
+      return Promise.resolve();
+    }
+
+    SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
+                                       ["security.webauth.webauthn_enable_softtoken", true],
+                                       ["security.webauth.webauthn_enable_usbtoken", false]]},
+                              runTests);
 
-   function runTests() {
-     isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
-     isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
-     is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
-     isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
-     isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
+    function runTests() {
+      is(navigator.authentication, undefined, "navigator.authentication does not exist any longer");
+      isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
+      isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
+      isnot(navigator.credentials.get, undefined, "CredentialManagement get API endpoint must exist");
 
-     let authn = navigator.authentication;
+      let credm = navigator.credentials;
 
-     let gAssertionChallenge = new Uint8Array(16);
-     window.crypto.getRandomValues(gAssertionChallenge);
+      let gAssertionChallenge = new Uint8Array(16);
+      window.crypto.getRandomValues(gAssertionChallenge);
 
-     let invalidCred = { type: "Magic", id: base64ToBytes("AAA=") };
-     let unknownCred = { type: "ScopedCred", id: base64ToBytes("AAA=") };
+      let invalidCred = {type: "Magic", id: base64ToBytes("AAA=")};
+      let unknownCred = {type: "public-key", id: base64ToBytes("AAA=")};
 
-     var testFuncs = [
-       function () {
-         // Test basic good call, but without giving a credential so expect failures
-         // this is OK by the standard, but not supported by U2F-backed authenticators
-         // like the soft token in use here.
-         return authn.getAssertion(gAssertionChallenge)
-                     .then(arrivingHereIsBad)
-                     .catch(expectNotAllowedError);
-       },
-       function () {
-         // Test with an unexpected option
-         return authn.getAssertion(gAssertionChallenge, { unknownValue: "hi" })
-                     .then(arrivingHereIsBad)
-                     .catch(expectNotAllowedError);
-       },
-       function () {
-         // Test with an invalid credential
-         return authn.getAssertion(gAssertionChallenge, { allowList: [invalidCred] })
-                     .then(arrivingHereIsBad)
-                     .catch(expectTypeError);
-       },
-       function () {
-         // Test with an unknown credential
-         return authn.getAssertion(gAssertionChallenge, { allowList: [unknownCred] })
-                     .then(arrivingHereIsBad)
-                     .catch(expectNotAllowedError);
-       },
-       function () {
-         // Test with an unexpected option and an invalid credential
-         return authn.getAssertion(gAssertionChallenge, { unknownValue: "hi" })
-                     .then(arrivingHereIsBad)
-                     .catch(expectNotAllowedError);
-       }
-     ];
+      var testFuncs = [
+        function () {
+          // Test basic good call, but without giving a credential so expect failures
+          // this is OK by the standard, but not supported by U2F-backed authenticators
+          // like the soft token in use here.
+          let publicKeyCredentialRequestOptions = {
+            challenge: gAssertionChallenge
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectNotAllowedError);
+        },
+        function () {
+          // Test with an unexpected option
+          let publicKeyCredentialRequestOptions = {
+            challenge: gAssertionChallenge,
+            unknownValue: "hi"
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectNotAllowedError);
+        },
+        function () {
+          // Test with an invalid credential
+          let publicKeyCredentialRequestOptions = {
+            challenge: gAssertionChallenge,
+            allowList: [invalidCred]
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectTypeError);
+        },
+        function () {
+          // Test with an unknown credential
+          let publicKeyCredentialRequestOptions = {
+            challenge: gAssertionChallenge,
+            allowList: [unknownCred]
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectNotAllowedError);
+        },
+        function () {
+          // Test with an unexpected option and an invalid credential
+          let publicKeyCredentialRequestOptions = {
+            challenge: gAssertionChallenge,
+            unknownValue: "hi",
+            allowList: [invalidCred]
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectTypeError);
+        }
+      ];
 
-     var i = 0;
-     var runNextTest = () => {
-       if (i == testFuncs.length) {
-         SimpleTest.finish();
-         return;
-       }
-       testFuncs[i]().then(() => { runNextTest(); });
-       i = i + 1;
-     };
-     runNextTest();
+      var i = 0;
+      var runNextTest = () => {
+        if (i == testFuncs.length) {
+          SimpleTest.finish();
+          return;
+        }
+        testFuncs[i]().then(() => { runNextTest(); });
+        i = i + 1;
+      };
+      runNextTest();
 
-   }
+    }
 
   </script>
 
 </body>
 </html>
--- a/dom/webauthn/tests/test_webauthn_loopback.html
+++ b/dom/webauthn/tests/test_webauthn_loopback.html
@@ -20,23 +20,21 @@
 
 // Execute the full-scope test
 SimpleTest.waitForExplicitFinish();
 
 SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
                                    ["security.webauth.webauthn_enable_softtoken", true],
                                    ["security.webauth.webauthn_enable_usbtoken", false]]},
 function() {
-  isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
+  is(navigator.authentication, undefined, "navigator.authentication does not exist any longer");
   isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
-  is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
-  isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
   isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
+  isnot(navigator.credentials.get, undefined, "CredentialManagement get API endpoint must exist");
 
-  let authn = navigator.authentication;
   let credm = navigator.credentials;
 
   let gCredentialChallenge = new Uint8Array(16);
   window.crypto.getRandomValues(gCredentialChallenge);
   let gAssertionChallenge = new Uint8Array(16);
   window.crypto.getRandomValues(gAssertionChallenge);
 
   testMakeCredential();
@@ -145,24 +143,28 @@ function() {
     .catch(function(aReason) {
       ok(aReason.toString().startsWith("NotAllowedError"), "Expect NotAllowedError, got " + aReason);
       testAssertion(aCredInfo);
     });
   }
 
   function testAssertion(aCredInfo) {
     let newCredential = {
-      type: "ScopedCred",
+      type: "public-key",
       id: Uint8Array.from(aCredInfo.rawId),
       transports: ["usb"],
     }
 
-    let assertOptions = {rpId: document.origin, timeoutSeconds: 5,
-                         allowList: [newCredential]};
-    authn.getAssertion(gAssertionChallenge, assertOptions)
+    let publicKeyCredentialRequestOptions = {
+      challenge: gAssertionChallenge,
+      timeout: 5000, // the minimum timeout is actually 15 seconds
+      rpId: document.origin,
+      allowList: [newCredential]
+    };
+    credm.get({publicKey: publicKeyCredentialRequestOptions})
     .then(function(aAssertion) {
       /* Pass along the pubKey. */
       return checkAssertionAndSigValid(aCredInfo.u2fReg.publicKey, aAssertion);
     })
     .then(function(aSigVerifyResult) {
       ok(aSigVerifyResult, "Signing signature verified");
       SimpleTest.finish();
     })
--- a/dom/webauthn/tests/test_webauthn_make_credential.html
+++ b/dom/webauthn/tests/test_webauthn_make_credential.html
@@ -45,23 +45,21 @@
       ok(aResult.toString().startsWith("NotSupportedError"), "Expecting a NotSupportedError");
       return Promise.resolve();
     }
 
     SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
                                        ["security.webauth.webauthn_enable_softtoken", true],
                                        ["security.webauth.webauthn_enable_usbtoken", false]]}, runTests);
     function runTests() {
-      isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
+      is(navigator.authentication, undefined, "navigator.authentication does not exist any longer");
       isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
-      is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
-      isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
       isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
+      isnot(navigator.credentials.get, undefined, "CredentialManagement get API endpoint must exist");
 
-      let authn = navigator.authentication;
       let credm = navigator.credentials;
 
       let gCredentialChallenge = new Uint8Array(16);
       window.crypto.getRandomValues(gCredentialChallenge);
 
       let rp = {id: "none", name: "none", icon: "none"};
       let user = {id: "none", name: "none", icon: "none", displayName: "none"};
       let param = {type: "public-key", algorithm: "p-256"};
--- a/dom/webauthn/tests/test_webauthn_no_token.html
+++ b/dom/webauthn/tests/test_webauthn_no_token.html
@@ -21,23 +21,21 @@
 // Execute the full-scope test
 SimpleTest.waitForExplicitFinish();
 
 // Turn off all tokens. This should result in "not allowed" failures
 SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
                                    ["security.webauth.webauthn_enable_softtoken", false],
                                    ["security.webauth.webauthn_enable_usbtoken", false]]},
 function() {
-  isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
+  is(navigator.authentication, undefined, "navigator.authentication does not exist any longer");
   isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
-  is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
-  isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
   isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
+  isnot(navigator.credentials.get, undefined, "CredentialManagement get API endpoint must exist");
 
-  let authn = navigator.authentication;
   let credm = navigator.credentials;
 
   let credentialChallenge = new Uint8Array(16);
   window.crypto.getRandomValues(credentialChallenge);
   let assertionChallenge = new Uint8Array(16);
   window.crypto.getRandomValues(assertionChallenge);
   let credentialId = new Uint8Array(128);
   window.crypto.getRandomValues(credentialId);
@@ -59,23 +57,27 @@ function() {
     .catch(function(aReason) {
       ok(aReason.toString().startsWith("NotAllowedError"), aReason);
       testAssertion();
     });
   }
 
   function testAssertion() {
     let newCredential = {
-      type: "ScopedCred",
+      type: "public-key",
       id: credentialId,
       transports: ["usb"],
     }
-    let assertOptions = {rpId: document.origin, timeoutSeconds: 5,
-                         allowList: [newCredential]};
-    authn.getAssertion(assertionChallenge, assertOptions)
+    let publicKeyCredentialRequestOptions = {
+      challenge: assertionChallenge,
+      timeout: 5000, // the minimum timeout is actually 15 seconds
+      rpId: document.origin,
+      allowList: [newCredential]
+    };
+    credm.get({publicKey: publicKeyCredentialRequestOptions})
     .then(function(aResult) {
       ok(false, "Should have failed.");
       SimpleTest.finish();
     })
     .catch(function(aReason) {
       ok(aReason.toString().startsWith("NotAllowedError"), aReason);
       SimpleTest.finish();
     })
--- a/dom/webauthn/tests/test_webauthn_sameorigin.html
+++ b/dom/webauthn/tests/test_webauthn_sameorigin.html
@@ -37,31 +37,29 @@
     function expectSecurityError(aResult) {
       // TODO: Change to `ok` when Bug 1329764 lands
       todo(aResult.toString().startsWith("SecurityError"), "Expecting a SecurityError");
       return Promise.resolve();
     }
 
     function keepThisPublicKeyCredential(aPublicKeyCredential) {
       gTrackedCredential = {
-        type: "ScopedCred",
+        type: "public-key",
         id: Uint8Array.from(aPublicKeyCredential.rawId),
         transports: [ "usb" ],
       }
       return Promise.resolve(aPublicKeyCredential);
     }
 
     function runTests() {
-      isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
+      is(navigator.authentication, undefined, "navigator.authentication does not exist any longer");
       isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
-      is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
-      isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
       isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
+      isnot(navigator.credentials.get, undefined, "CredentialManagement get API endpoint must exist");
 
-      let authn = navigator.authentication;
       let credm = navigator.credentials;
 
       let chall = new Uint8Array(16);
       window.crypto.getRandomValues(chall);
 
       let user = {id: "none", name: "none", icon: "none", displayName: "none"};
       let param = {type: "public-key", algorithm: "p-256"};
 
@@ -134,59 +132,87 @@
             rp: rp, user: user, challenge: chall, parameters: [param]
           };
           return credm.create({publicKey: makeCredentialOptions})
                       .then(arrivingHereIsBad)
                       .catch(expectSecurityError);
         },
         function () {
           // Test basic good call
-          return authn.getAssertion(chall, {allowList: [gTrackedCredential],
-                                            rpId: document.origin})
+          let publicKeyCredentialRequestOptions = {
+            challenge: chall,
+            rpId: document.origin,
+            allowList: [gTrackedCredential]
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
                       .then(arrivingHereIsGood)
                       .catch(arrivingHereIsBad);
         },
         function () {
           // Test rpId being unset
-          return authn.getAssertion(chall, {allowList: [gTrackedCredential]})
+          let publicKeyCredentialRequestOptions = {
+            challenge: chall,
+            allowList: [gTrackedCredential]
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
                       .then(arrivingHereIsGood)
                       .catch(arrivingHereIsBad);
         },
         function () {
           // Test this origin with optional fields
-          return authn.getAssertion(chall, {allowList: [gTrackedCredential],
-                                            rpId: "user:pass@" + document.origin + ":8888"})
+          let publicKeyCredentialRequestOptions = {
+            challenge: chall,
+            rpId: "user:pass@" + document.origin + ":8888",
+            allowList: [gTrackedCredential]
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
                       .then(arrivingHereIsBad)
                       .catch(expectSecurityError);
         },
         function () {
           // Test blank rpId
-          return authn.getAssertion(chall, {allowList: [gTrackedCredential],
-                                            rpId: ""})
+          let publicKeyCredentialRequestOptions = {
+            challenge: chall,
+            rpId: "",
+            allowList: [gTrackedCredential]
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
                       .then(arrivingHereIsBad)
                       .catch(expectSecurityError);
         },
         function () {
           // Test subdomain of this origin
-          return authn.getAssertion(chall, {allowList: [gTrackedCredential],
-                                            rpId: "subdomain." + document.origin})
+          let publicKeyCredentialRequestOptions = {
+            challenge: chall,
+            rpId: "subdomain." + document.origin,
+            allowList: [gTrackedCredential]
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
                       .then(arrivingHereIsBad)
                       .catch(expectSecurityError);
         },
         function () {
           // Test another origin
-          return authn.getAssertion(chall, {allowList: [gTrackedCredential],
-                                            rpId: "example.com"})
+          let publicKeyCredentialRequestOptions = {
+            challenge: chall,
+            rpId: "example.com",
+            allowList: [gTrackedCredential]
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
                       .then(arrivingHereIsBad)
                       .catch(expectSecurityError);
         },
         function () {
           // Test a different domain within the same TLD
-          return authn.getAssertion(chall, {allowList: [gTrackedCredential],
-                                            rpId: "alt.test"})
+          let publicKeyCredentialRequestOptions = {
+            challenge: chall,
+            rpId: "alt.test",
+            allowList: [gTrackedCredential]
+          };
+          return credm.get({publicKey: publicKeyCredentialRequestOptions})
                       .then(arrivingHereIsBad)
                       .catch(expectSecurityError)
         },
         function () {
           SimpleTest.finish();
         }
       ];
       var i = 0;
--- a/dom/webidl/CredentialManagement.webidl
+++ b/dom/webidl/CredentialManagement.webidl
@@ -10,14 +10,19 @@
 [Exposed=Window, SecureContext, Pref="security.webauth.webauthn"]
 interface Credential {
   readonly attribute USVString id;
   readonly attribute DOMString type;
 };
 
 [Exposed=Window, SecureContext, Pref="security.webauth.webauthn"]
 interface CredentialsContainer {
+  Promise<Credential?> get(optional CredentialRequestOptions options);
   Promise<Credential?> create(optional CredentialCreationOptions options);
 };
 
+dictionary CredentialRequestOptions {
+  PublicKeyCredentialRequestOptions publicKey;
+};
+
 dictionary CredentialCreationOptions {
   MakeCredentialOptions publicKey;
 };
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -366,15 +366,10 @@ partial interface Navigator {
 
 [NoInterfaceObject, Exposed=(Window,Worker)]
 interface NavigatorConcurrentHardware {
   readonly attribute unsigned long long hardwareConcurrency;
 };
 
 partial interface Navigator {
   [Pref="security.webauth.webauthn", SameObject]
-  readonly attribute WebAuthentication authentication;
-};
-
-partial interface Navigator {
-  [Pref="security.webauth.webauthn", SameObject]
   readonly attribute CredentialsContainer credentials;
 };
--- a/dom/webidl/WebAuthentication.webidl
+++ b/dom/webidl/WebAuthentication.webidl
@@ -61,16 +61,25 @@ dictionary AuthenticatorSelectionCriteri
     boolean       requireResidentKey = false;
 };
 
 enum Attachment {
     "platform",
     "cross-platform"
 };
 
+dictionary PublicKeyCredentialRequestOptions {
+    required BufferSource                challenge;
+    unsigned long                        timeout;
+    USVString                            rpId;
+    sequence<PublicKeyCredentialDescriptor> allowList = [];
+    // Extensions are not supported yet.
+    // AuthenticationExtensions             extensions;
+};
+
 dictionary CollectedClientData {
     required DOMString           challenge;
     required DOMString           origin;
     required DOMString           hashAlg;
     DOMString                    tokenBinding;
     // Extensions are not supported yet.
     // AuthenticationExtensions     clientExtensions;
     // AuthenticationExtensions     authenticatorExtensions;
@@ -89,44 +98,14 @@ dictionary PublicKeyCredentialDescriptor
 typedef (boolean or DOMString) WebAuthnAlgorithmID; // Fix when upstream there's a definition of how to serialize AlgorithmIdentifier
 
 [SecureContext, Pref="security.webauth.webauthn"]
 interface AuthenticatorAssertionResponse : AuthenticatorResponse {
     readonly attribute ArrayBuffer      authenticatorData;
     readonly attribute ArrayBuffer      signature;
 };
 
-dictionary AssertionOptions {
-    unsigned long                        timeoutSeconds;
-    USVString                            rpId;
-    sequence<ScopedCredentialDescriptor> allowList;
-    WebAuthnExtensions                   extensions;
-};
-
-dictionary WebAuthnExtensions {
-};
-
-enum ScopedCredentialType {
-    "ScopedCred"
-};
-
-dictionary ScopedCredentialDescriptor {
-    required ScopedCredentialType type;
-    required BufferSource         id;
-    sequence <WebAuthnTransport>  transports;
-};
-
 // Renamed from "Transport" to avoid a collision with U2F
 enum WebAuthnTransport {
     "usb",
     "nfc",
     "ble"
 };
-
-/***** The Main API *****/
-
-[SecureContext, Pref="security.webauth.webauthn"]
-interface WebAuthentication {
-    Promise<PublicKeyCredential> getAssertion (
-        BufferSource               assertionChallenge,
-        optional AssertionOptions  options
-    );
-};