Update inline_signin_ui to work in incognito mode

- Added a new reason for the signin that requests only the login process to
be executed and then takes the result from gaia and sends them through a new
message added to the inline_login.js. This code path avoids all cals that try
to perform operations on profiles
- This new mode is used by GCPW to gather the necessary login information

Bug: 887444

Change-Id: I84c62408b16c46a40360d7fc703b482d399cd76b
Reviewed-on: https://chromium-review.googlesource.com/c/1286755
Commit-Queue: Tien Mai <tienmai@chromium.org>
Reviewed-by: Achuith Bhandarkar <achuith@chromium.org>
Reviewed-by: Greg Thompson <grt@chromium.org>
Reviewed-by: Mihai Sardarescu <msarda@chromium.org>
Reviewed-by: Tommy Martino <tmartino@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Roger Tawa <rogerta@chromium.org>
Reviewed-by: Jesse Doherty <jwd@chromium.org>
Reviewed-by: Peter Kasting <pkasting@chromium.org>
Reviewed-by: Michael Giuffrida <michaelpg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607573}
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index d383a0b..d4800ed 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -1263,7 +1263,7 @@
           </else>
         </if>
       </if>
-      <!-- Chroium launch blocking dialog. -->
+      <!-- Chromium launch blocking dialog. -->
       <if expr="not is_android and not chromeos">
          <message name="IDS_ENTERPRISE_STARTUP_CLOUD_POLICY_ENROLLMENT_TOOLTIP" desc="The information message of Chromium launch blocking dialog for machine level user cloud policy enrollment.">
           Launching Chromium...
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index bcc144d..aae54346 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -3,6 +3,7 @@
   "+cc/paint",
   "+chrome/app",
   "+chrome/chrome_watcher",
+  "+chrome/credential_provider/common",
   "+chrome/grit",
   "+chrome/install_static",
   "+chrome/installer/util",
diff --git a/chrome/browser/resources/inline_login/inline_login.js b/chrome/browser/resources/inline_login/inline_login.js
index 76af8b5..aa56cf0 100644
--- a/chrome/browser/resources/inline_login/inline_login.js
+++ b/chrome/browser/resources/inline_login/inline_login.js
@@ -93,6 +93,18 @@
   }
 
   /**
+   * Sends a message 'lstFetchResults'. This is a specific message  sent when
+   * the inline signin is loaded with reason REASON_FETCH_LST_ONLY. Handlers of
+   * this message would expect a single argument a base::Dictionary value that
+   * contains the values fetched from the gaia sign in endpoint.
+   * @param {string} arg The string representation of the json data returned by
+   *    the sign in dialog after it has finished the sign in process.
+   */
+  function sendLSTFetchResults(arg) {
+    chrome.send('lstFetchResults', [arg]);
+  }
+
+  /**
    * Invoked when failed to get oauth2 refresh token.
    */
   function handleOAuth2TokenFailure() {
@@ -138,6 +150,7 @@
 
   return {
     closeDialog: closeDialog,
+    sendLSTFetchResults: sendLSTFetchResults,
     getAuthExtHost: getAuthExtHost,
     handleOAuth2TokenFailure: handleOAuth2TokenFailure,
     initialize: initialize,
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index a7e9cee..617ed0e 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2110,6 +2110,10 @@
     sources += [
       "network_profile_bubble.cc",
       "network_profile_bubble.h",
+      "startup/credential_provider_signin_dialog_win.cc",
+      "startup/credential_provider_signin_dialog_win.h",
+      "startup/credential_provider_signin_info_fetcher_win.cc",
+      "startup/credential_provider_signin_info_fetcher_win.h",
       "startup/default_browser_prompt_win.cc",
       "views/certificate_viewer_win.cc",
       "views/chrome_cleaner_dialog_win.cc",
@@ -2172,6 +2176,7 @@
       "//ui/views/controls/webview",
     ]
     deps += [
+      "//chrome/credential_provider/common:common_constants",
       "//components/search_engines",
       "//third_party/iaccessible2",
       "//third_party/isimpledom",
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 39061bc..7abfd399 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/prerender/prerender_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
+#include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/browser/task_manager/web_contents_tags.h"
 #include "chrome/browser/ui/browser.h"
@@ -84,7 +85,7 @@
 // those types of Browser.
 bool WindowCanOpenTabs(Browser* browser) {
   return browser->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP) ||
-      browser->tab_strip_model()->empty();
+         browser->tab_strip_model()->empty();
 }
 
 // Finds an existing Browser compatible with |profile|, making a new one if no
@@ -117,7 +118,7 @@
     // If incognito is forced, we punt.
     PrefService* prefs = profile->GetPrefs();
     if (prefs && IncognitoModePrefs::GetAvailability(prefs) ==
-            IncognitoModePrefs::FORCED) {
+                     IncognitoModePrefs::FORCED) {
       return false;
     }
 
@@ -408,11 +409,8 @@
     create_params.initially_hidden = true;
 
 #if defined(USE_AURA)
-  if (params.browser->window() &&
-      params.browser->window()->GetNativeWindow()) {
-    create_params.context =
-        params.browser->window()->GetNativeWindow();
-  }
+  if (params.browser->window() && params.browser->window()->GetNativeWindow())
+    create_params.context = params.browser->window()->GetNativeWindow();
 #endif
 
   std::unique_ptr<WebContents> target_contents =
@@ -443,7 +441,7 @@
   prerender::PrerenderManager* prerender_manager =
       prerender::PrerenderManagerFactory::GetForBrowserContext(profile);
   return prerender_manager &&
-      prerender_manager->MaybeUsePrerenderedPage(url, params);
+         prerender_manager->MaybeUsePrerenderedPage(url, params);
 }
 
 }  // namespace
@@ -459,8 +457,9 @@
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   const extensions::Extension* extension =
-    extensions::ExtensionRegistry::Get(params->initiating_profile)->
-        enabled_extensions().GetExtensionOrAppByURL(params->url);
+      extensions::ExtensionRegistry::Get(params->initiating_profile)
+          ->enabled_extensions()
+          .GetExtensionOrAppByURL(params->url);
   // Platform apps cannot navigate. Block the request.
   if (extension && extension->is_platform_app())
     params->url = GURL(chrome::kExtensionInvalidRequestURL);
@@ -697,6 +696,49 @@
   params->navigated_or_inserted_contents = contents_to_navigate_or_insert;
 }
 
