bug 1332681 - part 3/4 - convert authentication.makeCredential to credentials.create r=jcj,qdot
authorDavid Keeler <dkeeler@mozilla.com>
Mon, 22 May 2017 17:09:49 -0700
changeset 398498 3c0d57fec9e5bb5c6eb71389d62129d7f8a2baa8
parent 398497 5d05100ea93645c57fcdb196c323afe159151135
child 398499 3c876e859603f37750de4725546d2c1dddf05e31
push idunknown
push userunknown
push dateunknown
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 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
     );
 };