bug 1332681 - part 3/4 - convert authentication.makeCredential to credentials.create r?jcj,qdot draft
authorDavid Keeler <dkeeler@mozilla.com>
Mon, 22 May 2017 17:09:49 -0700
changeset 590356 7524671e6792ce63d9d290bd42c0a1851d4771b8
parent 590355 3c949f2f4523aea3d2cb474ddfa9bbea88eb6571
child 590357 ce53b9d5851576ad00dbf752e9207b68bd0151a4
push id62720
push userbmo:dkeeler@mozilla.com
push dateWed, 07 Jun 2017 18:21:33 +0000
reviewersjcj, qdot
bugs1332681
milestone55.0a1
bug 1332681 - part 3/4 - convert authentication.makeCredential to credentials.create r?jcj,qdot MozReview-Commit-ID: 1xfsQqGCEcl
dom/base/Navigator.cpp
dom/base/Navigator.h
dom/credentialmanagement/CredentialsContainer.cpp
dom/credentialmanagement/CredentialsContainer.h
dom/credentialmanagement/moz.build
dom/webauthn/PWebAuthnTransaction.ipdl
dom/webauthn/ScopedCredential.cpp
dom/webauthn/ScopedCredential.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
@@ -28,16 +28,17 @@
 #include "nsICookiePermission.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsContentUtils.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "BatteryManager.h"
+#include "mozilla/dom/CredentialsContainer.h"
 #include "mozilla/dom/GamepadServiceTest.h"
 #include "mozilla/dom/PowerManager.h"
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/FlyWebPublishedServer.h"
 #include "mozilla/dom/FlyWebService.h"
 #include "mozilla/dom/Permissions.h"
 #include "mozilla/dom/Presentation.h"
@@ -201,16 +202,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   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)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepadServiceTest)
@@ -2005,10 +2007,19 @@ WebAuthentication*
 Navigator::Authentication()
 {
   if (!mAuthentication) {
     mAuthentication = new WebAuthentication(GetWindow());
   }
   return mAuthentication;
 }
 
+CredentialsContainer*
+Navigator::Credentials()
+{
+  if (!mCredentials) {
+    mCredentials = new CredentialsContainer(GetWindow());
+  }
+  return mCredentials;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -38,16 +38,17 @@ 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
 //*****************************************************************************
 
 namespace mozilla {
@@ -221,16 +222,17 @@ public:
                               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();
 
   static void GetAcceptLanguages(nsTArray<nsString>& aLanguages);
@@ -290,16 +292,17 @@ private:
   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;
   RefPtr<VRServiceTest> mVRServiceTest;
copy from dom/webauthn/WebAuthentication.cpp
copy to dom/credentialmanagement/CredentialsContainer.cpp
--- a/dom/webauthn/WebAuthentication.cpp
+++ b/dom/credentialmanagement/CredentialsContainer.cpp
@@ -1,58 +1,46 @@
 /* -*- 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/CredentialsContainer.h"
+#include "mozilla/dom/Promise.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_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CredentialsContainer, mParent)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(CredentialsContainer)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(CredentialsContainer)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CredentialsContainer)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-WebAuthentication::WebAuthentication(nsPIDOMWindowInner* aParent) :
+CredentialsContainer::CredentialsContainer(nsPIDOMWindowInner* aParent) :
   mParent(aParent)
 {
   MOZ_ASSERT(aParent);
 }
 
-WebAuthentication::~WebAuthentication()
+CredentialsContainer::~CredentialsContainer()
 {}
 
 JSObject*
-WebAuthentication::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+CredentialsContainer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
-  return WebAuthenticationBinding::Wrap(aCx, this, aGivenProto);
+  return CredentialsContainerBinding::Wrap(aCx, this, aGivenProto);
 }
 
 already_AddRefed<Promise>
-WebAuthentication::MakeCredential(JSContext* aCx, const Account& aAccount,
-                                  const Sequence<ScopedCredentialParameters>& aCryptoParameters,
-                                  const ArrayBufferViewOrArrayBuffer& aChallenge,
-                                  const ScopedCredentialOptions& aOptions)
+CredentialsContainer::Create(const CredentialCreationOptions& aOptions)
 {
   RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
   MOZ_ASSERT(mgr);
-  return mgr->MakeCredential(mParent, aCx, aAccount, aCryptoParameters, aChallenge, aOptions);
-}
-
-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);
+  return mgr->MakeCredential(mParent, aOptions.mPublicKey);
 }
 
 } // namespace dom
 } // namespace mozilla
copy from dom/webauthn/WebAuthentication.h
copy to dom/credentialmanagement/CredentialsContainer.h
--- a/dom/webauthn/WebAuthentication.h
+++ b/dom/credentialmanagement/CredentialsContainer.h
@@ -1,66 +1,45 @@
 /* -*- 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
+#ifndef mozilla_dom_CredentialsContainer_h
+#define mozilla_dom_CredentialsContainer_h
 
-#include "mozilla/dom/WebAuthenticationBinding.h"
+#include "mozilla/dom/CredentialManagementBinding.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
+class CredentialsContainer final : public nsISupports
+                                 , public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebAuthentication)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CredentialsContainer)
 
-  explicit WebAuthentication(nsPIDOMWindowInner* aParent);
+  explicit CredentialsContainer(nsPIDOMWindowInner* aParent);
 
   nsPIDOMWindowInner*
   GetParentObject() const
   {
     return mParent;
   }
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   already_AddRefed<Promise>
-  MakeCredential(JSContext* aCx, const Account& accountInformation,
-                 const Sequence<ScopedCredentialParameters>& cryptoParameters,
-                 const ArrayBufferViewOrArrayBuffer& attestationChallenge,
-                 const ScopedCredentialOptions& options);
+  Create(const CredentialCreationOptions& aOptions);
 
-  already_AddRefed<Promise>
-  GetAssertion(const ArrayBufferViewOrArrayBuffer& assertionChallenge,
-               const AssertionOptions& options);
 private:
-  ~WebAuthentication();
-
-  already_AddRefed<Promise> CreatePromise();
-  nsresult GetOrigin(/*out*/ nsAString& aOrigin);
+  ~CredentialsContainer();
 
   nsCOMPtr<nsPIDOMWindowInner> mParent;
 };
 
 } // namespace dom
 } // namespace mozilla
 