+bool IsHostAllowedInIncognito(const GURL& url) {
+  std::string scheme = url.scheme();
+  base::StringPiece host = url.host_piece();
+  if (scheme == chrome::kChromeSearchScheme) {
+    return host != chrome::kChromeUIThumbnailHost &&
+           host != chrome::kChromeUIThumbnailHost2 &&
+           host != chrome::kChromeUIThumbnailListHost &&
+           host != chrome::kChromeUISuggestionsHost;
+  }
+
+  if (scheme != content::kChromeUIScheme)
+    return true;
+
+  if (host == chrome::kChromeUIChromeSigninHost) {
+#if defined(OS_WIN)
+    // Allow incognito mode for the chrome-signin url if we only want to
+    // retrieve the login scope token without touching any profiles. This
+    // option is only available on Windows for use with Google Credential
+    // Provider for Windows.
+    return signin::GetSigninReasonForPromoURL(url) ==
+           signin_metrics::Reason::REASON_FETCH_LST_ONLY;
+#else
+    return false;
+#endif  // defined(OS_WIN)
+  }
+
+  // Most URLs are allowed in incognito; the following are exceptions.
+  // chrome://extensions is on the list because it redirects to
+  // chrome://settings.
+  return host != chrome::kChromeUIAppLauncherPageHost &&
+         host != chrome::kChromeUISettingsHost &&
+         host != chrome::kChromeUIHelpHost &&
+         host != chrome::kChromeUIHistoryHost &&
+         host != chrome::kChromeUIExtensionsHost &&
+         host != chrome::kChromeUIBookmarksHost &&
+         host != chrome::kChromeUIUberHost &&
+         host != chrome::kChromeUIThumbnailHost &&
+         host != chrome::kChromeUIThumbnailHost2 &&
+         host != chrome::kChromeUIThumbnailListHost &&
+         host != chrome::kChromeUISuggestionsHost &&
+         host != chrome::kChromeUIDevicesHost;
+}
+
 bool IsURLAllowedInIncognito(const GURL& url,
                              content::BrowserContext* browser_context) {
   if (url.scheme() == content::kViewSourceScheme) {
@@ -708,35 +750,11 @@
     stripped_spec.erase(0, strlen(content::kViewSourceScheme) + 1);
     GURL stripped_url(stripped_spec);
     return stripped_url.is_valid() &&
-        IsURLAllowedInIncognito(stripped_url, browser_context);
-  }
-  // Most URLs are allowed in incognito; the following are exceptions.
-  // chrome://extensions is on the list because it redirects to
-  // chrome://settings.
-  if (url.scheme() == content::kChromeUIScheme &&
-      (url.host_piece() == chrome::kChromeUIAppLauncherPageHost ||
-       url.host_piece() == chrome::kChromeUISettingsHost ||
-       url.host_piece() == chrome::kChromeUIHelpHost ||
-       url.host_piece() == chrome::kChromeUIHistoryHost ||
-       url.host_piece() == chrome::kChromeUIExtensionsHost ||
-       url.host_piece() == chrome::kChromeUIBookmarksHost ||
-       url.host_piece() == chrome::kChromeUIChromeSigninHost ||
-       url.host_piece() == chrome::kChromeUIUberHost ||
-       url.host_piece() == chrome::kChromeUIThumbnailHost ||
-       url.host_piece() == chrome::kChromeUIThumbnailHost2 ||
-       url.host_piece() == chrome::kChromeUIThumbnailListHost ||
-       url.host_piece() == chrome::kChromeUISuggestionsHost ||
-       url.host_piece() == chrome::kChromeUIDevicesHost)) {
-    return false;
+           IsURLAllowedInIncognito(stripped_url, browser_context);
   }
 
-  if (url.scheme() == chrome::kChromeSearchScheme &&
-      (url.host_piece() == chrome::kChromeUIThumbnailHost ||
-       url.host_piece() == chrome::kChromeUIThumbnailHost2 ||
-       url.host_piece() == chrome::kChromeUIThumbnailListHost ||
-       url.host_piece() == chrome::kChromeUISuggestionsHost)) {
+  if (!IsHostAllowedInIncognito(url))
     return false;
-  }
 
   GURL rewritten_url = url;
   bool reverse_on_redirect = false;
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc
new file mode 100644
index 0000000..a94b0b0
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.cc
@@ -0,0 +1,300 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win.h"
+#include "chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h"
+
+#include "base/command_line.h"
+#include "base/json/json_writer.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/signin/signin_promo.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
+#include "components/keep_alive_registry/keep_alive_types.h"
+#include "components/keep_alive_registry/scoped_keep_alive.h"
+#include "components/signin/core/browser/signin_metrics.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_ui_message_handler.h"
+#include "ui/views/controls/webview/web_dialog_view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/web_dialogs/web_dialog_delegate.h"
+
+namespace {
+
+// This message must match the one sent in inline_login.js: sendLSTFetchResults.
+constexpr char kLSTFetchResultsMessage[] = "lstFetchResults";
+
+void HandleAllGcpwInfoFetched(
+    std::unique_ptr<ScopedKeepAlive> keep_alive,
+    std::unique_ptr<CredentialProviderSigninInfoFetcher> fetcher,
+    base::Value signin_result,
+    base::Value fetch_result) {
+  DCHECK(signin_result.is_dict());
+  DCHECK(fetch_result.is_dict());
+  if (!signin_result.DictEmpty() && !fetch_result.DictEmpty()) {
+    std::string json_result;
+    signin_result.MergeDictionary(&fetch_result);
+    if (base::JSONWriter::Write(signin_result, &json_result) &&
+        !json_result.empty()) {
+      // TODO(crbug.com/887444) output to the correct pipe the JSON result of
+      // the user sign in.
+    }
+  }
+
+  // Release the fetcher and mark it for eventual delete. It is not immediately
+  // deleted here in case it still wants to do further processing after
+  // returning from this callback
+  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, fetcher.release());
+
+  // Release the keep_alive implicitly and allow the dialog to die.
+}
+
+void HandleSigninCompleteForGcpwLogin(
+    std::unique_ptr<ScopedKeepAlive> keep_alive,
+    base::Value signin_result,
+    const std::string& access_token,
+    const std::string& refresh_token,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+  DCHECK(signin_result.is_dict());
+  DCHECK_EQ(signin_result.DictEmpty(),
+            access_token.empty() && refresh_token.empty());
+  if (!signin_result.DictEmpty()) {
+    // Create the fetcher and pass it to the callback so that it can be
+    // deleted once it is finished.
+    auto fetcher = std::make_unique<CredentialProviderSigninInfoFetcher>(
+        refresh_token, url_loader_factory);
+    fetcher->SetCompletionCallbackAndStart(
+        access_token,
+        base::BindOnce(&HandleAllGcpwInfoFetched, std::move(keep_alive),
+                       std::move(fetcher), std::move(signin_result)));
+  }
+
+  // If the function has not pass ownership of the keep alive yet at this point
+  // this means there was some error reading the sign in result or the result
+  // was empty. In this case, return from the method which will implicitly
+  // release the keep_alive which will close and release everything.
+}
+
+class CredentialProviderWebUIMessageHandler
+    : public content::WebUIMessageHandler {
+ public:
+  explicit CredentialProviderWebUIMessageHandler(
+      HandleGcpwSigninCompleteResult signin_callback)
+      : signin_callback_(std::move(signin_callback)) {}
+
+  // content::WebUIMessageHandler:
+  void RegisterMessages() override {
+    web_ui()->RegisterMessageCallback(
+        kLSTFetchResultsMessage,
+        base::BindRepeating(
+            &CredentialProviderWebUIMessageHandler::OnSigninComplete,
+            base::Unretained(this)));
+  }
+
+ private:
+  base::Value ParseArgs(const base::ListValue* args,
+                        std::string* out_access_token,
+                        std::string* out_refresh_token) {
+    const base::Value* dict_result = nullptr;
+    if (!args || args->empty() || !args->Get(0, &dict_result) ||
+        !dict_result->is_dict()) {
+      return base::Value(base::Value::Type::DICTIONARY);
+    }
+
+    const base::Value* email = dict_result->FindKeyOfType(
+        credential_provider::kKeyEmail, base::Value::Type::STRING);
+    const base::Value* password = dict_result->FindKeyOfType(
+        credential_provider::kKeyPassword, base::Value::Type::STRING);
+    const base::Value* id = dict_result->FindKeyOfType(
+        credential_provider::kKeyId, base::Value::Type::STRING);
+    const base::Value* access_token = dict_result->FindKeyOfType(
+        credential_provider::kKeyAccessToken, base::Value::Type::STRING);
+    const base::Value* refresh_token = dict_result->FindKeyOfType(
+        credential_provider::kKeyRefreshToken, base::Value::Type::STRING);
+
+    if (!email || email->GetString().empty() || !password ||
+        password->GetString().empty() || !id || id->GetString().empty() ||
+        !access_token || access_token->GetString().empty() || !refresh_token ||
+        refresh_token->GetString().empty()) {
+      return base::Value(base::Value::Type::DICTIONARY);
+    }
+
+    *out_access_token = access_token->GetString();
+    *out_refresh_token = refresh_token->GetString();
+    return dict_result->Clone();
+  }
+
+  void OnSigninComplete(const base::ListValue* args) {
+    std::string access_token;
+    std::string refresh_token;
+    base::Value signin_result = ParseArgs(args, &access_token, &refresh_token);
+
+    content::WebContents* contents = web_ui()->GetWebContents();
+    content::StoragePartition* partition =
+        content::BrowserContext::GetStoragePartitionForSite(
+            contents->GetBrowserContext(), signin::GetSigninPartitionURL());
+
+    // Regardless of the results of ParseArgs, |signin_callback_| will always
+    // be called to allow it to release any additional references it may hold
+    // (like the keep_alive in HandleSigninCompleteForGCPWLogin) or perform
+    // possible error handling.
+    std::move(signin_callback_)
+        .Run(std::move(signin_result), access_token, refresh_token,
+             partition->GetURLLoaderFactoryForBrowserProcess());
+  }
+
+  HandleGcpwSigninCompleteResult signin_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(CredentialProviderWebUIMessageHandler);
+};
+
+}  // namespace
+
+// Delegate to control a views::WebDialogView for purposes of showing a gaia
+// sign in page for purposes of the credential provider.
+class CredentialProviderWebDialogDelegate : public ui::WebDialogDelegate {
+ public:
+  // |reauth_email| is used to pre fill in the sign in dialog with the user's
+  // e-mail during a reauthorize sign in. This type of sign in is used to update
+  // the user's password.
+  CredentialProviderWebDialogDelegate(
+      const std::string& reauth_email,
+      HandleGcpwSigninCompleteResult signin_callback)
+      : reauth_email_(reauth_email),
+        signin_callback_(std::move(signin_callback)) {}
+
+  GURL GetDialogContentURL() const override {
+    signin_metrics::AccessPoint access_point =
+        signin_metrics::AccessPoint::ACCESS_POINT_MACHINE_LOGON;
+    signin_metrics::Reason reason =
+        signin_metrics::Reason::REASON_FETCH_LST_ONLY;
+    return reauth_email_.empty()
+               ? signin::GetPromoURLForDialog(access_point, reason, false)
+               : signin::GetReauthURLWithEmailForDialog(access_point, reason,
+                                                        reauth_email_);
+  }
+
+  ui::ModalType GetDialogModalType() const override {
+    return ui::MODAL_TYPE_SYSTEM;
+  }
+
+  base::string16 GetDialogTitle() const override { return base::string16(); }
+
+  base::string16 GetAccessibleDialogTitle() const override {
+    return base::string16();
+  }
+
+  std::string GetDialogName() const override {
+    // Return an empty window name; otherwise chrome will try to persist the
+    // window's position and DCHECK.
+    return std::string();
+  }
+
+  void GetWebUIMessageHandlers(
+      std::vector<content::WebUIMessageHandler*>* handlers) const override {
+    // The WebDialogUI will own and delete this message handler.
+    handlers->push_back(
+        new CredentialProviderWebUIMessageHandler(std::move(signin_callback_)));
+  }
+
+  void GetDialogSize(gfx::Size* size) const override {
+    // TODO(crbug.com/901947): Figure out exactly what size the dialog should
+    // be.
+    size->SetSize(448, 610);
+  }
+
+  void GetMinimumDialogSize(gfx::Size* size) const override {
+    GetDialogSize(size);
+  }
+
+  std::string GetDialogArgs() const override { return std::string(); }
+
+  void OnDialogClosed(const std::string& json_retval) override {
+    // Class owns itself and thus needs to be deleted eventually after the
+    // closed call back has been signalled since it will no longer be accessed
+    // by the WebDialogView.
+    base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+  }
+
+  void OnCloseContents(content::WebContents* source,
+                       bool* out_close_dialog) override {}
+
+  bool HandleContextMenu(const content::ContextMenuParams& params) override {
+    return true;
+  }
+
+  bool ShouldShowDialogTitle() const override { return false; }
+
+ protected:
+  // E-mail used to pre-fill the e-mail field when a reauth signin is required.
+  std::string reauth_email_;
+
+  // Callback that will be called when a valid sign in has been completed
+  // through the dialog.
+  mutable HandleGcpwSigninCompleteResult signin_callback_;
+};
+
+bool ValidateSigninCompleteResult(const std::string& access_token,
+                                  const std::string& refresh_token,
+                                  const base::Value& signin_result) {
+  return !access_token.empty() && !refresh_token.empty() &&
+         signin_result.is_dict();
+}
+
+void StartGCPWSignin(const base::CommandLine& command_line,
+                     content::BrowserContext* context) {
+  // This keep_alive is created since there is no browser created when
+  // --gcpw-logon is specified. Since there is no browser there is no holder of
+  // a ScopedKeepAlive present that will ensure Chrome kills itself when the
+  // last keep alive is released. So instead, keep the keep alive across the
+  // callbacks that will be sent during the signin process. Once the full fetch
+  // of the information necesssary for the GCPW is finished (or there is a
+  // failure) release the keep alive so that Chrome can shutdown.
+
+  ShowCredentialProviderSigninDialog(
+      command_line, context,
+      base::BindOnce(&HandleSigninCompleteForGcpwLogin,
+                     std::make_unique<ScopedKeepAlive>(
+                         KeepAliveOrigin::CREDENTIAL_PROVIDER_SIGNIN_DIALOG,
+                         KeepAliveRestartOption::DISABLED)));
+}
+
+views::WebDialogView* ShowCredentialProviderSigninDialog(
+    const base::CommandLine& command_line,
+    content::BrowserContext* context,
+    HandleGcpwSigninCompleteResult signin_complete_handler) {
+  DCHECK(signin_complete_handler);
+
+  // Open a frameless window whose entire surface displays a gaia sign in web
+  // page.
+  std::string reauth_email =
+      command_line.GetSwitchValueASCII(credential_provider::kGcpwSigninSwitch);
+
+  // Delegate to handle the result of the sign in request. This will
+  // delete itself eventually when it receives the OnDialogClosed call.
+  auto delegate = std::make_unique<CredentialProviderWebDialogDelegate>(
+      reauth_email, std::move(signin_complete_handler));
+
+  // The web dialog view that will contain the web ui for the login screen.
+  // This view will be automatically deleted by the widget that owns it when it
+  // is closed.
+  auto view = std::make_unique<views::WebDialogView>(
+      context, delegate.release(), new ChromeWebContentsHandler);
+  views::Widget::InitParams init_params(
+      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+  views::WebDialogView* web_view = view.release();
+  init_params.name = "GCPW";  // Used for debugging only.
+  init_params.delegate = web_view;
+
+  // This widget will automatically delete itself and its WebDialogView when the
+  // dialog window is closed.
+  views::Widget* widget = new views::Widget;
+  widget->Init(init_params);
+  widget->Show();
+
+  return web_view;
+}
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win.h b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.h
new file mode 100644
index 0000000..7dd099c
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win.h
@@ -0,0 +1,60 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_H_
+#define CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
+
+namespace base {
+class CommandLine;
+class Value;
+}  // namespace base
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
+namespace views {
+class WebDialogView;
+}  // namespace views
+
+// Callback signalled by the dialog when the Gaia sign in flow compltes.
+// Parameters are:
+// 1. A base::Value that is of type DICTIONARY. An empty dictionary signals an
+// error during the signin process
+// 2. The signed in user's access token.
+// 3. The signed in user's refresh token.
+// 4. A URL loader that will be used by various OAuth fetchers.
+using HandleGcpwSigninCompleteResult =
+    base::OnceCallback<void(base::Value,
+                            const std::string&,
+                            const std::string&,
+                            scoped_refptr<network::SharedURLLoaderFactory>)>;
+
+// Starts the Google Credential Provider for Windows (GCPW) Sign in flow. First
+// the function shows a frameless Google account sign in page allowing the user
+// to choose an  account to logon to Windows. Once the signin is complete, the
+// flow will automatically start requesting additional information required by
+// GCPW to complete Windows logon.
+void StartGCPWSignin(const base::CommandLine& command_line,
+                     content::BrowserContext* context);
+
+// This function displays a dialog window with a Gaia signin page. Once
+// the Gaia signin flow is finished, the callback given by
+// |signin_complete_handler| will be called with the results of the signin.
+// The return value is only valid during the lifetime of the dialog.
+views::WebDialogView* ShowCredentialProviderSigninDialog(
+    const base::CommandLine& command_line,
+    content::BrowserContext* context,
+    HandleGcpwSigninCompleteResult signin_complete_handler);
+
+#endif  // CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_H_
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc
new file mode 100644
index 0000000..e44876f
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc
@@ -0,0 +1,344 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/test/test_switches.cc"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win.h"
+#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h"
+#include "chrome/browser/ui/test/test_browser_dialog.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
+#include "chrome/test/base/interactive_test_utils.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "ui/views/controls/webview/web_dialog_view.h"
+#include "ui/views/test/widget_test.h"
+
+#define TEST_TASK_FUNC_NAME_FOR_THREAD_RUNNER(Func) Run##Func##Test
+
+class CredentialProviderSigninDialogWinIntegrationTest;
+
+class SigninDialogLoadingStoppedObserver : public content::WebContentsObserver {
+ public:
+  SigninDialogLoadingStoppedObserver(content::WebContents* web_contents,
+                                     base::OnceClosure idle_closure)
+      : content::WebContentsObserver(web_contents),
+        idle_closure_(std::move(idle_closure)) {}
+
+  void DidStopLoading() override {
+    if (idle_closure_)
+      std::move(idle_closure_).Run();
+  }
+
+  base::OnceClosure idle_closure_;
+};
+
+class CredentialProviderSigninDialogWinBaseTest : public InProcessBrowserTest {
+ protected:
+  CredentialProviderSigninDialogWinBaseTest();
+
+  content::WebContents* web_contents() { return web_contents_; }
+  virtual void WaitForDialogToLoad();
+
+  content::WebContents* web_contents_ = nullptr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CredentialProviderSigninDialogWinBaseTest);
+};
+
+CredentialProviderSigninDialogWinBaseTest::
+    CredentialProviderSigninDialogWinBaseTest()
+    : InProcessBrowserTest() {}
+
+void CredentialProviderSigninDialogWinBaseTest::WaitForDialogToLoad() {
+  EXPECT_TRUE(web_contents());
+
+  base::RunLoop run_loop;
+  SigninDialogLoadingStoppedObserver observer(web_contents(),
+                                              run_loop.QuitWhenIdleClosure());
+  run_loop.Run();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CredentialProviderSigninDialogWinDialogTest tests the dialog portion of the
+// credential provider sign in without checking whether the fetch of additional
+// information was successful.
+
+class CredentialProviderSigninDialogWinDialogTest
+    : public CredentialProviderSigninDialogWinBaseTest {
+ protected:
+  CredentialProviderSigninDialogWinDialogTest();
+
+  void SendSigninCompleteMessage(const base::Value& value);
+  void SendValidSigninCompleteMessage();
+  void WaitForSigninCompleteMessage();
+
+  void ShowSigninDialog();
+
+  // A HandleGCPWSiginCompleteResult callback to check that the signin dialog
+  // has correctly received and procesed the sign in complete message.
+  void HandleSignInComplete(
+      base::Value signin_result,
+      const std::string& access_token,
+      const std::string& refresh_token,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader);
+  bool signin_complete_called_ = false;
+
+  std::string result_access_token_;
+  std::string result_refresh_token_;
+  base::Value result_value_;
+  CredentialProviderSigninDialogTestDataStorage test_data_storage_;
+
+ private:
+  base::OnceClosure signin_complete_closure_;
+
+  DISALLOW_COPY_AND_ASSIGN(CredentialProviderSigninDialogWinDialogTest);
+};
+
+CredentialProviderSigninDialogWinDialogTest::
+    CredentialProviderSigninDialogWinDialogTest()
+    : CredentialProviderSigninDialogWinBaseTest() {}
+
+void CredentialProviderSigninDialogWinDialogTest::SendSigninCompleteMessage(
+    const base::Value& value) {
+  std::string json_string;
+  EXPECT_TRUE(base::JSONWriter::Write(value, &json_string));
+
+  std::string login_complete_message =
+      "chrome.send('lstFetchResults', [" + json_string + "]);";
+  content::RenderFrameHost* root = web_contents()->GetMainFrame();
+  content::ExecuteScriptAsync(root, login_complete_message);
+  WaitForSigninCompleteMessage();
+}
+
+void CredentialProviderSigninDialogWinDialogTest::
+    SendValidSigninCompleteMessage() {
+  SendSigninCompleteMessage(test_data_storage_.MakeValidSignInResponseValue());
+}
+
+void CredentialProviderSigninDialogWinDialogTest::
+    WaitForSigninCompleteMessage() {
+  // Run until the dialog has received the signin complete message.
+  base::RunLoop run_loop;
+  signin_complete_closure_ = run_loop.QuitWhenIdleClosure();
+  run_loop.Run();
+}
+
+void CredentialProviderSigninDialogWinDialogTest::ShowSigninDialog() {
+  views::WebDialogView* web_view = ShowCredentialProviderSigninDialog(
+      base::CommandLine(base::CommandLine::NoProgram::NO_PROGRAM),
+      browser()->profile(),
+      base::BindOnce(
+          &CredentialProviderSigninDialogWinDialogTest::HandleSignInComplete,
+          base::Unretained(this)));
+
+  web_contents_ = web_view->web_contents();
+}
+
+void CredentialProviderSigninDialogWinDialogTest::HandleSignInComplete(
+    base::Value signin_result,
+    const std::string& access_token,
+    const std::string& refresh_token,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader) {
+  result_access_token_ = access_token;
+  result_refresh_token_ = refresh_token;
+  EXPECT_FALSE(signin_complete_called_);
+  signin_complete_called_ = true;
+  result_value_ = std::move(signin_result);
+
+  if (signin_complete_closure_)
+    std::move(signin_complete_closure_).Run();
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+                       SendEmptySigninComplete) {
+  ShowSigninDialog();
+  WaitForDialogToLoad();
+  SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue());
+  EXPECT_TRUE(signin_complete_called_);
+  EXPECT_TRUE(result_value_.is_dict());
+  EXPECT_TRUE(result_value_.DictEmpty());
+  EXPECT_TRUE(result_access_token_.empty());
+  EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+                       SendInvalidSigninCompleteNoId) {
+  ShowSigninDialog();
+  WaitForDialogToLoad();
+  SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue(
+      std::string(), test_data_storage_.GetSuccessPassword(),
+      test_data_storage_.GetSuccessEmail(),
+      test_data_storage_.GetSuccessAccessToken(),
+      test_data_storage_.GetSuccessRefreshToken()));
+  EXPECT_TRUE(signin_complete_called_);
+  EXPECT_TRUE(result_value_.is_dict());
+  EXPECT_TRUE(result_value_.DictEmpty());
+  EXPECT_TRUE(result_access_token_.empty());
+  EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+                       SendInvalidSigninCompleteNoPassword) {
+  ShowSigninDialog();
+  WaitForDialogToLoad();
+  SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue(
+      test_data_storage_.GetSuccessId(), std::string(),
+      test_data_storage_.GetSuccessEmail(),
+      test_data_storage_.GetSuccessAccessToken(),
+      test_data_storage_.GetSuccessRefreshToken()));
+  EXPECT_TRUE(signin_complete_called_);
+  EXPECT_TRUE(result_value_.is_dict());
+  EXPECT_TRUE(result_value_.DictEmpty());
+  EXPECT_TRUE(result_access_token_.empty());
+  EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+                       SendInvalidSigninCompleteNoEmail) {
+  ShowSigninDialog();
+  WaitForDialogToLoad();
+  SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue(
+      test_data_storage_.GetSuccessId(),
+      test_data_storage_.GetSuccessPassword(), std::string(),
+      test_data_storage_.GetSuccessAccessToken(),
+      test_data_storage_.GetSuccessRefreshToken()));
+  EXPECT_TRUE(signin_complete_called_);
+  EXPECT_TRUE(result_value_.is_dict());
+  EXPECT_TRUE(result_value_.DictEmpty());
+  EXPECT_TRUE(result_access_token_.empty());
+  EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+                       SendInvalidSigninCompleteNoAccessToken) {
+  ShowSigninDialog();
+  WaitForDialogToLoad();
+  SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue(
+      test_data_storage_.GetSuccessId(),
+      test_data_storage_.GetSuccessPassword(),
+      test_data_storage_.GetSuccessEmail(), std::string(),
+      test_data_storage_.GetSuccessRefreshToken()));
+  EXPECT_TRUE(signin_complete_called_);
+  EXPECT_TRUE(result_value_.is_dict());
+  EXPECT_TRUE(result_value_.DictEmpty());
+  EXPECT_TRUE(result_access_token_.empty());
+  EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+                       SendInvalidSigninCompleteNoRefreshToken) {
+  ShowSigninDialog();
+  WaitForDialogToLoad();
+  SendSigninCompleteMessage(test_data_storage_.MakeSignInResponseValue(
+      test_data_storage_.GetSuccessId(),
+      test_data_storage_.GetSuccessPassword(),
+      test_data_storage_.GetSuccessEmail(),
+      test_data_storage_.GetSuccessAccessToken(), std::string()));
+  EXPECT_TRUE(signin_complete_called_);
+  EXPECT_TRUE(result_value_.is_dict());
+  EXPECT_TRUE(result_value_.DictEmpty());
+  EXPECT_TRUE(result_access_token_.empty());
+  EXPECT_TRUE(result_refresh_token_.empty());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinDialogTest,
+                       SuccessfulLoginMessage) {
+  ShowSigninDialog();
+  WaitForDialogToLoad();
+  SendValidSigninCompleteMessage();
+  EXPECT_TRUE(signin_complete_called_);
+  EXPECT_TRUE(result_value_.is_dict());
+  EXPECT_FALSE(result_value_.DictEmpty());
+  const base::DictionaryValue* result_dict;
+  EXPECT_TRUE(result_value_.GetAsDictionary(&result_dict));
+  std::string id_in_dict;
+  EXPECT_TRUE(result_dict->GetString("id", &id_in_dict));
+  std::string email_in_dict;
+  EXPECT_TRUE(result_dict->GetString("email", &email_in_dict));
+  std::string password_in_dict;
+  EXPECT_TRUE(result_dict->GetString("password", &password_in_dict));
+
+  EXPECT_EQ(id_in_dict, test_data_storage_.GetSuccessId());
+  EXPECT_EQ(email_in_dict, test_data_storage_.GetSuccessEmail());
+  EXPECT_EQ(password_in_dict, test_data_storage_.GetSuccessPassword());
+  EXPECT_EQ(result_access_token_, test_data_storage_.GetSuccessAccessToken());
+  EXPECT_EQ(result_refresh_token_, test_data_storage_.GetSuccessRefreshToken());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CredentialProviderSigninDialogWinIntegrationTest is used for testing the
+// integration of the dialog into Chrome, This test mainly verifies correct
+// start up state if we provide the --gcpw-signin switch.
+
+class CredentialProviderSigninDialogWinIntegrationTest
+    : public CredentialProviderSigninDialogWinBaseTest {
+ protected:
+  CredentialProviderSigninDialogWinIntegrationTest();
+
+  // InProcessBrowserTest:
+  void SetUpCommandLine(base::CommandLine* command_line) override;
+
+  // CredentialProviderSigninDialogWinBaseTest:
+  void WaitForDialogToLoad() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CredentialProviderSigninDialogWinIntegrationTest);
+};
+
+CredentialProviderSigninDialogWinIntegrationTest::
+    CredentialProviderSigninDialogWinIntegrationTest()
+    : CredentialProviderSigninDialogWinBaseTest() {}
+
+void CredentialProviderSigninDialogWinIntegrationTest::SetUpCommandLine(
+    base::CommandLine* command_line) {
+  command_line->AppendSwitch(::credential_provider::kGcpwSigninSwitch);
+}
+
+void CredentialProviderSigninDialogWinIntegrationTest::WaitForDialogToLoad() {
+  // The browser has already been created by the time this start starts and
+  // web_contents_ is not yet available. In this run case there should only
+  // be one widget available and that widget should contain the web contents
+  // needed for the test.
+  EXPECT_FALSE(web_contents_);
+  views::Widget::Widgets all_widgets = views::test::WidgetTest::GetAllWidgets();
+  EXPECT_EQ(all_widgets.size(), 1ull);
+  views::WebDialogView* web_dialog = static_cast<views::WebDialogView*>(
+      (*all_widgets.begin())->GetContentsView());
+  web_contents_ = web_dialog->web_contents();
+  EXPECT_TRUE(web_contents_);
+
+  CredentialProviderSigninDialogWinBaseTest::WaitForDialogToLoad();
+
+  // When running with --gcpw-signin, browser creation is completely bypassed
+  // only a dialog for the signin should be created directly. In a normal
+  // browser test, there is always a browser created so make sure that is not
+  // the case for our tests.
+  EXPECT_FALSE(browser());
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinIntegrationTest,
+                       ShowDialogOnlyTest) {
+  WaitForDialogToLoad();
+  EXPECT_EQ(Profile::ProfileType::INCOGNITO_PROFILE,
+            ((Profile*)(web_contents_->GetBrowserContext()))->GetProfileType());
+  views::Widget::Widgets all_widgets = views::test::WidgetTest::GetAllWidgets();
+  (*all_widgets.begin())->Close();
+  RunUntilBrowserProcessQuits();
+}
+
+IN_PROC_BROWSER_TEST_F(CredentialProviderSigninDialogWinIntegrationTest,
+                       EscapeClosesDialogTest) {
+  WaitForDialogToLoad();
+  views::Widget::Widgets all_widgets = views::test::WidgetTest::GetAllWidgets();
+  ui::KeyEvent escape_key_event(ui::EventType::ET_KEY_PRESSED,
+                                ui::KeyboardCode::VKEY_ESCAPE,
+                                ui::DomCode::ESCAPE, 0);
+  (*all_widgets.begin())->OnKeyEvent(&escape_key_event);
+  RunUntilBrowserProcessQuits();
+}
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.cc b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.cc
new file mode 100644
index 0000000..22215b6
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.cc
@@ -0,0 +1,60 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h"
+
+#include <string>
+
+CredentialProviderSigninDialogTestDataStorage::
+    CredentialProviderSigninDialogTestDataStorage()
+    : expected_success_signin_result_(base::Value::Type::DICTIONARY),
+      expected_success_fetch_result_(base::Value::Type::DICTIONARY) {
+  expected_success_signin_result_.SetKey("id", base::Value("gaia_user_id"));
+  expected_success_signin_result_.SetKey("password", base::Value("password"));
+  expected_success_signin_result_.SetKey("email", base::Value("foo@xyz.com"));
+  expected_success_signin_result_.SetKey("access_token",
+                                         base::Value("access_token"));
+  expected_success_signin_result_.SetKey("refresh_token",
+                                         base::Value("refresh_token"));
+  expected_success_fetch_result_.SetKey("token_handle",
+                                        base::Value("token_handle"));
+  expected_success_fetch_result_.SetKey("mdm_id_token",
+                                        base::Value("mdm_token"));
+  expected_success_fetch_result_.SetKey("full_name", base::Value("Foo Bar"));
+
+  expected_success_full_result_ = expected_success_signin_result_.Clone();
+  expected_success_full_result_.MergeDictionary(
+      &expected_success_fetch_result_);
+}
+
+// static
+base::Value
+CredentialProviderSigninDialogTestDataStorage::MakeSignInResponseValue(
+    const std::string& id,
+    const std::string& password,
+    const std::string& email,
+    const std::string& access_token,
+    const std::string& refresh_token) {
+  base::Value args(base::Value::Type::DICTIONARY);
+  if (!email.empty())
+    args.SetKey("email", base::Value(email));
+  if (!password.empty())
+    args.SetKey("password", base::Value(password));
+  if (!id.empty())
+    args.SetKey("id", base::Value(id));
+  if (!refresh_token.empty())
+    args.SetKey("refresh_token", base::Value(refresh_token));
+  if (!access_token.empty())
+    args.SetKey("access_token", base::Value(access_token));
+
+  return args;
+}
+
+base::Value
+CredentialProviderSigninDialogTestDataStorage::MakeValidSignInResponseValue()
+    const {
+  return MakeSignInResponseValue(GetSuccessId(), GetSuccessPassword(),
+                                 GetSuccessEmail(), GetSuccessAccessToken(),
+                                 GetSuccessRefreshToken());
+}
diff --git a/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h
new file mode 100644
index 0000000..ed1d4bc
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h
@@ -0,0 +1,88 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_TEST_DATA_H_
+#define CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_TEST_DATA_H_
+
+#include <string>
+
+#include "base/values.h"
+
+// Class used to store common test data used to validate the functioning of the
+// credential provider sign in dialog. This class stores the expected login
+// complte information that the dialog is supposed to received from the gaia
+// sign in as well as the expected values for any additional token / info
+// fetches needed to complete the sign in using the credential provider.
+// On a successful sign in result, we expect the final json result to match
+// the json result generated from the internal expected_success_result_
+// value.
+class CredentialProviderSigninDialogTestDataStorage {
+ public:
+  CredentialProviderSigninDialogTestDataStorage();
+
+  static base::Value MakeSignInResponseValue(
+      const std::string& id = std::string(),
+      const std::string& password = std::string(),
+      const std::string& email = std::string(),
+      const std::string& access_token = std::string(),
+      const std::string& refresh_token = std::string());
+  base::Value MakeValidSignInResponseValue() const;
+
+  std::string GetSuccessId() const {
+    return expected_success_signin_result_.FindKey("id")->GetString();
+  }
+  std::string GetSuccessPassword() const {
+    return expected_success_signin_result_.FindKey("password")->GetString();
+  }
+  std::string GetSuccessEmail() const {
+    return expected_success_signin_result_.FindKey("email")->GetString();
+  }
+  std::string GetSuccessAccessToken() const {
+    return expected_success_signin_result_.FindKey("access_token")->GetString();
+  }
+  std::string GetSuccessRefreshToken() const {
+    return expected_success_signin_result_.FindKey("refresh_token")
+        ->GetString();
+  }
+  std::string GetSuccessTokenHandle() const {
+    return expected_success_fetch_result_.FindKey("token_handle")->GetString();
+  }
+  std::string GetSuccessMdmIdToken() const {
+    return expected_success_fetch_result_.FindKey("mdm_id_token")->GetString();
+  }
+  std::string GetSuccessFullName() const {
+    return expected_success_fetch_result_.FindKey("full_name")->GetString();
+  }
+
+  const base::Value& expected_signin_result() const {
+    return expected_success_signin_result_;
+  }
+
+  const base::Value& expected_success_fetch_result() const {
+    return expected_success_fetch_result_;
+  }
+
+  const base::Value& expected_full_result() const {
+    return expected_success_full_result_;
+  }
+
+  bool EqualsSuccessfulSigninResult(const base::Value& result_value) const {
+    return EqualsEncodedValue(expected_signin_result(), result_value);
+  }
+  bool EqualsSccessfulFetchResult(const base::Value& result_value) const {
+    return EqualsEncodedValue(expected_success_fetch_result(), result_value);
+  }
+
+ private:
+  bool EqualsEncodedValue(const base::Value& success_value,
+                          const base::Value& result_value) const {
+    return result_value == success_value;
+  }
+
+  base::Value expected_success_signin_result_;
+  base::Value expected_success_fetch_result_;
+  base::Value expected_success_full_result_;
+};
+
+#endif  // CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_DIALOG_WIN_TEST_DATA_H_
diff --git a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc
new file mode 100644
index 0000000..f472311
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.cc
@@ -0,0 +1,129 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+#include <vector>
+
+#include "chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h"
+
+#include "base/logging.h"
+#include "base/syslog_logging.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
+#include "google_apis/google_api_keys.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+CredentialProviderSigninInfoFetcher::CredentialProviderSigninInfoFetcher(
+    const std::string& refresh_token,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+    : scoped_access_token_fetcher_(
+          std::make_unique<OAuth2AccessTokenFetcherImpl>(this,
+                                                         url_loader_factory,
+                                                         refresh_token)),
+      user_info_fetcher_(
+          std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory)),
+      token_handle_fetcher_(
+          std::make_unique<gaia::GaiaOAuthClient>(url_loader_factory)) {}
+
+CredentialProviderSigninInfoFetcher::~CredentialProviderSigninInfoFetcher() =
+    default;
+
+void CredentialProviderSigninInfoFetcher::SetCompletionCallbackAndStart(
+    const std::string& access_token,
+    FetchCompletionCallback completion_callback) {
+  DCHECK(!completion_callback.is_null());
+  completion_callback_ = std::move(completion_callback);
+  GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
+
+  // Scopes needed to fetch the full name of the user as well as an id token
+  // used for MDM registration.
+  std::vector<std::string> access_scopes{"email", "profile", "openid"};
+
+  scoped_access_token_fetcher_->Start(gaia_urls->oauth2_chrome_client_id(),
+                                      gaia_urls->oauth2_chrome_client_secret(),
+                                      access_scopes);
+  token_handle_fetcher_->GetTokenInfo(access_token, 0, this);
+}
+
+void CredentialProviderSigninInfoFetcher::OnGetTokenInfoResponse(
+    std::unique_ptr<base::DictionaryValue> token_info) {
+  DCHECK(token_handle_.empty());
+  bool has_error = !token_info->GetString("token_handle", &token_handle_) ||
+                   token_handle_.empty();
+  WriteResultsIfFinished(has_error);
+}
+
+void CredentialProviderSigninInfoFetcher::OnGetUserInfoResponse(
+    std::unique_ptr<base::DictionaryValue> user_info) {
+  DCHECK(!mdm_id_token_.empty());
+  DCHECK(full_name_.empty());
+  bool has_error =
+      !user_info->GetString("name", &full_name_) || full_name_.empty();
+  WriteResultsIfFinished(has_error);
+}
+
+void CredentialProviderSigninInfoFetcher::OnOAuthError() {
+  WriteResultsIfFinished(true);
+}
+
+void CredentialProviderSigninInfoFetcher::OnNetworkError(int response_code) {
+  SYSLOG(ERROR) << "Network error occured while fetching token handle: "
+                << response_code;
+  WriteResultsIfFinished(true);
+}
+
+void CredentialProviderSigninInfoFetcher::OnGetTokenSuccess(
+    const TokenResponse& token_response) {
+  DCHECK(mdm_id_token_.empty());
+  DCHECK(full_name_.empty());
+  mdm_id_token_ = token_response.id_token;
+
+  if (mdm_id_token_.empty() || token_response.access_token.empty()) {
+    WriteResultsIfFinished(true);
+    return;
+  }
+
+  // Once a valid access token is given for fetching the user's full name, fire
+  // off a request to get the user's info.
+  RequestUserInfoFromAccessToken(token_response.access_token);
+}
+
+void CredentialProviderSigninInfoFetcher::OnGetTokenFailure(
+    const GoogleServiceAuthError& error) {
+  WriteResultsIfFinished(true);
+}
+
+void CredentialProviderSigninInfoFetcher::RequestUserInfoFromAccessToken(
+    const std::string& access_token) {
+  user_info_fetcher_->GetUserInfo(access_token, 0, this);
+}
+
+void CredentialProviderSigninInfoFetcher::WriteResultsIfFinished(
+    bool has_error) {
+  DCHECK(completion_callback_);
+
+  if (!has_error &&
+      (mdm_id_token_.empty() || full_name_.empty() || token_handle_.empty())) {
+    return;
+  }
+
+  base::Value fetch_result(base::Value::Type::DICTIONARY);
+  if (!has_error) {
+    fetch_result.SetKey(credential_provider::kKeyMdmIdToken,
+                        base::Value(mdm_id_token_));
+    fetch_result.SetKey(credential_provider::kKeyFullname,
+                        base::Value(full_name_));
+    fetch_result.SetKey(credential_provider::kKeyTokenHandle,
+                        base::Value(token_handle_));
+  }
+
+  std::move(completion_callback_).Run(std::move(fetch_result));
+
+  scoped_access_token_fetcher_.reset();
+  user_info_fetcher_.reset();
+  token_handle_fetcher_.reset();
+}
diff --git a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h
new file mode 100644
index 0000000..7253bcd
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h
@@ -0,0 +1,81 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_INFO_FETCHER_WIN_H_
+#define CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_INFO_FETCHER_WIN_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/values.h"
+#include "google_apis/gaia/gaia_oauth_client.h"
+#include "google_apis/gaia/oauth2_access_token_fetcher.h"
+
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
+// Helper class used to query additional information needed to sign in or
+// create a new user through the Google Credential Provider for Windows. The
+// additional information needed is:
+// - User's full name.
+// - ID token used for Mobile Device Management (MDM) registration.
+// - A token handle for the user's refresh token.
+// A separate OAuth request is required for each piece of information and
+// each result arrives asynchronously so to gather all the results until they
+// have all been fetched or there is an error. Once one of the two conditions
+// are met notify the callback of the results.
+class CredentialProviderSigninInfoFetcher
+    : public gaia::GaiaOAuthClient::Delegate,
+      public OAuth2AccessTokenConsumer {
+ public:
+  // Callback signalled when the fetch of all necessary information for the GCPW
+  // is finished successfully or with an error.
+  // The single argument should always be a dictionary value and will be empty
+  // if there was an error during the fetch.
+  using FetchCompletionCallback = base::OnceCallback<void(base::Value)>;
+
+  CredentialProviderSigninInfoFetcher(
+      const std::string& refresh_token,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+  ~CredentialProviderSigninInfoFetcher() override;
+
+  void SetCompletionCallbackAndStart(
+      const std::string& access_token,
+      FetchCompletionCallback completion_callback);
+
+  // gaia::GaiaOAuthClient::Delegate:
+  void OnGetTokenInfoResponse(
+      std::unique_ptr<base::DictionaryValue> token_info) override;
+  void OnGetUserInfoResponse(
+      std::unique_ptr<base::DictionaryValue> user_info) override;
+  void OnOAuthError() override;
+  void OnNetworkError(int response_code) override;
+
+  // OAuth2AccessTokenConsumer:
+  void OnGetTokenSuccess(const TokenResponse& token_response) override;
+  void OnGetTokenFailure(const GoogleServiceAuthError& error) override;
+
+ protected:
+  void RequestUserInfoFromAccessToken(const std::string& access_token);
+  void WriteResultsIfFinished(bool has_error);
+
+  // This callback is triggered once all fetch requests have completed
+  // successfully or there was an error in one of the fetch requests.
+  FetchCompletionCallback completion_callback_;
+
+  std::string token_handle_;
+  std::string full_name_;
+  std::string mdm_id_token_;
+
+  std::unique_ptr<OAuth2AccessTokenFetcher> scoped_access_token_fetcher_;
+  std::unique_ptr<gaia::GaiaOAuthClient> user_info_fetcher_;
+  std::unique_ptr<gaia::GaiaOAuthClient> token_handle_fetcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(CredentialProviderSigninInfoFetcher);
+};
+
+#endif  // CHROME_BROWSER_UI_STARTUP_CREDENTIAL_PROVIDER_SIGNIN_INFO_FETCHER_WIN_H_
diff --git a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc
new file mode 100644
index 0000000..0a4f2893
--- /dev/null
+++ b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc
@@ -0,0 +1,231 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win.h"
+#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/json/json_reader.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "services/network/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+constexpr char kAccessTokenValue[] = "test_access_token_value";
+constexpr char kRefreshTokenValue[] = "test_refresh_token_value";
+constexpr char kInvalidTokenInfoResponse[] =
+    "{"
+    "  \"error\": \"invalid_token\""
+    "}";
+constexpr char kInvalidUserInfoResponse[] =
+    "{"
+    "  \"error\": \"invalid_token\""
+    "}";
+constexpr char kInvalidAccessTokenFetchResponse[] =
+    "{"
+    "  \"error\": \"invalid_token\""
+    "}";
+}  // namespace
+
+// Provides base functionality for the AccessTokenFetcher Tests below.  The
+// FakeURLFetcherFactory allows us to override the response data and payload for
+// specified URLs.  We use this to stub out network calls made by the
+// AccessTokenFetcher.  This fixture also creates an IO MessageLoop, if
+// necessary, for use by the AccessTokenFetcher.
+class CredentialProviderFetcherTest : public ::testing::Test {
+ protected:
+  CredentialProviderFetcherTest();
+  ~CredentialProviderFetcherTest() override;
+
+  void OnFetchComplete(base::OnceClosure done_closure,
+                       base::Value fetch_result);
+
+  void SetFakeResponses(const std::string& access_token_fetch_data,
+                        net::HttpStatusCode access_token_fetch_code,
+                        int access_token_net_error,
+                        const std::string& user_info_data,
+                        net::HttpStatusCode user_info_code,
+                        int user_info_net_error,
+                        const std::string& token_info_data,
+                        net::HttpStatusCode token_info_code,
+                        int token_info_net_error);
+
+  scoped_refptr<network::SharedURLLoaderFactory> shared_factory() {
+    return shared_factory_;
+  }
+
+  void RunFetcher();
+
+  // Used for result verification
+  base::Value fetch_result_;
+  CredentialProviderSigninDialogTestDataStorage test_data_storage_;
+
+  std::string valid_token_info_response_;
+  std::string valid_user_info_response_;
+  std::string valid_access_token_fetch_response_;
+
+ private:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CredentialProviderFetcherTest);
+};
+
+CredentialProviderFetcherTest::CredentialProviderFetcherTest()
+    : shared_factory_(
+          base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+              &test_url_loader_factory_)) {
+  valid_token_info_response_ =
+      "{"
+      "  \"audience\": \"blah.apps.googleusercontent.blah.com\","
+      "  \"used_id\": \"1234567890\","
+      "  \"scope\": \"all the things\","
+      "  \"expires_in\": 1800,"
+      "  \"token_type\": \"Bearer\","
+      "  \"token_handle\": \"" +
+      test_data_storage_.GetSuccessTokenHandle() +
+      "\""
+      "}";
+  valid_user_info_response_ =
+      "{"
+      "  \"name\": \"" +
+      test_data_storage_.GetSuccessFullName() +
+      "\""
+      "}";
+  valid_access_token_fetch_response_ =
+      "{"
+      "  \"access_token\": \"123456789\","
+      "  \"id_token\": \"" +
+      test_data_storage_.GetSuccessMdmIdToken() +
+      "\","
+      "  \"expires_in\": 1800"
+      "}";
+}
+
+CredentialProviderFetcherTest::~CredentialProviderFetcherTest() = default;
+
+void CredentialProviderFetcherTest::OnFetchComplete(
+    base::OnceClosure done_closure,
+    base::Value fetch_result) {
+  EXPECT_TRUE(fetch_result.is_dict());
+  fetch_result_ = std::move(fetch_result);
+
+  std::move(done_closure).Run();
+}
+
+void CredentialProviderFetcherTest::SetFakeResponses(
+    const std::string& access_token_fetch_data,
+    net::HttpStatusCode access_token_fetch_code,
+    int access_token_net_error,
+    const std::string& user_info_data,
+    net::HttpStatusCode user_info_code,
+    int user_info_net_error,
+    const std::string& token_info_data,
+    net::HttpStatusCode token_info_code,
+    int token_info_net_error) {
+  test_url_loader_factory_.AddResponse(
+      GaiaUrls::GetInstance()->oauth2_token_info_url(),
+      network::CreateResourceResponseHead(token_info_code), token_info_data,
+      network::URLLoaderCompletionStatus(token_info_net_error));
+
+  test_url_loader_factory_.AddResponse(
+      GaiaUrls::GetInstance()->oauth_user_info_url(),
+      network::CreateResourceResponseHead(user_info_code), user_info_data,
+      network::URLLoaderCompletionStatus(user_info_net_error));
+
+  test_url_loader_factory_.AddResponse(
+      GaiaUrls::GetInstance()->oauth2_token_url(),
+      network::CreateResourceResponseHead(access_token_fetch_code),
+      access_token_fetch_data,
+      network::URLLoaderCompletionStatus(access_token_net_error));
+}
+
+void CredentialProviderFetcherTest::RunFetcher() {
+  base::RunLoop run_loop;
+  auto fetcher_callback =
+      base::BindOnce(&CredentialProviderFetcherTest::OnFetchComplete,
+                     base::Unretained(this), run_loop.QuitClosure());
+
+  CredentialProviderSigninInfoFetcher fetcher(kRefreshTokenValue,
+                                              shared_factory());
+  fetcher.SetCompletionCallbackAndStart(kAccessTokenValue,
+                                        std::move(fetcher_callback));
+  run_loop.Run();
+}
+
+TEST_F(CredentialProviderFetcherTest, ValidFetchResult) {
+  SetFakeResponses(valid_access_token_fetch_response_, net::HTTP_OK, net::OK,
+                   valid_user_info_response_, net::HTTP_OK, net::OK,
+                   valid_token_info_response_, net::HTTP_OK, net::OK);
+
+  RunFetcher();
+  EXPECT_FALSE(fetch_result_.DictEmpty());
+  EXPECT_TRUE(test_data_storage_.EqualsSccessfulFetchResult(fetch_result_));
+}
+
+TEST_F(CredentialProviderFetcherTest,
+       ValidFetchResultWithNetworkErrorOnTokenFetch) {
+  SetFakeResponses(valid_access_token_fetch_response_, net::HTTP_BAD_REQUEST,
+                   net::ERR_FAILED, valid_user_info_response_, net::HTTP_OK,
+                   net::OK, valid_token_info_response_, net::HTTP_OK, net::OK);
+
+  RunFetcher();
+  EXPECT_TRUE(fetch_result_.DictEmpty());
+}
+
+TEST_F(CredentialProviderFetcherTest,
+       ValidFetchResultWithNetworkErrorOnUserInfoFetch) {
+  SetFakeResponses(valid_access_token_fetch_response_, net::HTTP_OK, net::OK,
+                   valid_user_info_response_, net::HTTP_BAD_REQUEST,
+                   net::ERR_FAILED, valid_token_info_response_, net::HTTP_OK,
+                   net::OK);
+
+  RunFetcher();
+  EXPECT_TRUE(fetch_result_.DictEmpty());
+}
+
+TEST_F(CredentialProviderFetcherTest, InvalidAccessTokenFetch) {
+  SetFakeResponses(kInvalidAccessTokenFetchResponse, net::HTTP_OK, net::OK,
+                   valid_user_info_response_, net::HTTP_OK, net::OK,
+                   valid_token_info_response_, net::HTTP_OK, net::OK);
+
+  RunFetcher();
+  EXPECT_TRUE(fetch_result_.DictEmpty());
+}
+
+TEST_F(CredentialProviderFetcherTest, InvalidUserInfoFetch) {
+  SetFakeResponses(valid_access_token_fetch_response_, net::HTTP_OK, net::OK,
+                   kInvalidUserInfoResponse, net::HTTP_OK, net::OK,
+                   valid_token_info_response_, net::HTTP_OK, net::OK);
+
+  RunFetcher();
+  EXPECT_TRUE(fetch_result_.DictEmpty());
+}
+
+TEST_F(CredentialProviderFetcherTest, InvalidTokenInfoFetch) {
+  SetFakeResponses(valid_access_token_fetch_response_, net::HTTP_OK, net::OK,
+                   valid_user_info_response_, net::HTTP_OK, net::OK,
+                   kInvalidTokenInfoResponse, net::HTTP_OK, net::OK);
+
+  RunFetcher();
+  EXPECT_TRUE(fetch_result_.DictEmpty());
+}
+
+TEST_F(CredentialProviderFetcherTest, InvalidFetchResult) {
+  SetFakeResponses(kInvalidAccessTokenFetchResponse, net::HTTP_OK, net::OK,
+                   kInvalidUserInfoResponse, net::HTTP_OK, net::OK,
+                   kInvalidTokenInfoResponse, net::HTTP_OK, net::OK);
+
+  RunFetcher();
+  EXPECT_TRUE(fetch_result_.DictEmpty());
+}
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index 2e13111..2ac28dc 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -93,6 +93,7 @@
 #include "chrome/browser/metrics/jumplist_metrics_win.h"
 #include "chrome/browser/notifications/win/notification_launch_id.h"
 #include "chrome/browser/ui/webui/settings/reset_settings_handler.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 #endif
 
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
@@ -329,6 +330,12 @@
                  << "browser session.";
   }
 