-#endif // mozilla_dom_WebAuthentication_h
+#endif // mozilla_dom_CredentialsContainer_h
--- a/dom/credentialmanagement/moz.build
+++ b/dom/credentialmanagement/moz.build
@@ -4,15 +4,19 @@
 # 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/.
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "DOM: Device Interfaces")
 
 EXPORTS.mozilla.dom += [
     'Credential.h',
+    'CredentialsContainer.h',
 ]
 
 UNIFIED_SOURCES += [
     'Credential.cpp',
+    'CredentialsContainer.cpp',
 ]
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 FINAL_LIBRARY = 'xul'
--- a/dom/webauthn/PWebAuthnTransaction.ipdl
+++ b/dom/webauthn/PWebAuthnTransaction.ipdl
@@ -15,21 +15,17 @@
  */
 
 include protocol PBackground;
 
 namespace mozilla {
 namespace dom {
 
 struct WebAuthnScopedCredentialDescriptor {
-  // Converted from mozilla::dom::ScopedCredentialType enum
-  uint32_t type;
   uint8_t[] id;
-  // Converted from mozilla::dom::WebAuthnTransport enum
-  uint32_t[] transports;
 };
 
 struct WebAuthnExtension {
   /* TODO Fill in with predefined extensions */
 };
 
 struct WebAuthnTransactionInfo {
   uint8_t[] RpIdHash;
deleted file mode 100644
--- a/dom/webauthn/ScopedCredential.cpp
+++ /dev/null
@@ -1,66 +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/ScopedCredential.h"
-#include "mozilla/dom/WebAuthenticationBinding.h"
-
-namespace mozilla {
-namespace dom {
-
-// Only needed for refcounted objects.
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ScopedCredential, mParent)
-NS_IMPL_CYCLE_COLLECTING_ADDREF(ScopedCredential)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(ScopedCredential)
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScopedCredential)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
-
-ScopedCredential::ScopedCredential(nsPIDOMWindowInner* aParent)
-  : mParent(aParent)
-  , mType(ScopedCredentialType::ScopedCred)
-{}
-
-ScopedCredential::~ScopedCredential()
-{}
-
-JSObject*
-ScopedCredential::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
-  return ScopedCredentialBinding::Wrap(aCx, this, aGivenProto);
-}
-
-ScopedCredentialType
-ScopedCredential::Type() const
-{
-  return mType;
-}
-
-void
-ScopedCredential::GetId(JSContext* aCx,
-                        JS::MutableHandle<JSObject*> aRetVal) const
-{
-  aRetVal.set(mIdBuffer.ToUint8Array(aCx));
-}
-
-nsresult
-ScopedCredential::SetType(ScopedCredentialType aType)
-{
-  mType = aType;
-  return NS_OK;
-}
-
-nsresult
-ScopedCredential::SetId(CryptoBuffer& aBuffer)
-{
-  if (!mIdBuffer.Assign(aBuffer)) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  return NS_OK;
-}
-
-} // namespace dom
-} // namespace mozilla
deleted file mode 100644
--- a/dom/webauthn/ScopedCredential.h
+++ /dev/null
@@ -1,66 +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_ScopedCredential_h
-#define mozilla_dom_ScopedCredential_h
-
-#include "js/TypeDecls.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/ErrorResult.h"
-#include "mozilla/dom/BindingDeclarations.h"
-#include "mozilla/dom/CryptoBuffer.h"
-#include "mozilla/dom/WebAuthenticationBinding.h"
-#include "nsCycleCollectionParticipant.h"
-#include "nsWrapperCache.h"
-
-namespace mozilla {
-namespace dom {
-
-class ScopedCredential final : public nsISupports
-                             , public nsWrapperCache
-{
-public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ScopedCredential)
-
-public:
-  explicit ScopedCredential(nsPIDOMWindowInner* aParent);
-
-protected:
-  ~ScopedCredential();
-
-public:
-  nsISupports*
-  GetParentObject() const
-  {
-    return mParent;
-  }
-
-  virtual JSObject*
-  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-
-  ScopedCredentialType
-  Type() const;
-
-  void
-  GetId(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal) const;
-
-  nsresult
-  SetType(ScopedCredentialType aType);
-
-  nsresult
-  SetId(CryptoBuffer& aBuffer);
-
-private:
-  nsCOMPtr<nsPIDOMWindowInner> mParent;
-  CryptoBuffer mIdBuffer;
-  ScopedCredentialType mType;
-};
-
-} // namespace dom
-} // namespace mozilla
-
-#endif // mozilla_dom_ScopedCredential_h
--- a/dom/webauthn/WebAuthentication.cpp
+++ b/dom/webauthn/WebAuthentication.cpp
@@ -30,27 +30,16 @@ WebAuthentication::~WebAuthentication()
 
 JSObject*
 WebAuthentication::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return WebAuthenticationBinding::Wrap(aCx, this, aGivenProto);
 }
 
 already_AddRefed<Promise>
-WebAuthentication::MakeCredential(JSContext* aCx, const Account& aAccount,
-                                  const Sequence<ScopedCredentialParameters>& aCryptoParameters,
-                                  const ArrayBufferViewOrArrayBuffer& aChallenge,
-                                  const ScopedCredentialOptions& aOptions)
-{
-  RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
-  MOZ_ASSERT(mgr);
-  return mgr->MakeCredential(mParent, aCx, aAccount, aCryptoParameters, aChallenge, aOptions);
-}
-
-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);
 }
 
--- a/dom/webauthn/WebAuthentication.h
+++ b/dom/webauthn/WebAuthentication.h
@@ -38,22 +38,16 @@ public:
   {
     return mParent;
   }
 
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   already_AddRefed<Promise>
-  MakeCredential(JSContext* aCx, const Account& accountInformation,
-                 const Sequence<ScopedCredentialParameters>& cryptoParameters,
-                 const ArrayBufferViewOrArrayBuffer& attestationChallenge,
-                 const ScopedCredentialOptions& options);
-
-  already_AddRefed<Promise>
   GetAssertion(const ArrayBufferViewOrArrayBuffer& assertionChallenge,
                const AssertionOptions& options);
 private:
   ~WebAuthentication();
 
   already_AddRefed<Promise> CreatePromise();
   nsresult GetOrigin(/*out*/ nsAString& aOrigin);
 
--- a/dom/webauthn/WebAuthnManager.cpp
+++ b/dom/webauthn/WebAuthnManager.cpp
@@ -35,17 +35,17 @@ static mozilla::LazyLogModule gWebAuthnM
 NS_IMPL_ISUPPORTS(WebAuthnManager, nsIIPCBackgroundChildCreateCallback);
 
 /***********************************************************************
  * Utility Functions
  **********************************************************************/
 
 template<class OOS>
 static nsresult