+#if defined(OS_WIN)
+  // Continue with the incognito profile if this is a credential provider logon.
+  if (command_line.HasSwitch(credential_provider::kGcpwSigninSwitch))
+    profile = profile->GetOffTheRecordProfile();
+#endif
+
   // Note: This check should have been done in ProcessCmdLineImpl()
   // before calling this function. However chromeos/login/login_utils.cc
   // calls this function directly (see comments there) so it has to be checked
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 5da96407..63914ac 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -77,6 +77,8 @@
 #endif  // defined(GOOGLE_CHROME_BUILD)
 #include "chrome/browser/notifications/notification_platform_bridge_win.h"
 #include "chrome/browser/shell_integration_win.h"
+#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 #endif  // defined(OS_WIN)
 
 #if BUILDFLAG(ENABLE_RLZ)
@@ -109,16 +111,18 @@
   LM_SHORTCUT_TASKBAR = 8,      // Launched from the taskbar.
   LM_USER_EXPERIMENT = 9,  // Launched after acceptance of a user experiment.
   LM_OTHER_OS = 10,        // Result bucket for OSes with no coverage here.
-  LM_MAC_UNDOCKED_DISK_LAUNCH = 11,   // Undocked launch from disk.
-  LM_MAC_DOCKED_DISK_LAUNCH = 12,     // Docked launch from disk.
-  LM_MAC_UNDOCKED_DMG_LAUNCH = 13,    // Undocked launch from a dmg.
-  LM_MAC_DOCKED_DMG_LAUNCH = 14,      // Docked launch from a dmg.
-  LM_MAC_DOCK_STATUS_ERROR = 15,      // Error determining dock status.
-  LM_MAC_DMG_STATUS_ERROR = 16,       // Error determining dmg status.
-  LM_MAC_DOCK_DMG_STATUS_ERROR = 17,  // Error determining dock and dmg status.
-  LM_WIN_PLATFORM_NOTIFICATION = 18,  // Launched from toast notification
-                                      // activation on Windows.
-  LM_SHORTCUT_START_MENU = 19,        // A Windows Start Menu shortcut.
+  LM_MAC_UNDOCKED_DISK_LAUNCH = 11,    // Undocked launch from disk.
+  LM_MAC_DOCKED_DISK_LAUNCH = 12,      // Docked launch from disk.
+  LM_MAC_UNDOCKED_DMG_LAUNCH = 13,     // Undocked launch from a dmg.
+  LM_MAC_DOCKED_DMG_LAUNCH = 14,       // Docked launch from a dmg.
+  LM_MAC_DOCK_STATUS_ERROR = 15,       // Error determining dock status.
+  LM_MAC_DMG_STATUS_ERROR = 16,        // Error determining dmg status.
+  LM_MAC_DOCK_DMG_STATUS_ERROR = 17,   // Error determining dock and dmg status.
+  LM_WIN_PLATFORM_NOTIFICATION = 18,   // Launched from toast notification
+                                       // activation on Windows.
+  LM_SHORTCUT_START_MENU = 19,         // A Windows Start Menu shortcut.
+  LM_CREDENTIAL_PROVIDER_SIGNIN = 20,  // Started as a logon stub for the Google
+                                       // Credential Provider for Windows.
 };
 
 // Returns a LaunchMode value if one can be determined with low overhead, or