-GetAlgorithmName(JSContext* aCx, const OOS& aAlgorithm,
+GetAlgorithmName(const OOS& aAlgorithm,
                  /* out */ nsString& aName)
 {
   MOZ_ASSERT(aAlgorithm.IsString()); // TODO: remove assertion when we coerce.
 
   if (aAlgorithm.IsString()) {
     // If string, then treat as algorithm name
     aName.Assign(aAlgorithm.GetAsString());
   } else {
@@ -95,20 +95,20 @@ AssembleClientData(const nsAString& aOri
   MOZ_ASSERT(NS_IsMainThread());
 
   nsString challengeBase64;
   nsresult rv = aChallenge.ToJwkBase64(challengeBase64);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return NS_ERROR_FAILURE;
   }
 
-  WebAuthnClientData clientDataObject;
+  CollectedClientData clientDataObject;
+  clientDataObject.mChallenge.Assign(challengeBase64);
   clientDataObject.mOrigin.Assign(aOrigin);
-  clientDataObject.mHashAlg.SetAsString().Assign(NS_LITERAL_STRING("S256"));
-  clientDataObject.mChallenge.Assign(challengeBase64);
+  clientDataObject.mHashAlg.Assign(NS_LITERAL_STRING("S256"));
 
   nsAutoString temp;
   if (NS_WARN_IF(!clientDataObject.ToJSON(temp))) {
     return NS_ERROR_FAILURE;
   }
 
   aJsonOut.Assign(NS_ConvertUTF16toUTF8(temp));
   return NS_OK;
@@ -210,21 +210,18 @@ WebAuthnManager::GetOrCreate()
 WebAuthnManager*
 WebAuthnManager::Get()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return gWebAuthnManager;
 }
 
 already_AddRefed<Promise>
-WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
-                                const Account& aAccountInformation,
-                                const Sequence<ScopedCredentialParameters>& aCryptoParameters,
-                                const ArrayBufferViewOrArrayBuffer& aChallenge,
-                                const ScopedCredentialOptions& aOptions)
+WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent,
+                                const MakeCredentialOptions& aOptions)
 {
   MOZ_ASSERT(aParent);
 
   MaybeClearTransaction();
 
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aParent);
 
   ErrorResult rv;
@@ -240,37 +237,37 @@ WebAuthnManager::MakeCredential(nsPIDOMW
     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();
+  if (aOptions.mTimeout.WasPassed()) {
+    adjustedTimeout = aOptions.mTimeout.Value();
     adjustedTimeout = std::max(15.0, adjustedTimeout);
     adjustedTimeout = std::min(120.0, adjustedTimeout);
   }
 
   nsCString rpId;
-  if (!aOptions.mRpId.WasPassed()) {
-    // If rpId is not specified, then set rpId to callerOrigin, and rpIdHash to
+  if (!aOptions.mRp.mId.WasPassed()) {
+    // If rp.id is not specified, then set rpId to callerOrigin, and rpIdHash to
     // the SHA-256 hash of rpId.
     rpId.Assign(NS_ConvertUTF16toUTF8(origin));
   } else {
     // If rpId is specified, then invoke the procedure used for relaxing the
     // same-origin restriction by setting the document.domain attribute, using
     // rpId as the given value but without changing the current document’s
     // domain. If no errors are thrown, set rpId to the value of host as
     // computed by this procedure, and rpIdHash to the SHA-256 hash of rpId.
     // Otherwise, reject promise with a DOMException whose name is
     // "SecurityError", and terminate this algorithm.
 
-    if (NS_FAILED(RelaxSameOrigin(aParent, aOptions.mRpId.Value(), rpId))) {
+    if (NS_FAILED(RelaxSameOrigin(aParent, aOptions.mRp.mId.Value(), rpId))) {
       promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
       return promise.forget();
     }
   }
 
   CryptoBuffer rpIdHash;
   if (!rpIdHash.SetLength(SHA256_LENGTH, fallible)) {
     promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
@@ -288,74 +285,75 @@ WebAuthnManager::MakeCredential(nsPIDOMW
   srv = HashCString(hashService, rpId, rpIdHash);
   if (NS_WARN_IF(NS_FAILED(srv))) {
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
     return promise.forget();
   }
 
   // Process each element of cryptoParameters using the following steps, to
   // produce a new sequence normalizedParameters.
-  nsTArray<ScopedCredentialParameters> normalizedParams;
-  for (size_t a = 0; a < aCryptoParameters.Length(); ++a) {
+  nsTArray<PublicKeyCredentialParameters> normalizedParams;
+  for (size_t a = 0; a < aOptions.mParameters.Length(); ++a) {
     // Let current be the currently selected element of
     // cryptoParameters.
 
-    // If current.type does not contain a ScopedCredentialType
+    // If current.type does not contain a PublicKeyCredentialType
     // supported by this implementation, then stop processing current and move
     // on to the next element in cryptoParameters.
-    if (aCryptoParameters[a].mType != ScopedCredentialType::ScopedCred) {
+    if (aOptions.mParameters[a].mType != PublicKeyCredentialType::Public_key) {
       continue;
     }
 
     // Let normalizedAlgorithm be the result of normalizing an algorithm using
     // the procedure defined in [WebCryptoAPI], with alg set to
     // current.algorithm and op set to 'generateKey'. If an error occurs during
     // this procedure, then stop processing current and move on to the next
     // element in cryptoParameters.
 
     nsString algName;
-    if (NS_FAILED(GetAlgorithmName(aCx, aCryptoParameters[a].mAlgorithm,
+    if (NS_FAILED(GetAlgorithmName(aOptions.mParameters[a].mAlgorithm,
                                    algName))) {
       continue;
     }
 
-    // Add a new object of type ScopedCredentialParameters to
+    // Add a new object of type PublicKeyCredentialParameters to
     // normalizedParameters, with type set to current.type and algorithm set to
     // normalizedAlgorithm.
-    ScopedCredentialParameters normalizedObj;
-    normalizedObj.mType = aCryptoParameters[a].mType;
+    PublicKeyCredentialParameters normalizedObj;
+    normalizedObj.mType = aOptions.mParameters[a].mType;
     normalizedObj.mAlgorithm.SetAsString().Assign(algName);
 
     if (!normalizedParams.AppendElement(normalizedObj, mozilla::fallible)){
       promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
       return promise.forget();
     }
   }
 
   // If normalizedAlgorithm is empty and cryptoParameters was not empty, cancel
   // the timer started in step 2, reject promise with a DOMException whose name
   // is "NotSupportedError", and terminate this algorithm.
-  if (normalizedParams.IsEmpty() && !aCryptoParameters.IsEmpty()) {
+  if (normalizedParams.IsEmpty() && !aOptions.mParameters.IsEmpty()) {
     promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return promise.forget();
   }
 
   // TODO: The following check should not be here. This is checking for
   // parameters specific to the soft key, and should be put in the soft key
   // manager in the parent process. Still need to serialize
-  // ScopedCredentialParameters first.
+  // PublicKeyCredentialParameters first.
 
-  // Check if at least one of the specified combinations of ScopedCredentialType
-  // and cryptographic parameters is supported. If not, return an error code
-  // equivalent to NotSupportedError and terminate the operation.
+  // Check if at least one of the specified combinations of
+  // PublicKeyCredentialParameters and cryptographic parameters is supported. If
+  // not, return an error code equivalent to NotSupportedError and terminate the
+  // operation.
 
   bool isValidCombination = false;
 
   for (size_t a = 0; a < normalizedParams.Length(); ++a) {
-    if (normalizedParams[a].mType == ScopedCredentialType::ScopedCred &&
+    if (normalizedParams[a].mType == PublicKeyCredentialType::Public_key &&
         normalizedParams[a].mAlgorithm.IsString() &&
         normalizedParams[a].mAlgorithm.GetAsString().EqualsLiteral(
           WEBCRYPTO_NAMED_CURVE_P256)) {
       isValidCombination = true;
       break;
     }
   }
   if (!isValidCombination) {
@@ -374,17 +372,17 @@ WebAuthnManager::MakeCredential(nsPIDOMW
   // Currently no extensions are supported
   //
   // Use attestationChallenge, 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);
@@ -402,25 +400,19 @@ WebAuthnManager::MakeCredential(nsPIDOMW
     promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
     return promise.forget();
   }
 
   nsTArray<WebAuthnScopedCredentialDescriptor> excludeList;
   if (aOptions.mExcludeList.WasPassed()) {
     for (const auto& s: aOptions.mExcludeList.Value()) {
       WebAuthnScopedCredentialDescriptor c;
-      c.type() = static_cast<uint32_t>(s.mType);
       CryptoBuffer cb;
       cb.Assign(s.mId);
       c.id() = cb;
-      if (s.mTransports.WasPassed()) {
-        for (const auto& t: s.mTransports.Value()) {
-          c.transports().AppendElement(static_cast<uint32_t>(t));
-        }
-      }
       excludeList.AppendElement(c);
     }
   }
 
   // TODO: Add extension list building
   nsTArray<WebAuthnExtension> extensions;
 
   WebAuthnTransactionInfo info(rpIdHash,
@@ -571,25 +563,19 @@ WebAuthnManager::GetAssertion(nsPIDOMWin
   if (!aOptions.mAllowList.WasPassed()) {
     promise->MaybeReject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
     return promise.forget();
   }
 
   nsTArray<WebAuthnScopedCredentialDescriptor> allowList;
   for (const auto& s: aOptions.mAllowList.Value()) {
     WebAuthnScopedCredentialDescriptor c;
-    c.type() = static_cast<uint32_t>(s.mType);
     CryptoBuffer cb;
     cb.Assign(s.mId);
     c.id() = cb;
-    if (s.mTransports.WasPassed()) {
-      for (const auto& t: s.mTransports.Value()) {
-        c.transports().AppendElement(static_cast<uint32_t>(t));
-      }
-    }
     allowList.AppendElement(c);
   }
 
   // TODO: Add extension list building
   // If extensions was specified, process any extensions supported by this
   // 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
--- a/dom/webauthn/WebAuthnManager.h
+++ b/dom/webauthn/WebAuthnManager.h
@@ -2,19 +2,19 @@
 /* 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_WebAuthnManager_h
 #define mozilla_dom_WebAuthnManager_h
 
-#include "nsIIPCBackgroundChildCreateCallback.h"
 #include "mozilla/MozPromise.h"
 #include "mozilla/dom/PWebAuthnTransaction.h"
+#include "nsIIPCBackgroundChildCreateCallback.h"
 
 /*
  * Content process manager for the WebAuthn protocol. Created on calls to the
  * WebAuthentication DOM object, this manager handles establishing IPC channels
  * for WebAuthn transactions, as well as keeping track of JS Promise objects
  * representing transactions in flight.
  *
  * The WebAuthn spec (https://www.w3.org/TR/webauthn/) allows for two different
@@ -68,21 +68,18 @@ public:
   void
   FinishGetAssertion(nsTArray<uint8_t>& aCredentialId,
                      nsTArray<uint8_t>& aSigBuffer);
 
   void
   Cancel(const nsresult& aError);
 
   already_AddRefed<Promise>
-  MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
-                 const Account& aAccountInformation,
-                 const Sequence<ScopedCredentialParameters>& aCryptoParameters,
-                 const ArrayBufferViewOrArrayBuffer& aAttestationChallenge,
-                 const ScopedCredentialOptions& aOptions);
+  MakeCredential(nsPIDOMWindowInner* aParent,
+                 const MakeCredentialOptions& aOptions);
 
   already_AddRefed<Promise>
   GetAssertion(nsPIDOMWindowInner* aParent,
                const ArrayBufferViewOrArrayBuffer& aAssertionChallenge,
                const AssertionOptions& aOptions);
 
   void StartRegister();
   void StartSign();
--- a/dom/webauthn/moz.build
+++ b/dom/webauthn/moz.build
@@ -12,17 +12,16 @@ IPDL_SOURCES += [
 ]
 
 EXPORTS.mozilla.dom += [
     'AuthenticatorAssertionResponse.h',
     'AuthenticatorAttestationResponse.h',
     'AuthenticatorResponse.h',
     'NSSU2FTokenRemote.h',
     'PublicKeyCredential.h',
-    'ScopedCredential.h',
     'U2FSoftTokenManager.h',
     'U2FTokenManager.h',
     'U2FTokenTransport.h',
     'WebAuthentication.h',
     'WebAuthnManager.h',
     'WebAuthnRequest.h',
     'WebAuthnTransactionChild.h',
     'WebAuthnTransactionParent.h',
@@ -30,17 +29,16 @@ EXPORTS.mozilla.dom += [
 ]
 
 UNIFIED_SOURCES += [
     'AuthenticatorAssertionResponse.cpp',
     'AuthenticatorAttestationResponse.cpp',
     'AuthenticatorResponse.cpp',
     'NSSU2FTokenRemote.cpp',
     'PublicKeyCredential.cpp',
-    'ScopedCredential.cpp',
     'U2FSoftTokenManager.cpp',
     'U2FTokenManager.cpp',
     'WebAuthentication.cpp',
     'WebAuthnManager.cpp',
     'WebAuthnTransactionChild.cpp',
     'WebAuthnTransactionParent.cpp',
     'WebAuthnUtil.cpp'
 ]
--- a/dom/webauthn/tests/test_webauthn_get_assertion.html
+++ b/dom/webauthn/tests/test_webauthn_get_assertion.html
@@ -38,18 +38,20 @@
 
    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.authentication.makeCredential, undefined, "WebAuthn makeCredential 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");
 
      let authn = navigator.authentication;
 
      let gAssertionChallenge = new Uint8Array(16);
      window.crypto.getRandomValues(gAssertionChallenge);
 
      let invalidCred = { type: "Magic", id: base64ToBytes("AAA=") };
      let unknownCred = { type: "ScopedCred", id: base64ToBytes("AAA=") };
--- a/dom/webauthn/tests/test_webauthn_loopback.html
+++ b/dom/webauthn/tests/test_webauthn_loopback.html
@@ -21,20 +21,23 @@
 // 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");
-  isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential 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");
 
   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();
 
@@ -98,37 +101,47 @@ function() {
     })
     .then(function(aSignedData) {
       console.log(aPublicKey, aSignedData, signatureValue);
       return verifySignature(aPublicKey, aSignedData, signatureValue);
     })
   }
 
   function testMakeCredential() {
-    let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
-    let param = {type: "ScopedCred", algorithm: "p-256"};
-
-    authn.makeCredential(acct, [param], gCredentialChallenge)
+    let rp = {id: document.origin, name: "none", icon: "none"};
+    let user = {id: "none", name: "none", icon: "none", displayName: "none"};
+    let param = {type: "public-key", algorithm: "P-256"};
+    let makeCredentialOptions = {
+      rp: rp,
+      user: user,
+      challenge: gCredentialChallenge,
+      parameters: [param]
+    };
+    credm.create({publicKey: makeCredentialOptions})
     .then(checkCredentialValid)
     .then(testMakeDuplicate)
     .catch(function(aReason) {
       ok(false, aReason);
       SimpleTest.finish();
     });
   }
 
   function testMakeDuplicate(aCredInfo) {
-    let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
-    let param = {type: "ScopedCred", algorithm: "p-256"};
-    let options = {rpId: document.origin,
-                   excludeList: [{type: "ScopedCred",
-                                  id: Uint8Array.from(aCredInfo.rawId),
-                                  transports: ["usb"]}]};
-
-    authn.makeCredential(acct, [param], gCredentialChallenge, options)
+    let rp = {id: document.origin, name: "none", icon: "none"};
+    let user = {id: "none", name: "none", icon: "none", displayName: "none"};
+    let param = {type: "public-key", algorithm: "P-256"};
+    let makeCredentialOptions = {
+      rp: rp,
+      user: user,
+      challenge: gCredentialChallenge,
+      parameters: [param],
+      excludeList: [{type: "public-key", id: Uint8Array.from(aCredInfo.rawId),
+                     transports: ["usb"]}]
+    };
+    credm.create({publicKey: makeCredentialOptions})
     .then(function() {
       // We should have errored here!
       ok(false, "The excludeList didn't stop a duplicate being created!");
       SimpleTest.finish();
     })
     .catch(function(aReason) {
       ok(aReason.toString().startsWith("NotAllowedError"), "Expect NotAllowedError, got " + aReason);
       testAssertion(aCredInfo);
--- a/dom/webauthn/tests/test_webauthn_make_credential.html
+++ b/dom/webauthn/tests/test_webauthn_make_credential.html
@@ -11,186 +11,240 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 
   <h1>Test for MakeCredential 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";
+    "use strict";
 
-   // Execute the full-scope test
-   SimpleTest.waitForExplicitFinish();
+    // Execute the full-scope test
+    SimpleTest.waitForExplicitFinish();
 
-   function arrivingHereIsGood(aResult) {
-     ok(true, "Good result! Received a: " + aResult);
-     return Promise.resolve();
-   }
+    function arrivingHereIsGood(aResult) {
+      ok(true, "Good result! Received a: " + aResult);
+      return Promise.resolve();
+    }
 
-   function arrivingHereIsBad(aResult) {
-     ok(false, "Bad result! Received a: " + aResult);
-     return Promise.resolve();
-   }
+    function arrivingHereIsBad(aResult) {
+      ok(false, "Bad result! Received a: " + aResult);
+      return Promise.resolve();
+    }
 
-   function expectNotAllowedError(aResult) {
-     ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
-     return Promise.resolve();
-   }
+    function expectNotAllowedError(aResult) {
+      ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
+      return Promise.resolve();
+    }
+
+    function expectTypeError(aResult) {
+      ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
+      return Promise.resolve();
+    }
 
-   function expectTypeError(aResult) {
-     ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
-     return Promise.resolve();
-   }
-
-   function expectNotSupportedError(aResult) {
-     ok(aResult.toString().startsWith("NotSupportedError"), "Expecting a NotSupportedError");
-     return Promise.resolve();
-   }
+    function expectNotSupportedError(aResult) {
+      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");
-     isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
-     isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
+    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");
 
-     let authn = navigator.authentication;
+      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"};
+      let unsupportedParam = {type: "public-key", algorithm: "3DES"};
+      let badParam = {type: "SimplePassword", algorithm: "MaxLength=2"};
 
-     let gCredentialChallenge = new Uint8Array(16);
-     window.crypto.getRandomValues(gCredentialChallenge);
-
-     let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
-     let param = {type: "ScopedCred", algorithm: "p-256"};
-     let unsupportedParam = {type: "ScopedCred", algorithm: "3DES"};
-     let badParam = {type: "SimplePassword", algorithm: "MaxLength=2"};
+      var testFuncs = [
+        // Test basic good call
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: gCredentialChallenge, parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsGood)
+                      .catch(arrivingHereIsBad);
+        },
 
-     var testFuncs = [
-       // Test basic good call
-       function() {
-         return authn.makeCredential(acct, [param], gCredentialChallenge)
-              .then(arrivingHereIsGood)
-              .catch(arrivingHereIsBad);
-       },
+        // Test empty account
+        function() {
+          let makeCredentialOptions = {
+            challenge: gCredentialChallenge, parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectTypeError);
+        },
+
+        // Test without a parameter
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: gCredentialChallenge, parameters: []
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectNotSupportedError);
+        },
 
-       // Test empty account
-       function() {
-         return authn.makeCredential({}, [param], gCredentialChallenge)
-                     .then(arrivingHereIsBad)
-                     .catch(expectTypeError);
-       },
-
-       // Test without a parameter
-       function() {
-         return authn.makeCredential(acct, [], gCredentialChallenge)
-                     .then(arrivingHereIsBad)
-                     .catch(expectNotSupportedError);
-       },
+        // Test without a parameter array at all
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: gCredentialChallenge
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+               .then(arrivingHereIsBad)
+               .catch(expectTypeError);
+        },
 
-       // Test without a parameter array at all
-       function() {
-         return authn.makeCredential(acct, null, gCredentialChallenge)
-              .then(arrivingHereIsBad)
-              .catch(expectTypeError);
-       },
+        // Test with an unsupported parameter
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: gCredentialChallenge, parameters: [unsupportedParam]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectNotSupportedError);
+        },
 
-       // Test with an unsupported parameter
-       function() {
-         return authn.makeCredential(acct, [unsupportedParam], gCredentialChallenge)
-              .then(arrivingHereIsBad)
-              .catch(expectNotSupportedError);
-       },
+        // Test with an unsupported parameter and a good one
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: gCredentialChallenge,
+            parameters: [param, unsupportedParam]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsGood)
+                      .catch(arrivingHereIsBad);
+        },
 
-       // Test with an unsupported parameter and a good one
-       function() {
-         return authn.makeCredential(acct, [unsupportedParam, param], gCredentialChallenge)
-              .then(arrivingHereIsGood)
-              .catch(arrivingHereIsBad);
-       },
+        // Test with a bad parameter
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: gCredentialChallenge, parameters: [badParam]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+               .then(arrivingHereIsBad)
+               .catch(expectTypeError);
+        },
 
-       // Test with a bad parameter
-       function() {
-         return authn.makeCredential(acct, [badParam], gCredentialChallenge)
-              .then(arrivingHereIsBad)
-              .catch(expectTypeError);
-       },
-
-       // Test with an unsupported parameter, and a bad one
-       function() {
-         return authn.makeCredential(acct, [unsupportedParam, badParam],
-                              gCredentialChallenge)
-              .then(arrivingHereIsBad)
-              .catch(expectTypeError);
-       },
+        // Test with an unsupported parameter, and a bad one
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: gCredentialChallenge,
+            parameters: [unsupportedParam, badParam]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectTypeError);
+        },
 
-       // Test with an unsupported parameter, a bad one, and a good one. This
-       // should still fail, as anything with a badParam should fail.
-       function() {
-         return authn.makeCredential(acct, [unsupportedParam, badParam, param],
-                              gCredentialChallenge)
-              .then(arrivingHereIsBad)
-              .catch(expectTypeError);
-       },
+        // Test with an unsupported parameter, a bad one, and a good one. This
+        // should still fail, as anything with a badParam should fail.
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: gCredentialChallenge,
+            parameters: [param, unsupportedParam, badParam]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+               .then(arrivingHereIsBad)
+               .catch(expectTypeError);
+        },
 
-       // Test without a challenge
-       function() {
-         return authn.makeCredential(acct, [param], null)
-              .then(arrivingHereIsBad)
-              .catch(expectTypeError);
-       },
+        // Test without a challenge
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, user: user, parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectTypeError);
+        },
 
-       // Test with an invalid challenge
-       function() {
-         return authn.makeCredential(acct, [param], "begone, thou ill-fitting moist glove!")
-              .then(arrivingHereIsBad)
-              .catch(expectTypeError);
-       },
+        // Test with an invalid challenge
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: "begone, thou ill-fitting moist glove!",
+            parameters: [unsupportedParam]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+               .then(arrivingHereIsBad)
+               .catch(expectTypeError);
+        },
 
-       // Test with duplicate parameters
-       function() {
-         return authn.makeCredential(acct, [param, param, param], gCredentialChallenge)
-              .then(arrivingHereIsGood)
-              .catch(arrivingHereIsBad);
-       },
+        // Test with duplicate parameters
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: gCredentialChallenge,
+            parameters: [param, param, param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsGood)
+                      .catch(arrivingHereIsBad);
+        },
 
-       // Test an incomplete account
-       function() {
-         return authn.makeCredential({id: "none"
-         }, [param], gCredentialChallenge)
-              .then(arrivingHereIsBad)
-              .catch(expectTypeError);
-       },
-
-       function() {
-         return authn.makeCredential({name: "none", imageURL: "http://example.com/404"},
-                              [param], gCredentialChallenge)
-              .then(arrivingHereIsBad)
-              .catch(expectTypeError);
-       },
+        // Test with missing rp
+        function() {
+          let makeCredentialOptions = {
+            user: user, challenge: gCredentialChallenge, parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectTypeError);
+        },
 
-       // Test a complete account
-       function() {
-         return authn.makeCredential({rpDisplayName: "Foxxy", displayName: "Foxxy V",
-                                      id: "foxes_are_the_best@example.com",
-                                      name: "Fox F. Foxington",
-                                      imageURL: "https://example.com/fox.svg"},
-                                     [param], gCredentialChallenge)
-                     .then(arrivingHereIsGood)
-                     .catch(arrivingHereIsBad);
-       }];
+        // Test with missing user
+        function() {
+          let makeCredentialOptions = {
+            rp: rp, challenge: gCredentialChallenge, parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectTypeError);
+        },
 
-     var i = 0;
-     var runNextTest = () => {
-       if (i == testFuncs.length) {
-         SimpleTest.finish();
-         return;
-       }
-       testFuncs[i]().then(() => { runNextTest(); });
-       i = i + 1;
-     };
-     runNextTest();
-   };
+        // Test a complete account
+        function() {
+          let completeRP = {id: "Foxxy RP", name: "Foxxy Name",
+                            icon: "https://example.com/fox.svg"};
+          let completeUser = {id: "foxes_are_the_best@example.com",
+                              name: "Fox F. Foxington",
+                              icon: "https://example.com/fox.svg",
+                              displayName: "Foxxy V"};
+          let makeCredentialOptions = {
+            rp: completeRP, user: completeUser, challenge: gCredentialChallenge,
+            parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsGood)
+                      .catch(arrivingHereIsBad);
+        }];
+
+      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_no_token.html
+++ b/dom/webauthn/tests/test_webauthn_no_token.html
@@ -22,52 +22,59 @@
 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");
-  isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential 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");
 
   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);
 
   testMakeCredential();
 
   function testMakeCredential() {
-    let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
-    let param = {type: "ScopedCred", algorithm: "p-256"};
-    authn.makeCredential(acct, [param], credentialChallenge)
+    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"};
+    let makeCredentialOptions = {
+      rp: rp, user: user, challenge: credentialChallenge, parameters: [param]
+    };
+    credm.create({publicKey: makeCredentialOptions})
     .then(function(aResult) {
       ok(false, "Should have failed.");
       testAssertion();
     })
     .catch(function(aReason) {
       ok(aReason.toString().startsWith("NotAllowedError"), aReason);
       testAssertion();
     });
   }
 
   function testAssertion() {
     let newCredential = {
       type: "ScopedCred",
       id: credentialId,
-      transports: [ "usb" ],
+      transports: ["usb"],
     }
     let assertOptions = {rpId: document.origin, timeoutSeconds: 5,
-                         allowList: [ newCredential ]};
+                         allowList: [newCredential]};
     authn.getAssertion(assertionChallenge, assertOptions)
     .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
@@ -11,176 +11,202 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 
   <h1>Test Same Origin Policy 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";
+    "use strict";
 
-   // Execute the full-scope test
-   SimpleTest.waitForExplicitFinish();
+    // Execute the full-scope test
+    SimpleTest.waitForExplicitFinish();
 
-   var gTrackedCredential = {};
+    var gTrackedCredential = {};
 
-   function arrivingHereIsGood(aResult) {
-     ok(true, "Good result! Received a: " + aResult);
-     return Promise.resolve();
-   }
+    function arrivingHereIsGood(aResult) {
+      ok(true, "Good result! Received a: " + aResult);
+      return Promise.resolve();
+    }
 
-   function arrivingHereIsBad(aResult) {
-     // TODO: Change to `ok` when Bug 1329764 lands
-     todo(false, "Bad result! Received a: " + aResult);
-     return Promise.resolve();
-   }
+    function arrivingHereIsBad(aResult) {
+      // TODO: Change to `ok` when Bug 1329764 lands
+      todo(false, "Bad result! Received a: " + aResult);
+      return Promise.resolve();
+    }
 
-   function expectSecurityError(aResult) {
-     // TODO: Change to `ok` when Bug 1329764 lands
-     todo(aResult.toString().startsWith("SecurityError"), "Expecting a SecurityError");
-     return Promise.resolve();
-   }
+    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",
-       id: Uint8Array.from(aPublicKeyCredential.rawId),
-       transports: [ "usb" ],
-     }
-     return Promise.resolve(aPublicKeyCredential);
-   }
+    function keepThisPublicKeyCredential(aPublicKeyCredential) {
+      gTrackedCredential = {
+        type: "ScopedCred",
+        id: Uint8Array.from(aPublicKeyCredential.rawId),
+        transports: [ "usb" ],
+      }
+      return Promise.resolve(aPublicKeyCredential);
+    }
 
-   function runTests() {
-     isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
-     isnot(navigator.authentication.makeCredential, undefined,
-           "WebAuthn makeCredential API endpoint must exist");
-     isnot(navigator.authentication.getAssertion, undefined,
-           "WebAuthn getAssertion API endpoint must exist");
+    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");
+
+      let authn = navigator.authentication;
+      let credm = navigator.credentials;
 
-     let authn = navigator.authentication;
+      let chall = new Uint8Array(16);
+      window.crypto.getRandomValues(chall);
 
-     let chall = new Uint8Array(16);
-     window.crypto.getRandomValues(chall);
-
-     let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
-     let param = {type: "ScopedCred", algorithm: "p-256"};
+      let user = {id: "none", name: "none", icon: "none", displayName: "none"};
+      let param = {type: "public-key", algorithm: "p-256"};
 
-     var testFuncs = [
-       function() {
-         // Test basic good call
-         return authn.makeCredential(acct, [param], chall, {rpId: document.origin})
-                     .then(keepThisPublicKeyCredential)
-                     .then(arrivingHereIsGood)
-                     .catch(arrivingHereIsBad);
-       },
+      var testFuncs = [
+        function() {
+          // Test basic good call
+          let rp = {id: document.origin};
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: chall, parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(keepThisPublicKeyCredential)
+                      .then(arrivingHereIsGood)
+                      .catch(arrivingHereIsBad);
+        },
 
-       function() {
-         // Test rpId being unset
-         return authn.makeCredential(acct, [param], chall, {})
-                     .then(arrivingHereIsGood)
-                     .catch(arrivingHereIsBad);
-       },
-       function() {
-         // Test this origin with optional fields
-         return authn.makeCredential(acct, [param], chall,
-                                     {rpId: "user:pass@" + document.origin + ":8888"})
-                     .then(arrivingHereIsBad)
-                     .catch(expectSecurityError);
-       },
-       function() {
-         // Test blank rpId
-         return authn.makeCredential(acct, [param], chall, {rpId: ""})
-                     .then(arrivingHereIsBad)
-                     .catch(expectSecurityError);
-       },
-       function() {
-         // Test subdomain of this origin
-         return authn.makeCredential(acct, [param], chall,
-                                     {rpId: "subdomain." + document.origin})
-                     .then(arrivingHereIsBad)
-                     .catch(expectSecurityError);
-       },
-       function() {
-         // Test another origin
-         return authn.makeCredential(acct, [param], chall, {rpId: "example.com"})
-                     .then(arrivingHereIsBad)
-                     .catch(expectSecurityError);
-       },
-       function () {
-         // est a different domain within the same TLD
-         return authn.makeCredential(acct, [param], chall, {rpId: "alt.test"})
-                     .then(arrivingHereIsBad)
-                     .catch(expectSecurityError);
-       },
-       function () {
-         // Test basic good call
-         return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
-                                           rpId: document.origin})
-                     .then(arrivingHereIsGood)
-                     .catch(arrivingHereIsBad);
-       },
-       function () {
-         // Test rpId being unset
-         return authn.getAssertion(chall, {allowList: [ gTrackedCredential ]})
-                     .then(arrivingHereIsGood)
-                     .catch(arrivingHereIsBad);
-       },
-       function () {
-         // Test this origin with optional fields
-         return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
-                                           rpId: "user:pass@" + document.origin + ":8888"})
-                     .then(arrivingHereIsBad)
-                     .catch(expectSecurityError);
-       },
-       function () {
-         // Test blank rpId
-         return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
-                                           rpId: ""})
-                     .then(arrivingHereIsBad)
-                     .catch(expectSecurityError);
-       },
-       function () {
-         // Test subdomain of this origin
-         return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
-                                           rpId: "subdomain." + document.origin})
-                     .then(arrivingHereIsBad)
-                     .catch(expectSecurityError);
-       },
-       function () {
-         // Test another origin
-         return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
-                                           rpId: "example.com"})
-                     .then(arrivingHereIsBad)
-                     .catch(expectSecurityError);
-       },
-       function () {
-         // Test a different domain within the same TLD
-         return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
-                                           rpId: "alt.test"})
-                     .then(arrivingHereIsBad)
-                     .catch(expectSecurityError)
-       },
-       function () {
-         SimpleTest.finish();
-       }
-     ];
-     var i = 0;
-     var runNextTest = () => {
-       if (i == testFuncs.length) {
-         SimpleTest.finish();
-         return;
-       }
-       console.log(i);
-       testFuncs[i]().then(() => { runNextTest(); });
-       i = i + 1;
-     };
-     runNextTest();
-   };
-   SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
-                                      ["security.webauth.webauthn_enable_softtoken", true],
-                                      ["security.webauth.webauthn_enable_usbtoken", false]]},
-                             runTests);
+        function() {
+          // Test rp.id being unset
+          let makeCredentialOptions = {
+            rp: {}, user: user, challenge: chall, parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsGood)
+                      .catch(arrivingHereIsBad);
+        },
+        function() {
+          // Test this origin with optional fields
+          let rp = {id: "user:pass@" + document.origin + ":8888"};
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: chall, parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectSecurityError);
+        },
+        function() {
+          // Test blank rp.id
+          let rp = {id: ""};
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: chall, parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectSecurityError);
+        },
+        function() {
+          // Test subdomain of this origin
+          let rp = {id: "subdomain." + document.origin};
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: chall, parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectSecurityError);
+        },
+        function() {
+          // Test another origin
+          let rp = {id: "example.com"};
+          let makeCredentialOptions = {
+            rp: rp, user: user, challenge: chall, parameters: [param]
+          };
+          return credm.create({publicKey: makeCredentialOptions})
+                      .then(arrivingHereIsBad)
+                      .catch(expectSecurityError);
+        },
+        function () {
+          // Test a different domain within the same TLD
+          let rp = {id: "alt.test"};
+          let makeCredentialOptions = {
+            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})
+                      .then(arrivingHereIsGood)
+                      .catch(arrivingHereIsBad);
+        },
+        function () {
+          // Test rpId being unset
+          return authn.getAssertion(chall, {allowList: [gTrackedCredential]})
+                      .then(arrivingHereIsGood)
+                      .catch(arrivingHereIsBad);
+        },
+        function () {
+          // Test this origin with optional fields
+          return authn.getAssertion(chall, {allowList: [gTrackedCredential],
+                                            rpId: "user:pass@" + document.origin + ":8888"})
+                      .then(arrivingHereIsBad)
+                      .catch(expectSecurityError);
+        },
+        function () {
+          // Test blank rpId
+          return authn.getAssertion(chall, {allowList: [gTrackedCredential],
+                                            rpId: ""})
+                      .then(arrivingHereIsBad)
+                      .catch(expectSecurityError);
+        },
+        function () {
+          // Test subdomain of this origin
+          return authn.getAssertion(chall, {allowList: [gTrackedCredential],
+                                            rpId: "subdomain." + document.origin})
+                      .then(arrivingHereIsBad)
+                      .catch(expectSecurityError);
+        },
+        function () {
+          // Test another origin
+          return authn.getAssertion(chall, {allowList: [gTrackedCredential],
+                                            rpId: "example.com"})
+                      .then(arrivingHereIsBad)
+                      .catch(expectSecurityError);
+        },
+        function () {
+          // Test a different domain within the same TLD
+          return authn.getAssertion(chall, {allowList: [gTrackedCredential],
+                                            rpId: "alt.test"})
+                      .then(arrivingHereIsBad)
+                      .catch(expectSecurityError)
+        },
+        function () {
+          SimpleTest.finish();
+        }
+      ];
+      var i = 0;
+      var runNextTest = () => {
+        if (i == testFuncs.length) {
+          SimpleTest.finish();
+          return;
+        }
+        console.log(i);
+        testFuncs[i]().then(() => { runNextTest(); });
+        i = i + 1;
+      };
+      runNextTest();
+    };
+    SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
+                                       ["security.webauth.webauthn_enable_softtoken", true],
+                                       ["security.webauth.webauthn_enable_usbtoken", false]]},
+                              runTests);
 
   </script>
 
 </body>
 </html>
--- a/dom/webidl/CredentialManagement.webidl
+++ b/dom/webidl/CredentialManagement.webidl
@@ -7,8 +7,17 @@
  * https://www.w3.org/TR/credential-management-1/
  */
 
 [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?> create(optional CredentialCreationOptions options);
+};
+
+dictionary CredentialCreationOptions {
+  MakeCredentialOptions publicKey;
+};
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -368,8 +368,13 @@ partial interface Navigator {
 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
@@ -22,73 +22,97 @@ interface AuthenticatorResponse {
     readonly attribute ArrayBuffer clientDataJSON;
 };
 
 [SecureContext, Pref="security.webauth.webauthn"]
 interface AuthenticatorAttestationResponse : AuthenticatorResponse {
     readonly attribute ArrayBuffer attestationObject;
 };
 
-dictionary Account {
-    required DOMString rpDisplayName;
-    required DOMString displayName;
-    required DOMString id;
-    DOMString          name;
-    DOMString          imageURL;
+dictionary PublicKeyCredentialParameters {
+    required PublicKeyCredentialType  type;
+    required WebAuthnAlgorithmID algorithm; // NOTE: changed from AllgorithmIdentifier because typedef (object or DOMString) not serializable
+};
+
+dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
+    DOMString displayName;
+};
+
+dictionary MakeCredentialOptions {
+    required PublicKeyCredentialEntity rp;
+    required PublicKeyCredentialUserEntity user;
+
+    required BufferSource                         challenge;
+    required sequence<PublicKeyCredentialParameters> parameters;
+
+    unsigned long                        timeout;
+    sequence<PublicKeyCredentialDescriptor> excludeList;
+    AuthenticatorSelectionCriteria       authenticatorSelection;
+    // Extensions are not supported yet.
+    // AuthenticationExtensions             extensions;
+};
+
+dictionary PublicKeyCredentialEntity {
+    DOMString id;
+    DOMString name;
+    USVString icon;
+};
+
+dictionary AuthenticatorSelectionCriteria {
+    Attachment    attachment;
+    boolean       requireResidentKey = false;
+};
+
+enum Attachment {
+    "platform",
+    "cross-platform"
+};
+
+dictionary CollectedClientData {
+    required DOMString           challenge;
+    required DOMString           origin;
+    required DOMString           hashAlg;
+    DOMString                    tokenBinding;
+    // Extensions are not supported yet.
+    // AuthenticationExtensions     clientExtensions;
+    // AuthenticationExtensions     authenticatorExtensions;
+};
+
+enum PublicKeyCredentialType {
+    "public-key"
+};
+
+dictionary PublicKeyCredentialDescriptor {
+    required PublicKeyCredentialType type;
+    required BufferSource id;
+    sequence<WebAuthnTransport>   transports;
 };
 
 typedef (boolean or DOMString) WebAuthnAlgorithmID; // Fix when upstream there's a definition of how to serialize AlgorithmIdentifier
 
-dictionary ScopedCredentialParameters {
-    required ScopedCredentialType type;
-    required WebAuthnAlgorithmID  algorithm; // NOTE: changed from AllgorithmIdentifier because typedef (object or DOMString) not serializable
-};
-
-dictionary ScopedCredentialOptions {
-    unsigned long                        timeoutSeconds;
-    USVString                            rpId;
-    sequence<ScopedCredentialDescriptor> excludeList;
-    WebAuthnExtensions                   extensions;
-};
-
 [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 {
 };
 
-// Renamed from "ClientData" to avoid a collision with U2F
-dictionary WebAuthnClientData {
-    required DOMString           challenge;
-    required DOMString           origin;
-    required WebAuthnAlgorithmID hashAlg; // NOTE: changed from AllgorithmIdentifier because typedef (object or DOMString) not serializable
-    DOMString                    tokenBinding;
-    WebAuthnExtensions           extensions;
-};
-
 enum ScopedCredentialType {
     "ScopedCred"
 };
 
-[SecureContext, Pref="security.webauth.webauthn"]
-interface ScopedCredential {
-    readonly attribute ScopedCredentialType type;
-    readonly attribute ArrayBuffer          id;
-};
-
 dictionary ScopedCredentialDescriptor {
     required ScopedCredentialType type;
     required BufferSource         id;
     sequence <WebAuthnTransport>  transports;
 };
 
 // Renamed from "Transport" to avoid a collision with U2F
 enum WebAuthnTransport {
@@ -96,20 +120,13 @@ enum WebAuthnTransport {
     "nfc",
     "ble"
 };
 
 /***** The Main API *****/
 
 [SecureContext, Pref="security.webauth.webauthn"]
 interface WebAuthentication {
-    Promise<PublicKeyCredential> makeCredential (
-        Account                                 accountInformation,
-        sequence<ScopedCredentialParameters>    cryptoParameters,
-        BufferSource                            attestationChallenge,
-        optional ScopedCredentialOptions        options
-    );
-
     Promise<PublicKeyCredential> getAssertion (
         BufferSource               assertionChallenge,
         optional AssertionOptions  options
     );
 };