@@ -319,6 +323,17 @@
     }
     return false;
   }
+  // If being started for credential provider logon purpose, only show the
+  // signin page.
+  if (command_line_.HasSwitch(credential_provider::kGcpwSigninSwitch)) {
+    DCHECK_EQ(Profile::ProfileType::INCOGNITO_PROFILE,
+              profile_->GetProfileType());
+    // NOTE: All launch urls are ignored when running with --gcpw-logon since
+    // this mode only loads Google's sign in page.
+    StartGCPWSignin(command_line_, profile_);
+    RecordLaunchModeHistogram(LM_CREDENTIAL_PROVIDER_SIGNIN);
+    return true;
+  }
 #endif  // defined(OS_WIN)
 
   if (command_line_.HasSwitch(switches::kAppId)) {
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
index 9071078f..6858dffb 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -22,6 +22,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -74,6 +75,12 @@
 #include "net/base/url_util.h"
 #include "ui/base/l10n/l10n_util.h"
 
+#if defined(OS_WIN)
+
+#include "chrome/credential_provider/common/gcp_strings.h"
+
+#endif  // defined(OS_WIN)
+
 namespace {
 
 void LogHistogramValue(signin_metrics::AccessPointAction action) {
@@ -218,6 +225,33 @@
     browser = handler_->GetDesktopBrowser();
   }
 
+  signin_metrics::AccessPoint access_point =
+      signin::GetAccessPointForPromoURL(current_url_);
+  signin_metrics::Reason reason =
+      signin::GetSigninReasonForPromoURL(current_url_);
+  if (reason == signin_metrics::Reason::REASON_FETCH_LST_ONLY) {
+// Constants are only available on Windows for the Google Credential
+// Provider for Windows. Other platforms will just close the dialog here.
+#if defined(OS_WIN)
+    std::string json_retval;
+    base::Value args(base::Value::Type::DICTIONARY);
+    args.SetKey(credential_provider::kKeyEmail, base::Value(email_));
+    args.SetKey(credential_provider::kKeyPassword, base::Value(password_));
+    args.SetKey(credential_provider::kKeyId, base::Value(gaia_id_));
+    args.SetKey(credential_provider::kKeyRefreshToken,
+                base::Value(result.refresh_token));
+    args.SetKey(credential_provider::kKeyAccessToken,
+                base::Value(result.access_token));
+
+    handler_->SendLSTFetchResultsMessage(args);
+#else
+    if (handler_)
+      handler_->CloseDialogFromJavascript();
+#endif  // defined(OS_WIN)
+    base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
+    return;
+  }
+
   AboutSigninInternals* about_signin_internals =
       AboutSigninInternalsFactory::GetForProfile(profile_);
   about_signin_internals->OnRefreshTokenReceived("Successful");
@@ -227,11 +261,6 @@
       AccountTrackerServiceFactory::GetForProfile(profile_)
           ->SeedAccountInfo(gaia_id_, email_);
 
-  signin_metrics::AccessPoint access_point =
-      signin::GetAccessPointForPromoURL(current_url_);
-  signin_metrics::Reason reason =
-      signin::GetSigninReasonForPromoURL(current_url_);
-
   SigninManager* signin_manager = SigninManagerFactory::GetForProfile(profile_);
   std::string primary_email =
       signin_manager->GetAuthenticatedAccountInfo().email;
@@ -399,9 +428,13 @@
   if (handler_)
     handler_->HandleLoginError(error.ToString(), base::string16());
 
-  AboutSigninInternals* about_signin_internals =
-    AboutSigninInternalsFactory::GetForProfile(profile_);
-  about_signin_internals->OnRefreshTokenReceived("Failure");
+  signin_metrics::Reason reason =
+      signin::GetSigninReasonForPromoURL(current_url_);
+  if (reason != signin_metrics::Reason::REASON_FETCH_LST_ONLY) {
+    AboutSigninInternals* about_signin_internals =
+        AboutSigninInternalsFactory::GetForProfile(profile_);
+    about_signin_internals->OnRefreshTokenReceived("Failure");
+  }
 
   base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
 }
@@ -518,16 +551,18 @@
   // the current profile is the system profile.  In this case, use the email to
   // find the right profile to reauthenticate.  Otherwise the profile can be
   // taken from web_ui().
+  signin_metrics::Reason reason =
+      signin::GetSigninReasonForPromoURL(current_url);
+
   Profile* profile = Profile::FromWebUI(web_ui());
-  if (IsSystemProfile(profile)) {
+  if (reason != signin_metrics::Reason::REASON_FETCH_LST_ONLY &&
+      IsSystemProfile(profile)) {
     ProfileManager* manager = g_browser_process->profile_manager();
     base::FilePath path = profiles::GetPathOfProfileWithEmail(manager, email);
     if (path.empty()) {
       path = UserManager::GetSigninProfilePath();
     }
     if (!path.empty()) {
-      signin_metrics::Reason reason =
-          signin::GetSigninReasonForPromoURL(current_url);
       // If we are only reauthenticating a profile in the user manager (and not
       // unlocking it), load the profile and finish the login.
       if (reason == signin_metrics::Reason::REASON_REAUTHENTICATION) {
@@ -659,7 +694,8 @@
   }
 
   std::string error_msg;
-  bool can_offer = CanOfferSignin(profile, can_offer_for, params.gaia_id,
+  bool can_offer = reason == signin_metrics::Reason::REASON_FETCH_LST_ONLY ||
+                   CanOfferSignin(profile, can_offer_for, params.gaia_id,
                                   params.email, &error_msg);
   if (!can_offer) {
     if (params.handler) {
@@ -671,7 +707,8 @@
 
   AboutSigninInternals* about_signin_internals =
       AboutSigninInternalsFactory::GetForProfile(profile);
-  about_signin_internals->OnAuthenticationResultReceived("Successful");
+  if (about_signin_internals)
+    about_signin_internals->OnAuthenticationResultReceived("Successful");
 
   std::string signin_scoped_device_id =
       GetSigninScopedDeviceIdForProfile(profile);
@@ -690,13 +727,23 @@
 
   // If opened from user manager to unlock a profile, make sure the user manager
   // is closed and that the profile is marked as unlocked.
-  if (!params.is_force_sign_in_with_usermanager) {
+  if (reason != signin_metrics::Reason::REASON_FETCH_LST_ONLY &&
+      !params.is_force_sign_in_with_usermanager) {
     UnlockProfileAndHideLoginUI(params.profile_path, params.handler);
   }
 }
 
 void InlineLoginHandlerImpl::HandleLoginError(const std::string& error_msg,
                                               const base::string16& email) {
+  content::WebContents* contents = web_ui()->GetWebContents();
+  const GURL& current_url = contents->GetURL();
+  signin_metrics::Reason reason =
+      signin::GetSigninReasonForPromoURL(current_url);
+
+  if (reason == signin_metrics::Reason::REASON_FETCH_LST_ONLY) {
+    SendLSTFetchResultsMessage(base::Value(base::Value::Type::DICTIONARY));
+    return;
+  }
   SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
   Browser* browser = GetDesktopBrowser();
   Profile* profile = Profile::FromWebUI(web_ui());
@@ -711,6 +758,12 @@
   }
 }
 
+void InlineLoginHandlerImpl::SendLSTFetchResultsMessage(
+    const base::Value& arg) {
+  if (IsJavascriptAllowed())
+    CallJavascriptFunction("inline.login.sendLSTFetchResults", arg);
+}
+
 Browser* InlineLoginHandlerImpl::GetDesktopBrowser() {
   Browser* browser = chrome::FindBrowserWithWebContents(
       web_ui()->GetWebContents());
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
index 8234ded..d1f2979 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
@@ -47,6 +47,13 @@
   void HandleLoginError(const std::string& error_msg,
                         const base::string16& email);
 
+  // Calls the javascript function 'sendLSTFetchResults' with the given
+  // base::Value result. This value will be passed to another
+  // WebUiMessageHandler which needs to handle the 'lstFetchResults' message
+  // with a single argument that is the dictionary of values relevant for the
+  // sign in of the user.
+  void SendLSTFetchResultsMessage(const base::Value& arg);
+
  private:
   // InlineLoginHandler overrides:
   void SetExtraInitParams(base::DictionaryValue& params) override;
diff --git a/chrome/credential_provider/common/BUILD.gn b/chrome/credential_provider/common/BUILD.gn
new file mode 100644
index 0000000..69a9bf52
--- /dev/null
+++ b/chrome/credential_provider/common/BUILD.gn
@@ -0,0 +1,13 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Common string constants shared between the credential provider DLL
+# and Chrome.
+
+source_set("common_constants") {
+  sources = [
+    "gcp_strings.cc",
+    "gcp_strings.h",
+  ]
+}
diff --git a/chrome/credential_provider/gaiacp/gcp_strings.cc b/chrome/credential_provider/common/gcp_strings.cc
similarity index 85%
rename from chrome/credential_provider/gaiacp/gcp_strings.cc
rename to chrome/credential_provider/common/gcp_strings.cc
index 00806f6e..bf1d7eb 100644
--- a/chrome/credential_provider/gaiacp/gcp_strings.cc
+++ b/chrome/credential_provider/common/gcp_strings.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 
 namespace credential_provider {
 
@@ -14,6 +14,7 @@
 const char kKeyMdmIdToken[] = "mdm_id_token";
 const char kKeyPassword[] = "password";
 const char kKeyRefreshToken[] = "refresh_token";
+const char kKeyAccessToken[] = "access_token";
 const char kKeySID[] = "sid";
 const char kKeyTokenHandle[] = "token_handle";
 const char kKeyUsername[] = "user_name";
@@ -41,4 +42,8 @@
     L"SOFTWARE\\Google\\Update\\Clients\\"
     L"{32987697-A14E-4B89-84D6-630D5431E831}";
 
+// Chrome is being opened to show the credential provider logon page.  This
+// page is always shown in incognito mode.
+const char kGcpwSigninSwitch[] = "gcpw-signin";
+
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/gcp_strings.h b/chrome/credential_provider/common/gcp_strings.h
similarity index 83%
rename from chrome/credential_provider/gaiacp/gcp_strings.h
rename to chrome/credential_provider/common/gcp_strings.h
index 481fdb1..78ac46c 100644
--- a/chrome/credential_provider/gaiacp/gcp_strings.h
+++ b/chrome/credential_provider/common/gcp_strings.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_CREDENTIAL_PROVIDER_GAIACP_GCP_STRINGS_H_
-#define CHROME_CREDENTIAL_PROVIDER_GAIACP_GCP_STRINGS_H_
+#ifndef CHROME_CREDENTIAL_PROVIDER_COMMON_GCP_STRINGS_H_
+#define CHROME_CREDENTIAL_PROVIDER_COMMON_GCP_STRINGS_H_
 
 namespace credential_provider {
 
@@ -15,6 +15,7 @@
 extern const char kKeyMdmIdToken[];
 extern const char kKeyPassword[];
 extern const char kKeyRefreshToken[];
+extern const char kKeyAccessToken[];
 extern const char kKeySID[];
 extern const char kKeyTokenHandle[];
 extern const char kKeyUsername[];
@@ -38,6 +39,8 @@
 extern const wchar_t kRegUpdaterClientStateAppPath[];
 extern const wchar_t kRegUpdaterClientsAppPath[];
 
+extern const char kGcpwSigninSwitch[];
+
 }  // namespace credential_provider
 
-#endif  // CHROME_CREDENTIAL_PROVIDER_GAIACP_GCP_STRINGS_H_
+#endif  // CHROME_CREDENTIAL_PROVIDER_COMMON_GCP_STRINGS_H_
diff --git a/chrome/credential_provider/gaiacp/BUILD.gn b/chrome/credential_provider/gaiacp/BUILD.gn
index 34bdaa56..f9e5adfc 100644
--- a/chrome/credential_provider/gaiacp/BUILD.gn
+++ b/chrome/credential_provider/gaiacp/BUILD.gn
@@ -15,17 +15,17 @@
 import("//testing/test.gni")
 
 # This static library is shared with the setup program.
-
 source_set("common") {
   sources = [
-    "gcp_strings.cc",
-    "gcp_strings.h",
     "gcp_utils.cc",
     "gcp_utils.h",
     "logging.cc",
     "logging.h",
   ]
   public_configs = [ ":common_config" ]
+  public_deps = [
+    "//chrome/credential_provider/common:common_constants",
+  ]
   deps = [
     "//base:base",
     "//components/version_info",
diff --git a/chrome/credential_provider/gaiacp/dllmain.cc b/chrome/credential_provider/gaiacp/dllmain.cc
index b670b89..bddebd82 100644
--- a/chrome/credential_provider/gaiacp/dllmain.cc
+++ b/chrome/credential_provider/gaiacp/dllmain.cc
@@ -20,11 +20,11 @@
 #include "base/values.h"
 #include "base/win/registry.h"
 #include "chrome/common/chrome_version.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_base.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_provider.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_provider_module.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gcp_utils.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
 #include "chrome/credential_provider/gaiacp/os_user_manager.h"
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.cc b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
index fcd63e0..0429541e 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
@@ -21,8 +21,8 @@
 #include "base/win/current_module.h"
 #include "base/win/registry.h"
 #include "base/win/scoped_handle.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gcp_utils.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
 #include "chrome/credential_provider/gaiacp/os_process_manager.h"
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
index fd9eaa3..f16c3db 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
@@ -17,9 +17,9 @@
 #include "base/test/multiprocess_test.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
 #include "chrome/credential_provider/test/com_fakes.h"
 #include "chrome/credential_provider/test/gcp_fakes.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_provider.cc b/chrome/credential_provider/gaiacp/gaia_credential_provider.cc
index 64a5c7cc..8cfc88d 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_provider.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_provider.cc
@@ -12,9 +12,9 @@
 #include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
 #include "chrome/credential_provider/gaiacp/os_user_manager.h"
 #include "chrome/credential_provider/gaiacp/reauth_credential.h"
diff --git a/chrome/credential_provider/gaiacp/gcp_utils.cc b/chrome/credential_provider/gaiacp/gcp_utils.cc
index 1ce0825..f6dac4a 100644
--- a/chrome/credential_provider/gaiacp/gcp_utils.cc
+++ b/chrome/credential_provider/gaiacp/gcp_utils.cc
@@ -40,7 +40,7 @@
 #include "base/win/current_module.h"
 #include "base/win/registry.h"
 #include "base/win/win_util.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
 
 namespace credential_provider {
diff --git a/chrome/credential_provider/gaiacp/os_process_manager.cc b/chrome/credential_provider/gaiacp/os_process_manager.cc
index 5e2da2c..8ae6fb4 100644
--- a/chrome/credential_provider/gaiacp/os_process_manager.cc
+++ b/chrome/credential_provider/gaiacp/os_process_manager.cc
@@ -37,7 +37,7 @@
 #include "base/win/registry.h"
 #include "base/win/scoped_process_information.h"
 #include "base/win/win_util.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gcp_utils.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
 
diff --git a/chrome/credential_provider/gaiacp/reauth_credential.cc b/chrome/credential_provider/gaiacp/reauth_credential.cc
index e0ff970..91a1866 100644
--- a/chrome/credential_provider/gaiacp/reauth_credential.cc
+++ b/chrome/credential_provider/gaiacp/reauth_credential.cc
@@ -5,7 +5,7 @@
 #include "chrome/credential_provider/gaiacp/reauth_credential.h"
 
 #include "base/stl_util.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
 #include "chrome/credential_provider/gaiacp/os_user_manager.h"
 #include "chrome/credential_provider/gaiacp/reg_utils.h"
diff --git a/chrome/credential_provider/gaiacp/reg_utils.cc b/chrome/credential_provider/gaiacp/reg_utils.cc
index 7e95ef619..357030f 100644
--- a/chrome/credential_provider/gaiacp/reg_utils.cc
+++ b/chrome/credential_provider/gaiacp/reg_utils.cc
@@ -8,7 +8,7 @@
 
 #include "base/stl_util.h"
 #include "base/win/registry.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 
 namespace credential_provider {
 
diff --git a/chrome/credential_provider/gaiacp/scoped_user_profile.cc b/chrome/credential_provider/gaiacp/scoped_user_profile.cc
index 0a3eb25..f57d221 100644
--- a/chrome/credential_provider/gaiacp/scoped_user_profile.cc
+++ b/chrome/credential_provider/gaiacp/scoped_user_profile.cc
@@ -13,7 +13,7 @@
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/registry.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gcp_utils.h"
 #include "chrome/credential_provider/gaiacp/logging.h"
 #include "chrome/credential_provider/gaiacp/reg_utils.h"
diff --git a/chrome/credential_provider/test/gcp_setup_unittests.cc b/chrome/credential_provider/test/gcp_setup_unittests.cc
index 77db864..d81ebc6 100644
--- a/chrome/credential_provider/test/gcp_setup_unittests.cc
+++ b/chrome/credential_provider/test/gcp_setup_unittests.cc
@@ -23,8 +23,8 @@
 #include "base/test/test_reg_util_win.h"
 #include "base/win/registry.h"
 #include "build/build_config.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
-#include "chrome/credential_provider/gaiacp/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gcp_utils.h"
 #include "chrome/credential_provider/setup/setup_lib.h"
 #include "chrome/credential_provider/test/gcp_fakes.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 3f86810..44a4e0af 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -396,6 +396,19 @@
   }
 }
 
+if (is_win) {
+  source_set("credential_provider_test_utils") {
+    testonly = true
+    sources = [
+      "../browser/ui/startup/credential_provider_signin_dialog_win_test_data.cc",
+      "../browser/ui/startup/credential_provider_signin_dialog_win_test_data.h",
+    ]
+    deps = [
+      "//base",
+    ]
+  }
+}
+
 test("browser_tests") {
   sources = [
     # TODO(jbudorick): Move tests here from other lists as Android support is
@@ -1980,6 +1993,7 @@
       sources += [
         "../browser/browser_switcher/browser_switcher_service_browsertest.cc",
         "../browser/printing/pdf_to_emf_converter_browsertest.cc",
+        "../browser/ui/startup/credential_provider_signin_dialog_win_browsertest.cc",
         "../browser/ui/views/accessibility/invert_bubble_view_browsertest.cc",
         "../browser/ui/views/settings_reset_prompt_dialog_browsertest.cc",
         "../browser/ui/views/uninstall_view_browsertest.cc",
@@ -2002,6 +2016,7 @@
       deps += [
         "//chrome:other_version",
         "//chrome/app:command_ids",
+        "//chrome/test:credential_provider_test_utils",
         "//device/vr",
         "//third_party/wtl",
         "//ui/resources",
@@ -2933,6 +2948,12 @@
     data_deps += [ "//chrome:chrome_framework" ]
   }
 
+  if (is_win) {
+    assert(toolkit_views)
+    sources += [ "../browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc" ]
+    deps += [ "//chrome/test:credential_provider_test_utils" ]
+  }
+
   if (enable_dice_support) {
     sources += [
       "../browser/signin/dice_response_handler_unittest.cc",
diff --git a/components/keep_alive_registry/keep_alive_types.cc b/components/keep_alive_registry/keep_alive_types.cc
index 8f47bc5..37190e9f 100644
--- a/components/keep_alive_registry/keep_alive_types.cc
+++ b/components/keep_alive_registry/keep_alive_types.cc
@@ -47,6 +47,8 @@
       return out << "PROFILE_LOADER";
     case KeepAliveOrigin::USER_MANAGER_VIEW:
       return out << "USER_MANAGER_VIEW";
+    case KeepAliveOrigin::CREDENTIAL_PROVIDER_SIGNIN_DIALOG:
+      return out << "CREDENTIAL_PROVIDER_SIGNIN_DIALOG";
   }
 
   NOTREACHED();
diff --git a/components/keep_alive_registry/keep_alive_types.h b/components/keep_alive_registry/keep_alive_types.h
index 9e1d49d..879e0b7 100644
--- a/components/keep_alive_registry/keep_alive_types.h
+++ b/components/keep_alive_registry/keep_alive_types.h
@@ -44,7 +44,8 @@
   PANEL_VIEW,
   PROFILE_HELPER,
   PROFILE_LOADER,
-  USER_MANAGER_VIEW
+  USER_MANAGER_VIEW,
+  CREDENTIAL_PROVIDER_SIGNIN_DIALOG,
 };
 
 // Restart: Allow Chrome to restart when all the registered KeepAlives allow
diff --git a/components/signin/core/browser/signin_metrics.cc b/components/signin/core/browser/signin_metrics.cc
index 9abc7c9..6526d05 100644
--- a/components/signin/core/browser/signin_metrics.cc
+++ b/components/signin/core/browser/signin_metrics.cc
@@ -118,6 +118,10 @@
       base::RecordAction(
           base::UserMetricsAction("Signin_Signin_FromManageCardsBubble"));
       break;
+    case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+      base::RecordAction(
+          base::UserMetricsAction("Signin_Signin_FromMachineLogon"));
+      break;
     case AccessPoint::ACCESS_POINT_MAX:
       NOTREACHED();
       break;
@@ -186,6 +190,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+    case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
       NOTREACHED() << "Signin_SigninWithDefault_From* user actions"
                    << " are not recorded for access_point "
                    << static_cast<int>(access_point)
@@ -259,6 +264,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+    case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
       NOTREACHED() << "Signin_SigninNotDefault_From* user actions"
                    << " are not recorded for access point "
                    << static_cast<int>(access_point)
@@ -332,6 +338,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+    case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
       // These access points do not support personalized sign-in promos, so
       // |Signin_SigninNewAccountPreDice_From*| user actions should not
       // be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -416,6 +423,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+    case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
       // These access points do not support personalized sign-in promos, so
       // |Signin_SigninNewAccountNoExistingAccount_From*| user actions should
       // not be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -496,6 +504,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+    case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
       // These access points do not support personalized sign-in promos, so
       // |Signin_SigninNewAccountExistingAccount_From*| user actions should not
       // be recorded for them. Note: To avoid bloating the sign-in APIs, the
@@ -951,6 +960,7 @@
     case AccessPoint::ACCESS_POINT_SUPERVISED_USER:
     case AccessPoint::ACCESS_POINT_USER_MANAGER:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
+    case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
       NOTREACHED() << "Signin_Impression_From* user actions"
                    << " are not recorded for access point "
                    << static_cast<int>(access_point);
@@ -1079,6 +1089,7 @@
     case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
     case AccessPoint::ACCESS_POINT_UNKNOWN:
     case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
+    case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
       NOTREACHED() << "Signin_Impression{With|WithNo}Account_From* user actions"
                    << " are not recorded for access point "
                    << static_cast<int>(access_point)
diff --git a/components/signin/core/browser/signin_metrics.h b/components/signin/core/browser/signin_metrics.h
index 19b9dbfa..4529276 100644
--- a/components/signin/core/browser/signin_metrics.h
+++ b/components/signin/core/browser/signin_metrics.h
@@ -153,6 +153,7 @@
   ACCESS_POINT_FORCE_SIGNIN_WARNING,
   ACCESS_POINT_SAVE_CARD_BUBBLE,
   ACCESS_POINT_MANAGE_CARDS_BUBBLE,
+  ACCESS_POINT_MACHINE_LOGON,
   ACCESS_POINT_MAX,  // This must be last.
 };
 
@@ -185,7 +186,11 @@
   REASON_UNLOCK,
   REASON_UNKNOWN_REASON,  // This should never have been used to get signin URL.
   REASON_FORCED_SIGNIN_PRIMARY_ACCOUNT,
-  REASON_MAX,  // This must be last.
+  REASON_FETCH_LST_ONLY,  // Used to simply login and acquire a login scope
+                          // token without actually signing into any profiles on
+                          // Chrome. This allows the chrome signin page to work
+                          // in incognito mode.
+  REASON_MAX,             // This must be last.
 };
 
 // Enum values used for use with the "Signin.Reauth" histogram.
diff --git a/components/signin/core/browser/signin_metrics_unittest.cc b/components/signin/core/browser/signin_metrics_unittest.cc
index a8939fa..7f7e96f 100644
--- a/components/signin/core/browser/signin_metrics_unittest.cc
+++ b/components/signin/core/browser/signin_metrics_unittest.cc
@@ -106,6 +106,8 @@
         return "SaveCardBubble";
       case AccessPoint::ACCESS_POINT_MANAGE_CARDS_BUBBLE:
         return "ManageCardsBubble";
+      case AccessPoint::ACCESS_POINT_MACHINE_LOGON:
+        return "MachineLogon";
       case AccessPoint::ACCESS_POINT_MAX:
         NOTREACHED();
         return "";
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index eafe22a..d748932 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -17207,6 +17207,14 @@
   </description>
 </action>
 
+<action name="Signin_Signin_FromMachineLogon">
+  <owner>rogerta@chromium.org</owner>
+  <owner>tienmai@chromium.org</owner>
+  <description>
+    Record when a user signs in using a Windows machine's logon screen.
+  </description>
+</action>
+
 <action name="Signin_Signin_FromManageCardsBubble">
   <owner>manasverma@google.com</owner>
   <owner>jsaul@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index f11ee7d5..4a70bb4c 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -28382,6 +28382,10 @@
   <int value="19" label="LM_SHORTCUT_START_MENU">
     Launched from a Start Menu shortcut (Windows).
   </int>
+  <int value="20" label="LM_GCPW_LOGON">
+    Launched as a logon stub for the Google Credential Provider for Windows
+    (Windows).
+  </int>
 </enum>
 
 <enum name="LaunchType">