[gnome-software] auth: Use gnome-online-accounts to handle the authentication



commit e1cce7348411c6790044d2c9cd96b8696ca5c126
Author: Andrea Azzarone <azzaronea gmail com>
Date:   Mon Jun 4 14:51:47 2018 -0500

    auth: Use gnome-online-accounts to handle the authentication

 .gitlab-ci.yml                      |   1 +
 contrib/gnome-software.spec.in      |   2 +-
 data/org.gnome.software.gschema.xml |   7 +
 lib/gs-auth.c                       | 793 ++++++++++++------------------------
 lib/gs-auth.h                       |  96 +----
 lib/gs-plugin-job.c                 |   2 +-
 lib/gs-plugin-loader.c              |  15 +-
 lib/gs-plugin-loader.h              |   2 +-
 lib/gs-plugin-types.h               |  14 -
 lib/gs-plugin-vfuncs.h              |  64 ---
 lib/gs-plugin.c                     |  36 +-
 lib/gs-plugin.h                     |   2 +-
 lib/gs-self-test.c                  |  49 ---
 lib/meson.build                     |   6 +-
 meson.build                         |   2 +-
 plugins/dummy/gs-plugin-dummy.c     | 103 +----
 plugins/dummy/gs-self-test.c        |  83 ----
 plugins/dummy/meson.build           |   2 +-
 plugins/meson.build                 |   1 +
 plugins/snap/gs-plugin-snap.c       | 187 +++------
 src/gs-auth-dialog.c                | 559 +++++++++++++++----------
 src/gs-auth-dialog.h                |   8 +-
 src/gs-auth-dialog.ui               | 383 ++++++-----------
 src/gs-page.c                       |   8 +-
 src/gs-page.h                       |   2 +-
 src/gs-shell.c                      | 170 +++-----
 src/meson.build                     |   4 +-
 27 files changed, 889 insertions(+), 1712 deletions(-)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 0d99b81b..90093205 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -11,6 +11,7 @@ before_script:
   # Some deps may not be sync'd
   - dnf -y install rpm-ostree-devel
   - dnf -y install libstemmer-devel
+  - dnf -y install gnome-online-accounts-devel
 
 build-gnome-software:
   stage: build
diff --git a/contrib/gnome-software.spec.in b/contrib/gnome-software.spec.in
index 0dec552d..aba9e487 100644
--- a/contrib/gnome-software.spec.in
+++ b/contrib/gnome-software.spec.in
@@ -34,11 +34,11 @@ BuildRequires: gtk3-devel >= %{gtk3_version}
 BuildRequires: gtk-doc
 BuildRequires: json-glib-devel >= %{json_glib_version}
 BuildRequires: libappstream-glib-devel >= %{appstream_glib_version}
+BuildRequires: gnome-online-accounts-devel
 BuildRequires: libsoup-devel
 BuildRequires: meson
 BuildRequires: PackageKit-glib-devel >= %{packagekit_version}
 BuildRequires: polkit-devel
-BuildRequires: libsecret-devel
 BuildRequires: flatpak-devel >= %{flatpak_version}
 BuildRequires: ostree-devel
 BuildRequires: rpm-ostree-devel
diff --git a/data/org.gnome.software.gschema.xml b/data/org.gnome.software.gschema.xml
index fab37c9e..97780e0d 100644
--- a/data/org.gnome.software.gschema.xml
+++ b/data/org.gnome.software.gschema.xml
@@ -139,5 +139,12 @@
       <default>true</default>
       <summary>Enable GNOME Shell extensions repository</summary>
     </key>
+    <child name="auth" schema="org.gnome.software.auth"/>
+  </schema>
+  <schema id="org.gnome.software.auth" gettext-domain="gnome-software">
+    <key name="account-id" type="s">
+      <default>''</default>
+      <summary>A string storing the gnome-online-account id used to login</summary>
+    </key>
   </schema>
 </schemalist>
diff --git a/lib/gs-auth.c b/lib/gs-auth.c
index 098efd13..ecd60e50 100644
--- a/lib/gs-auth.c
+++ b/lib/gs-auth.c
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
  * Copyright (C) 2016 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2018 Canonical Ltd
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -32,612 +33,307 @@
 
 #include "config.h"
 
-#include <libsecret/secret.h>
-
 #include "gs-auth.h"
 #include "gs-plugin.h"
 
 struct _GsAuth
 {
-       GObject                  parent_instance;
-
-       GsAuthFlags              flags;
-       gchar                   *provider_id;
-       gchar                   *provider_name;
-       gchar                   *provider_logo;
-       gchar                   *provider_uri;
-       gchar                   *provider_schema;
-       gchar                   *username;
-       gchar                   *password;
-       gchar                   *pin;
-       GHashTable              *metadata;      /* utf8: utf8 */
+       GObject          parent_instance;
+
+       gchar           *header_none;
+       gchar           *header_single;
+       gchar           *header_multiple;
+
+       gchar           *auth_id;
+       gchar           *provider_name;
+       gchar           *provider_type;
+
+       GoaClient       *goa_client;
+       GoaObject       *goa_object;
+
+       GSettings       *settings;
+};
+
+static void gs_auth_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GsAuth, gs_auth, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE(G_TYPE_INITABLE, gs_auth_initable_iface_init))
+
+enum {
+       SIGNAL_CHANGED,
+       SIGNAL_LAST
 };
 
 enum {
        PROP_0,
-       PROP_USERNAME,
-       PROP_PASSWORD,
-       PROP_PIN,
-       PROP_FLAGS,
+       PROP_AUTH_ID,
+       PROP_PROVIDER_TYPE,
+       PROP_GOA_OBJECT,
        PROP_LAST
 };
 
-G_DEFINE_TYPE (GsAuth, gs_auth, G_TYPE_OBJECT)
+static guint signals [SIGNAL_LAST] = { 0 };
 
-/**
- * gs_auth_get_provider_id:
- * @auth: a #GsAuth
- *
- * Gets the authentication service ID.
- *
- * Returns: the string to use for searching, e.g. "UbuntuOne"
- */
-const gchar *
-gs_auth_get_provider_id (GsAuth *auth)
-{
-       g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
-       return auth->provider_id;
-}
 
 /**
- * gs_auth_get_provider_name:
+ * gs_auth_get_header:
  * @auth: a #GsAuth
+ * @n: the number of accounts
  *
- * Gets the authentication service name.
+ * Gets the header to be used in the authentication dialog in case there are @n
+ * available accounts.
  *
- * Returns: the string to show in the UI
+ * Returns: (transfer none) : a string
  */
 const gchar *
-gs_auth_get_provider_name (GsAuth *auth)
+gs_auth_get_header (GsAuth *auth, guint n)
 {
        g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
-       return auth->provider_name;
+
+       if (n == 0)
+               return auth->header_none;
+       else if (n == 1)
+               return auth->header_single;
+       else
+               return auth->header_multiple;
 }
 
 /**
- * gs_auth_set_provider_name:
+ * gs_auth_set_header:
  * @auth: a #GsAuth
- * @provider_name: a service name, e.g. "GNOME Online Accounts"
+ * @header_none: the header to be used if no account is present
+ * @header_single: the header to be used if one account is present
+ * @header_multiple: the header to be used if two or more accounts are present
  *
- * Sets the name to be used for the authentication dialog.
+ * Sets the headers to be used for the authentication dialog.
  */
 void
-gs_auth_set_provider_name (GsAuth *auth, const gchar *provider_name)
+gs_auth_set_header (GsAuth *auth,
+                   const gchar *header_none,
+                   const gchar *header_single,
+                   const gchar *header_multiple)
 {
        g_return_if_fail (GS_IS_AUTH (auth));
-       g_free (auth->provider_name);
-       auth->provider_name = g_strdup (provider_name);
+       g_return_if_fail (header_none != NULL);
+       g_return_if_fail (header_single != NULL);
+       g_return_if_fail (header_multiple != NULL);
+
+       g_free (auth->header_none);
+       auth->header_none = g_strdup (header_none);
+
+       g_free (auth->header_single);
+       auth->header_single = g_strdup (header_single);
+
+       g_free (auth->header_multiple);
+       auth->header_multiple = g_strdup (header_multiple);
 }
 
 /**
- * gs_auth_get_provider_logo:
+ * gs_auth_get_auth_id:
  * @auth: a #GsAuth
  *
- * Gets the authentication service image.
+ * Gets the authentication service ID.
  *
- * Returns: the filename of an image, or %NULL
+ * Returns: (transfer none): a string
  */
 const gchar *
-gs_auth_get_provider_logo (GsAuth *auth)
+gs_auth_get_auth_id (GsAuth *auth)
 {
        g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
-       return auth->provider_logo;
-}
-
-/**
- * gs_auth_set_provider_logo:
- * @auth: a #GsAuth
- * @provider_logo: an image, e.g. "/usr/share/icons/gnome-online.png"
- *
- * Sets the image to be used for the authentication dialog.
- */
-void
-gs_auth_set_provider_logo (GsAuth *auth, const gchar *provider_logo)
-{
-       g_return_if_fail (GS_IS_AUTH (auth));
-       g_free (auth->provider_logo);
-       auth->provider_logo = g_strdup (provider_logo);
+       return auth->auth_id;
 }
 
 /**
- * gs_auth_get_provider_uri:
+ * gs_auth_get_provider_name:
  * @auth: a #GsAuth
  *
- * Gets the authentication service website.
+ * Gets the authentication service name.
  *
- * Returns: the URI, or %NULL
+ * Returns: (transfer none): a string
  */
 const gchar *
-gs_auth_get_provider_uri (GsAuth *auth)
+gs_auth_get_provider_name (GsAuth *auth)
 {
        g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
-       return auth->provider_uri;
+       return auth->provider_name;
 }
 
 /**
- * gs_auth_set_provider_uri:
+ * gs_auth_set_provider_name:
  * @auth: a #GsAuth
- * @provider_uri: a URI, e.g. "http://www.gnome.org/sso";
+ * @provider_name: a service name, e.g. "Snap Store"
  *
- * Sets the website to be used for the authentication dialog.
+ * Sets the name to be used for the authentication dialog.
  */
 void
-gs_auth_set_provider_uri (GsAuth *auth, const gchar *provider_uri)
+gs_auth_set_provider_name (GsAuth *auth, const gchar *provider_name)
 {
        g_return_if_fail (GS_IS_AUTH (auth));
-       g_free (auth->provider_uri);
-       auth->provider_uri = g_strdup (provider_uri);
+       g_return_if_fail (provider_name != NULL);
+
+       g_free (auth->provider_name);
+       auth->provider_name = g_strdup (provider_name);
 }
 
 /**
- * gs_auth_get_provider_schema:
+ * gs_auth_get_provider_type:
  * @auth: a #GsAuth
  *
- * Gets the authentication schema ID.
+ * Gets the GoaProvider type to be used for the authentication dialog.
  *
- * Returns: the URI, or %NULL
+ * Returns: (transfer none): a string
  */
 const gchar *
-gs_auth_get_provider_schema (GsAuth *auth)
+gs_auth_get_provider_type (GsAuth *auth)
 {
        g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
-       return auth->provider_schema;
+       return auth->provider_type;
 }
 
 /**
- * gs_auth_set_provider_schema:
+ * gs_auth_peek_goa_object:
  * @auth: a #GsAuth
- * @provider_schema: a URI, e.g. "com.distro.provider"
  *
- * Sets the schema ID to be used for saving the state to disk.
- */
-void
-gs_auth_set_provider_schema (GsAuth *auth, const gchar *provider_schema)
-{
-       g_return_if_fail (GS_IS_AUTH (auth));
-       g_free (auth->provider_schema);
-       auth->provider_schema = g_strdup (provider_schema);
-}
-
-/**
- * gs_auth_get_username:
- * @auth: a #GsAuth
- *
- * Gets the auth username.
+ * Gets the logged #GoaObject if any.
  *
- * Returns: the username to be used for the authentication
+ * Returns: (transfer none) (nullable): a #GoaObject, or %NULL
  */
-const gchar *
-gs_auth_get_username (GsAuth *auth)
+GoaObject *
+gs_auth_peek_goa_object (GsAuth *auth)
 {
        g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
-       return auth->username;
+       return auth->goa_object;
 }
 
-/**
- * gs_auth_set_username:
- * @auth: a #GsAuth
- * @username: a username, e.g. "hughsie"
- *
- * Sets the username to be used for the authentication.
- */
-void
-gs_auth_set_username (GsAuth *auth, const gchar *username)
+static gboolean
+gs_auth_goa_account_equal (GoaAccount *acc1, GoaAccount *acc2)
 {
-       g_return_if_fail (GS_IS_AUTH (auth));
-       g_free (auth->username);
-       auth->username = g_strdup (username);
-}
+       if (acc1 == acc2)
+               return TRUE;
 
-/**
- * gs_auth_get_password:
- * @auth: a #GsAuth
- *
- * Gets the password to be used for the authentication.
- *
- * Returns: the string, or %NULL
- **/
-const gchar *
-gs_auth_get_password (GsAuth *auth)
-{
-       g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
-       return auth->password;
-}
+       if (acc1 == NULL || acc2 == NULL)
+               return FALSE;
 
-/**
- * gs_auth_set_password:
- * @auth: a #GsAuth
- * @password: password string, e.g. "p@ssw0rd"
- *
- * Sets the password to be used for the authentication.
- */
-void
-gs_auth_set_password (GsAuth *auth, const gchar *password)
-{
-       g_return_if_fail (GS_IS_AUTH (auth));
-       g_free (auth->password);
-       auth->password = g_strdup (password);
+       return !g_strcmp0 (goa_account_get_id (acc1),
+                          goa_account_get_id (acc2));
 }
 
-/**
- * gs_auth_get_flags:
- * @auth: a #GsAuth
- *
- * Gets any flags set on the authentication, for example if we should remember
- * credentials.
- *
- * Returns: a #GsAuthFlags, e.g. %GS_AUTH_FLAG_REMEMBER
- */
-GsAuthFlags
-gs_auth_get_flags (GsAuth *auth)
+static gboolean
+gs_auth_goa_object_equal (GoaObject *obj1, GoaObject *obj2)
 {
-       g_return_val_if_fail (GS_IS_AUTH (auth), 0);
-       return auth->flags;
-}
+       if (obj1 == obj2)
+               return TRUE;
 
-/**
- * gs_auth_set_flags:
- * @auth: a #GsAuth
- * @flags: a #GsAuthFlags, e.g. %GS_AUTH_FLAG_REMEMBER
- *
- * Gets any flags set on the authentication.
- */
-void
-gs_auth_set_flags (GsAuth *auth, GsAuthFlags flags)
-{
-       g_return_if_fail (GS_IS_AUTH (auth));
-       auth->flags = flags;
-}
+       if (obj1 == NULL || obj2 == NULL)
+               return FALSE;
 
-/**
- * gs_auth_add_flags:
- * @auth: a #GsAuth
- * @flags: a #GsAuthFlags, e.g. %GS_AUTH_FLAG_REMEMBER
- *
- * Adds flags to an existing authentication without replacing the other flags.
- */
-void
-gs_auth_add_flags (GsAuth *auth, GsAuthFlags flags)
-{
-       g_return_if_fail (GS_IS_AUTH (auth));
-       auth->flags |= flags;
+       return gs_auth_goa_account_equal(goa_object_peek_account (obj1),
+                                        goa_object_peek_account (obj2));
 }
 
-/**
- * gs_auth_has_flag:
- * @auth: a #GsAuth
- * @flags: a #GsAuthFlags, e.g. %GS_AUTH_FLAG_REMEMBER
- *
- * Finds out if the authentication has a flag.
- *
- * Returns: %TRUE if set
- */
-gboolean
-gs_auth_has_flag (GsAuth *auth, GsAuthFlags flags)
+static void
+gs_auth_account_changed_cb (GoaClient *client,
+                           GoaObject *goa_object,
+                           GsAuth *auth)
 {
-       g_return_val_if_fail (GS_IS_AUTH (auth), FALSE);
-       return (auth->flags & flags) > 0;
-}
+       if (!gs_auth_goa_object_equal (auth->goa_object, goa_object))
+               return;
 
-/**
- * gs_auth_get_pin:
- * @auth: a #GsAuth
- *
- * Gets the PIN code.
- *
- * Returns: the 2 factor authentication PIN, or %NULL
- **/
-const gchar *
-gs_auth_get_pin (GsAuth *auth)
-{
-       g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
-       return auth->pin;
+       g_signal_emit (auth, signals[SIGNAL_CHANGED], 0);
 }
 
-/**
- * gs_auth_set_pin:
- * @auth: a #GsAuth
- * @pin: the PIN code, e.g. "12345"
- *
- * Sets the 2 factor authentication PIN, which can be left unset.
- */
-void
-gs_auth_set_pin (GsAuth *auth, const gchar *pin)
+static void
+gs_auth_account_removed_cb (GoaClient *client,
+                           GoaObject *goa_object,
+                           GsAuth *auth)
 {
-       g_return_if_fail (GS_IS_AUTH (auth));
-       g_free (auth->pin);
-       auth->pin = g_strdup (pin);
-}
+       if (!gs_auth_goa_object_equal (auth->goa_object, goa_object))
+               return;
 
-/**
- * gs_auth_get_metadata_item:
- * @auth: a #GsAuth
- * @key: a string
- *
- * Gets some metadata from a authentication object.
- * It is left for the the plugin to use this method as required, but a
- * typical use would be to retrieve some secure auth token.
- *
- * Returns: A string value, or %NULL for not found
- */
-const gchar *
-gs_auth_get_metadata_item (GsAuth *auth, const gchar *key)
-{
-       g_return_val_if_fail (GS_IS_AUTH (auth), NULL);
-       g_return_val_if_fail (key != NULL, NULL);
-       return g_hash_table_lookup (auth->metadata, key);
+       gs_auth_set_goa_object (auth, NULL);
 }
 
 /**
- * gs_auth_add_metadata:
+ * gs_auth_set_goa_object:
  * @auth: a #GsAuth
- * @key: a string
- * @value: a string
+ * @goa_object: (nullable) a #GoaObject
  *
- * Adds metadata to the authentication object.
- * It is left for the the plugin to use this method as required, but a
- * typical use would be to store some secure auth token.
+ * Set the #GoaObject used to login in.
  */
 void
-gs_auth_add_metadata (GsAuth *auth, const gchar *key, const gchar *value)
+gs_auth_set_goa_object (GsAuth *auth,
+                       GoaObject *goa_object)
 {
        g_return_if_fail (GS_IS_AUTH (auth));
-       g_hash_table_insert (auth->metadata, g_strdup (key), g_strdup (value));
-}
-
-static gboolean
-_g_error_is_set (GError **error)
-{
-       if (error == NULL)
-               return FALSE;
-       return *error != NULL;
-}
-
-/**
- * gs_auth_store_load:
- * @auth: a #GsAuth
- * @flags: some #GsAuthStoreFlags, e.g. %GS_AUTH_STORE_FLAG_USERNAME
- * @cancellable: a #GCancellable or %NULL
- * @error: a #GError or %NULL
- *
- * Loads authentication tokens from disk in a secure way.
- * By default only the username and password are loaded, but they are not
- * overwritten if already set.
- *
- * If additional tokens are required to be loaded you must first tell the
- * GsAuth instance what metadata to load. This can be done using:
- * `gs_auth_add_metadata("additional-secret-key-name",NULL)`
- *
- * This function is expected to be called from gs_plugin_setup().
- *
- * Returns: %TRUE if the tokens were loaded correctly.
- */
-gboolean
-gs_auth_store_load (GsAuth *auth, GsAuthStoreFlags flags,
-                   GCancellable *cancellable, GError **error)
-{
-       SecretSchema schema = {
-               auth->provider_schema,
-               SECRET_SCHEMA_NONE,
-               { { "key", SECRET_SCHEMA_ATTRIBUTE_STRING } }
-       };
-
-       /* no schema */
-       if (auth->provider_schema == NULL) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "No provider schema set for %s",
-                            auth->provider_id);
-               return FALSE;
-       }
 
-       /* username */
-       if ((flags & GS_AUTH_STORE_FLAG_USERNAME) > 0 && auth->username == NULL) {
-               auth->username = secret_password_lookup_sync (&schema,
-                                                             cancellable,
-                                                             error,
-                                                             "key", "username",
-                                                             NULL);
-               if (_g_error_is_set (error))
-                       return FALSE;
-       }
-
-       /* password */
-       if ((flags & GS_AUTH_STORE_FLAG_PASSWORD) > 0 && auth->password == NULL) {
-               auth->password = secret_password_lookup_sync (&schema,
-                                                             cancellable,
-                                                             error,
-                                                             "key", "password",
-                                                             NULL);
-               if (_g_error_is_set (error))
-                       return FALSE;
-       }
+       if (gs_auth_goa_object_equal (auth->goa_object, goa_object))
+               return;
 
-       /* metadata */
-       if (flags & GS_AUTH_STORE_FLAG_METADATA) {
-               g_autoptr(GList) keys = NULL;
-               keys = g_hash_table_get_keys (auth->metadata);
-               for (GList *l = keys; l != NULL; l = l->next) {
-                       g_autofree gchar *tmp = NULL;
-                       const gchar *key = l->data;
-                       const gchar *value = g_hash_table_lookup (auth->metadata, key);
-                       if (value != NULL)
-                               continue;
-                       tmp = secret_password_lookup_sync (&schema,
-                                                          cancellable,
-                                                          error,
-                                                          "key", key,
-                                                          NULL);
-                       if (_g_error_is_set (error))
-                               return FALSE;
-                       if (tmp != NULL)
-                               gs_auth_add_metadata (auth, key, tmp);
-               }
-       }
+       g_clear_object (&auth->goa_object);
+       if (goa_object)
+               auth->goa_object = g_object_ref (goa_object);
 
-       /* success */
-       return TRUE;
+       g_object_notify (G_OBJECT (auth), "goa-object");
+       g_signal_emit (auth, signals[SIGNAL_CHANGED], 0);
 }
 
-/**
- * gs_auth_store_save:
- * @auth: a #GsAuth
- * @flags: some #GsAuthStoreFlags, e.g. %GS_AUTH_STORE_FLAG_USERNAME
- * @cancellable: a #GCancellable or %NULL
- * @error: a #GError or %NULL
- *
- * Saves the username, password and all added metadata to disk in a secure way.
- *
- * This function is expected to be called from gs_plugin_setup().
- *
- * Returns: %TRUE if the tokens were all saved correctly.
- */
-gboolean
-gs_auth_store_save (GsAuth *auth, GsAuthStoreFlags flags,
-                   GCancellable *cancellable, GError **error)
+static gboolean
+string_to_goa_object (GValue   *value,
+                     GVariant *variant,
+                     gpointer  user_data)
 {
-       SecretSchema schema = {
-               auth->provider_schema,
-               SECRET_SCHEMA_NONE,
-               { { "key", SECRET_SCHEMA_ATTRIBUTE_STRING } }
-       };
-
-       /* no schema */
-       if (auth->provider_schema == NULL) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "No provider schema set for %s",
-                            auth->provider_id);
-               return FALSE;
-       }
+       GsAuth *auth = GS_AUTH (user_data);
+       GoaObject *goa_object;
+       const gchar *account_id;
 
-       /* username */
-       if ((flags & GS_AUTH_STORE_FLAG_USERNAME) > 0 && auth->username != NULL) {
-               if (!secret_password_store_sync (&schema,
-                                                NULL, /* collection */
-                                                auth->provider_schema,
-                                                auth->username,
-                                                cancellable, error,
-                                                "key", "username", NULL))
-                       return FALSE;
-       }
-
-       /* password */
-       if ((flags & GS_AUTH_STORE_FLAG_PASSWORD) > 0 && auth->password != NULL) {
-               if (!secret_password_store_sync (&schema,
-                                                NULL, /* collection */
-                                                auth->provider_schema,
-                                                auth->password,
-                                                cancellable, error,
-                                                "key", "password", NULL))
-                       return FALSE;
-       }
+       account_id = g_variant_get_string (variant, NULL);
 
-       /* metadata */
-       if (flags & GS_AUTH_STORE_FLAG_METADATA) {
-               g_autoptr(GList) keys = NULL;
-               keys = g_hash_table_get_keys (auth->metadata);
-               for (GList *l = keys; l != NULL; l = l->next) {
-                       const gchar *key = l->data;
-                       const gchar *value = g_hash_table_lookup (auth->metadata, key);
-                       if (value == NULL)
-                               continue;
-                       if (!secret_password_store_sync (&schema,
-                                                        NULL, /* collection */
-                                                        auth->provider_schema,
-                                                        value,
-                                                        cancellable, error,
-                                                        "key", key, NULL))
-                               return FALSE;
-               }
-       }
+       goa_object = goa_client_lookup_by_id (auth->goa_client, account_id);
+       if (!goa_object)
+               return TRUE;
 
-       /* success */
+       g_value_take_object (value, goa_object);
        return TRUE;
 }
 
-gboolean
-gs_auth_store_clear (GsAuth *auth, GsAuthStoreFlags flags,
-                    GCancellable *cancellable, GError **error)
+static GVariant *
+goa_object_to_string (const GValue       *value,
+                     const GVariantType *expected_type,
+                     gpointer            user_data)
 {
-       SecretSchema schema = {
-               auth->provider_schema,
-               SECRET_SCHEMA_NONE,
-               { { "key", SECRET_SCHEMA_ATTRIBUTE_STRING } }
-       };
-
-       /* no schema */
-       if (auth->provider_schema == NULL) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "No provider schema set for %s",
-                            auth->provider_id);
-               return FALSE;
-       }
+       GObject *object = g_value_get_object (value);
 
-       /* username */
-       if ((flags & GS_AUTH_STORE_FLAG_USERNAME) > 0) {
-               if (!secret_password_clear_sync (&schema,
-                                                cancellable, error,
-                                                "key", "username", NULL))
-                       return FALSE;
-       }
+       GoaObject *goa_object = object != NULL ? GOA_OBJECT (object) : NULL;
+       GoaAccount *goa_account = goa_object != NULL ? goa_object_peek_account (goa_object) : NULL;
 
-       g_free (auth->username);
-       auth->username = NULL;
-
-       /* password */
-       if ((flags & GS_AUTH_STORE_FLAG_PASSWORD) > 0) {
-               if (!secret_password_clear_sync (&schema,
-                                                cancellable, error,
-                                                "key", "password", NULL))
-                       return FALSE;
-       }
-
-       g_free (auth->password);
-       auth->password = NULL;
-
-       /* metadata */
-       if (flags & GS_AUTH_STORE_FLAG_METADATA) {
-               g_autoptr(GList) keys = NULL;
-               keys = g_hash_table_get_keys (auth->metadata);
-               for (GList *l = keys; l != NULL; l = l->next) {
-                       const gchar *key = l->data;
-                       if (!secret_password_clear_sync (&schema,
-                                                        cancellable, error,
-                                                        "key", key, NULL))
-                               return FALSE;
-
-               }
-       }
+       if (goa_account != NULL)
+               return g_variant_new_string (goa_account_get_id (goa_account));
+       else
+               return g_variant_new_string ("");
+}
 
-       g_hash_table_remove_all (auth->metadata);
+/* GObject */
 
-       /* success */
-       return TRUE;
+static void
+gs_auth_init (GsAuth *auth)
+{
 }
 
 static void
 gs_auth_get_property (GObject *object, guint prop_id,
-                       GValue *value, GParamSpec *pspec)
+                     GValue *value, GParamSpec *pspec)
 {
        GsAuth *auth = GS_AUTH (object);
 
        switch (prop_id) {
-       case PROP_USERNAME:
-               g_value_set_string (value, auth->username);
-               break;
-       case PROP_PASSWORD:
-               g_value_set_string (value, auth->password);
+       case PROP_AUTH_ID:
+               g_value_set_string (value, auth->auth_id);
                break;
-       case PROP_FLAGS:
-               g_value_set_uint64 (value, auth->flags);
+       case PROP_PROVIDER_TYPE:
+               g_value_set_string (value, auth->provider_type);
                break;
-       case PROP_PIN:
-               g_value_set_string (value, auth->pin);
+       case PROP_GOA_OBJECT:
+               g_value_set_object (value, auth->goa_object);
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -647,22 +343,19 @@ gs_auth_get_property (GObject *object, guint prop_id,
 
 static void
 gs_auth_set_property (GObject *object, guint prop_id,
-                       const GValue *value, GParamSpec *pspec)
+                     const GValue *value, GParamSpec *pspec)
 {
        GsAuth *auth = GS_AUTH (object);
 
        switch (prop_id) {
-       case PROP_USERNAME:
-               gs_auth_set_username (auth, g_value_get_string (value));
+       case PROP_AUTH_ID:
+               auth->auth_id = g_value_dup_string (value);
                break;
-       case PROP_PASSWORD:
-               gs_auth_set_password (auth, g_value_get_string (value));
+       case PROP_PROVIDER_TYPE:
+               auth->provider_type = g_value_dup_string (value);
                break;
-       case PROP_FLAGS:
-               gs_auth_set_flags (auth, g_value_get_uint64 (value));
-               break;
-       case PROP_PIN:
-               gs_auth_set_pin (auth, g_value_get_string (value));
+       case PROP_GOA_OBJECT:
+               gs_auth_set_goa_object (auth, g_value_get_object (value));
                break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -675,15 +368,16 @@ gs_auth_finalize (GObject *object)
 {
        GsAuth *auth = GS_AUTH (object);
 
-       g_free (auth->provider_id);
+       g_free (auth->header_none);
+       g_free (auth->header_single);
+       g_free (auth->header_multiple);
+       g_free (auth->auth_id);
        g_free (auth->provider_name);
-       g_free (auth->provider_logo);
-       g_free (auth->provider_uri);
-       g_free (auth->provider_schema);
-       g_free (auth->username);
-       g_free (auth->password);
-       g_free (auth->pin);
-       g_hash_table_unref (auth->metadata);
+
+       g_clear_object (&auth->goa_client);
+       g_clear_object (&auth->goa_object);
+
+       g_clear_object (&auth->settings);
 
        G_OBJECT_CLASS (gs_auth_parent_class)->finalize (object);
 }
@@ -693,64 +387,99 @@ gs_auth_class_init (GsAuthClass *klass)
 {
        GParamSpec *pspec;
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
        object_class->finalize = gs_auth_finalize;
        object_class->get_property = gs_auth_get_property;
        object_class->set_property = gs_auth_set_property;
 
-       /**
-        * GsAuth:username:
-        */
-       pspec = g_param_spec_string ("username", NULL, NULL,
-                                    NULL,
-                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
-       g_object_class_install_property (object_class, PROP_USERNAME, pspec);
-
-       /**
-        * GsAuth:password:
-        */
-       pspec = g_param_spec_string ("password", NULL, NULL,
-                                    NULL,
-                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
-       g_object_class_install_property (object_class, PROP_PASSWORD, pspec);
-
-       /**
-        * GsAuth:flags:
-        */
-       pspec = g_param_spec_uint64 ("flags", NULL, NULL,
-                                    GS_AUTH_FLAG_NONE,
-                                    GS_AUTH_FLAG_LAST,
-                                    GS_AUTH_FLAG_NONE,
-                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
-       g_object_class_install_property (object_class, PROP_FLAGS, pspec);
-
-       /**
-        * GsAuth:pin:
-        */
-       pspec = g_param_spec_string ("pin", NULL, NULL,
-                                    NULL,
-                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
-       g_object_class_install_property (object_class, PROP_PIN, pspec);
+       pspec = g_param_spec_string ("auth-id", NULL, NULL, NULL,
+                                    G_PARAM_READWRITE |
+                                    G_PARAM_CONSTRUCT_ONLY);
+       g_object_class_install_property (object_class, PROP_AUTH_ID, pspec);
+
+       pspec = g_param_spec_string ("provider-type", NULL, NULL, NULL,
+                                    G_PARAM_READWRITE |
+                                    G_PARAM_CONSTRUCT_ONLY);
+       g_object_class_install_property (object_class, PROP_PROVIDER_TYPE, pspec);
+
+       pspec = g_param_spec_object ("goa-object", NULL, NULL,
+                                    GOA_TYPE_OBJECT,
+                                    G_PARAM_READWRITE |
+                                    G_PARAM_EXPLICIT_NOTIFY);
+       g_object_class_install_property (object_class, PROP_GOA_OBJECT, pspec);
+
+       signals [SIGNAL_CHANGED] =
+               g_signal_new ("changed",
+                             G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+                             0, NULL, NULL, g_cclosure_marshal_generic,
+                             G_TYPE_NONE, 0);
+}
+
+/* GInitable */
+
+static gboolean
+gs_auth_initable_init (GInitable *initable,
+                      GCancellable *cancellable,
+                      GError  **error)
+{
+       GsAuth *self;
+       g_autofree gchar *path = NULL;
+
+       g_return_val_if_fail (GS_IS_AUTH (initable), FALSE);
+
+       self = GS_AUTH (initable);
+
+       self->goa_client = goa_client_new_sync (NULL, error);
+       if (self->goa_client == NULL)
+               return FALSE;
+
+       g_signal_connect (self->goa_client, "account-changed",
+                         G_CALLBACK (gs_auth_account_changed_cb), self);
+       g_signal_connect (self->goa_client, "account-removed",
+                         G_CALLBACK (gs_auth_account_removed_cb), self);
+
+       path = g_strdup_printf ("/org/gnome/software/auth/%s/", self->auth_id);
+       self->settings = g_settings_new_with_path ("org.gnome.software.auth", path);
+
+       g_settings_bind_with_mapping (self->settings, "account-id",
+                                     self, "goa-object",
+                                     G_SETTINGS_BIND_DEFAULT,
+                                     string_to_goa_object,
+                                     goa_object_to_string,
+                                     self, NULL);
+
+       return TRUE;
 }
 
 static void
-gs_auth_init (GsAuth *auth)
+gs_auth_initable_iface_init (GInitableIface *iface)
 {
-       auth->metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                               g_free, g_free);
+       iface->init = gs_auth_initable_init;
 }
 
 /**
  * gs_auth_new:
- * @provider_id: a provider ID used for mapping, e.g. "GnomeSSO"
+ * @auth_id: an identifier used for mapping, e.g. "snapd"
+ * @provider_type: the name of the GoaProvider466 to be used, e.g. "ubuntusso"
+ * @error: A #GError
  *
- * Return value: a new #GsAuth object.
+ * Return value: (transfer full) (nullable): a new #GsAuth object.
  **/
 GsAuth *
-gs_auth_new (const gchar *provider_id)
+gs_auth_new (const gchar *auth_id,
+            const gchar *provider_type,
+            GError **error)
 {
        GsAuth *auth;
-       auth = g_object_new (GS_TYPE_AUTH, NULL);
-       auth->provider_id = g_strdup (provider_id);
+
+       g_return_val_if_fail (auth_id != NULL, NULL);
+       g_return_val_if_fail (provider_type != NULL, NULL);
+
+       auth = g_initable_new (GS_TYPE_AUTH, NULL, error,
+                              "auth-id", auth_id,
+                              "provider-type", provider_type,
+                              NULL);
+
        return GS_AUTH (auth);
 }
 
diff --git a/lib/gs-auth.h b/lib/gs-auth.h
index 55df1a7d..c2018f67 100644
--- a/lib/gs-auth.h
+++ b/lib/gs-auth.h
@@ -1,6 +1,7 @@
  /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
  * Copyright (C) 2016 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2018 Canonical Ltd
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -24,6 +25,8 @@
 
 #include <glib-object.h>
 #include <gio/gio.h>
+#define GOA_API_IS_SUBJECT_TO_CHANGE
+#include <goa/goa.h>
 
 G_BEGIN_DECLS
 
@@ -31,88 +34,23 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (GsAuth, gs_auth, GS, AUTH, GObject)
 
-/**
- * GsAuthFlags:
- * @GS_AUTH_FLAG_NONE:                 No special flags set
- * @GS_AUTH_FLAG_VALID:                        Authorisation is valid
- * @GS_AUTH_FLAG_REMEMBER:             Remember this authentication if possible
- *
- * The flags for the auth.
- **/
-typedef enum {
-       GS_AUTH_FLAG_NONE       = 0,
-       GS_AUTH_FLAG_VALID      = 1 << 0,
-       GS_AUTH_FLAG_REMEMBER   = 1 << 1,
-       /*< private >*/
-       GS_AUTH_FLAG_LAST
-} GsAuthFlags;
-
-/**
- * GsAuthStoreFlags:
- * @GS_AUTH_STORE_FLAG_NONE:           No special flags set
- * @GS_AUTH_STORE_FLAG_USERNAME:       Load or save the username
- * @GS_AUTH_STORE_FLAG_PASSWORD:       Load or save the password
- * @GS_AUTH_STORE_FLAG_METADATA:       Load or save any metadata
- *
- * The flags used when loading or saving the authentication to disk.
- **/
-typedef enum {
-       GS_AUTH_STORE_FLAG_NONE = 0,
-       GS_AUTH_STORE_FLAG_USERNAME     = 1 << 0,
-       GS_AUTH_STORE_FLAG_PASSWORD     = 1 << 1,
-       GS_AUTH_STORE_FLAG_METADATA     = 1 << 2,
-       /*< private >*/
-       GS_AUTH_STORE_FLAG_LAST
-} GsAuthStoreFlags;
-
-GsAuth         *gs_auth_new                    (const gchar    *provider_id);
-const gchar    *gs_auth_get_provider_id        (GsAuth         *auth);
+GsAuth         *gs_auth_new                    (const gchar    *auth_id,
+                                                const gchar    *provider_type,
+                                                GError        **error);
+const gchar    *gs_auth_get_header             (GsAuth         *auth,
+                                                guint           n);
+void            gs_auth_set_header             (GsAuth         *auth,
+                                                const gchar    *header_none,
+                                                const gchar    *header_single,
+                                                const gchar    *header_multiple);
+const gchar    *gs_auth_get_auth_id            (GsAuth         *auth);
 const gchar    *gs_auth_get_provider_name      (GsAuth         *auth);
 void            gs_auth_set_provider_name      (GsAuth         *auth,
                                                 const gchar    *provider_name);
-const gchar    *gs_auth_get_provider_logo      (GsAuth         *auth);
-void            gs_auth_set_provider_logo      (GsAuth         *auth,
-                                                const gchar    *provider_logo);
-const gchar    *gs_auth_get_provider_uri       (GsAuth         *auth);
-void            gs_auth_set_provider_uri       (GsAuth         *auth,
-                                                const gchar    *provider_uri);
-const gchar    *gs_auth_get_provider_schema    (GsAuth         *auth);
-void            gs_auth_set_provider_schema    (GsAuth         *auth,
-                                                const gchar    *provider_schema);
-const gchar    *gs_auth_get_username           (GsAuth         *auth);
-void            gs_auth_set_username           (GsAuth         *auth,
-                                                const gchar    *username);
-const gchar    *gs_auth_get_password           (GsAuth         *auth);
-void            gs_auth_set_password           (GsAuth         *auth,
-                                                const gchar    *password);
-const gchar    *gs_auth_get_pin                (GsAuth         *auth);
-void            gs_auth_set_pin                (GsAuth         *auth,
-                                                const gchar    *pin);
-GsAuthFlags     gs_auth_get_flags              (GsAuth         *auth);
-void            gs_auth_set_flags              (GsAuth         *auth,
-                                                GsAuthFlags     flags);
-void            gs_auth_add_flags              (GsAuth         *auth,
-                                                GsAuthFlags     flags);
-gboolean        gs_auth_has_flag               (GsAuth         *auth,
-                                                GsAuthFlags     flags);
-const gchar    *gs_auth_get_metadata_item      (GsAuth         *auth,
-                                                const gchar    *key);
-void            gs_auth_add_metadata           (GsAuth         *auth,
-                                                const gchar    *key,
-                                                const gchar    *value);
-gboolean        gs_auth_store_load             (GsAuth         *auth,
-                                                GsAuthStoreFlags flags,
-                                                GCancellable   *cancellable,
-                                                GError         **error);
-gboolean        gs_auth_store_save             (GsAuth         *auth,
-                                                GsAuthStoreFlags flags,
-                                                GCancellable   *cancellable,
-                                                GError         **error);
-gboolean        gs_auth_store_clear            (GsAuth         *auth,
-                                                GsAuthStoreFlags flags,
-                                                GCancellable   *cancellable,
-                                                GError         **error);
-
+const gchar    *gs_auth_get_provider_type      (GsAuth         *auth);
+GoaObject      *gs_auth_peek_goa_object        (GsAuth         *auth);
+void            gs_auth_set_goa_object         (GsAuth         *auth,
+                                                GoaObject      *goa_object);
 G_END_DECLS
 
 #endif /* __GS_AUTH_H */
diff --git a/lib/gs-plugin-job.c b/lib/gs-plugin-job.c
index 4254194c..e1d8bc79 100644
--- a/lib/gs-plugin-job.c
+++ b/lib/gs-plugin-job.c
@@ -131,7 +131,7 @@ gs_plugin_job_to_string (GsPluginJob *self)
        }
        if (self->auth != NULL) {
                g_string_append_printf (str, " with auth=%s",
-                                       gs_auth_get_provider_id (self->auth));
+                                       gs_auth_get_auth_id (self->auth));
        }
        if (self->file != NULL) {
                g_autofree gchar *path = g_file_get_path (self->file);
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 5f469262..d298d4f6 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -720,17 +720,6 @@ gs_plugin_loader_call_vfunc (GsPluginLoaderHelper *helper,
                                           cancellable, &error_local);
                }
                break;
-       case GS_PLUGIN_ACTION_AUTH_LOGIN:
-       case GS_PLUGIN_ACTION_AUTH_LOGOUT:
-       case GS_PLUGIN_ACTION_AUTH_REGISTER:
-       case GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD:
-               {
-                       GsPluginAuthFunc plugin_func = func;
-                       ret = plugin_func (plugin,
-                                          gs_plugin_job_get_auth (helper->plugin_job),
-                                          cancellable, &error_local);
-               }
-               break;
        default:
                g_critical ("no handler for %s", helper->function_name);
                break;
@@ -2140,7 +2129,7 @@ gs_plugin_loader_get_scale (GsPluginLoader *plugin_loader)
 
 GsAuth *
 gs_plugin_loader_get_auth_by_id (GsPluginLoader *plugin_loader,
-                                const gchar *provider_id)
+                                const gchar *auth_id)
 {
        GsPluginLoaderPrivate *priv = gs_plugin_loader_get_instance_private (plugin_loader);
        guint i;
@@ -2148,7 +2137,7 @@ gs_plugin_loader_get_auth_by_id (GsPluginLoader *plugin_loader,
        /* match on ID */
        for (i = 0; i < priv->auth_array->len; i++) {
                GsAuth *auth = g_ptr_array_index (priv->auth_array, i);
-               if (g_strcmp0 (gs_auth_get_provider_id (auth), provider_id) == 0)
+               if (g_strcmp0 (gs_auth_get_auth_id (auth), auth_id) == 0)
                        return auth;
        }
        return NULL;
diff --git a/lib/gs-plugin-loader.h b/lib/gs-plugin-loader.h
index bb013826..16ad468a 100644
--- a/lib/gs-plugin-loader.h
+++ b/lib/gs-plugin-loader.h
@@ -80,7 +80,7 @@ gboolean       gs_plugin_loader_get_enabled           (GsPluginLoader *plugin_loader,
 void            gs_plugin_loader_add_location          (GsPluginLoader *plugin_loader,
                                                         const gchar    *location);
 GsAuth         *gs_plugin_loader_get_auth_by_id        (GsPluginLoader *plugin_loader,
-                                                        const gchar    *provider_id);
+                                                        const gchar    *auth_id);
 GPtrArray      *gs_plugin_loader_get_auths             (GsPluginLoader *plugin_loader);
 guint           gs_plugin_loader_get_scale             (GsPluginLoader *plugin_loader);
 void            gs_plugin_loader_set_scale             (GsPluginLoader *plugin_loader,
diff --git a/lib/gs-plugin-types.h b/lib/gs-plugin-types.h
index f3c67e8e..aae56646 100644
--- a/lib/gs-plugin-types.h
+++ b/lib/gs-plugin-types.h
@@ -73,9 +73,6 @@ typedef guint64 GsPluginFlags;
  * @GS_PLUGIN_ERROR_NO_SPACE:                  No disk space to allow action
  * @GS_PLUGIN_ERROR_AUTH_REQUIRED:             Authentication was required
  * @GS_PLUGIN_ERROR_AUTH_INVALID:              Provided authentication was invalid
- * @GS_PLUGIN_ERROR_PIN_REQUIRED:              PIN required for authentication
- * @GS_PLUGIN_ERROR_ACCOUNT_SUSPENDED:         User account has been suspended
- * @GS_PLUGIN_ERROR_ACCOUNT_DEACTIVATED:       User account has been deactivated
  * @GS_PLUGIN_ERROR_PLUGIN_DEPSOLVE_FAILED:    The plugins installed are incompatible
  * @GS_PLUGIN_ERROR_DOWNLOAD_FAILED:           The download action failed
  * @GS_PLUGIN_ERROR_WRITE_FAILED:              The save-to-disk failed
@@ -98,9 +95,6 @@ typedef enum {
        GS_PLUGIN_ERROR_NO_SPACE,
        GS_PLUGIN_ERROR_AUTH_REQUIRED,
        GS_PLUGIN_ERROR_AUTH_INVALID,
-       GS_PLUGIN_ERROR_PIN_REQUIRED,
-       GS_PLUGIN_ERROR_ACCOUNT_SUSPENDED,
-       GS_PLUGIN_ERROR_ACCOUNT_DEACTIVATED,
        GS_PLUGIN_ERROR_PLUGIN_DEPSOLVE_FAILED,
        GS_PLUGIN_ERROR_DOWNLOAD_FAILED,
        GS_PLUGIN_ERROR_WRITE_FAILED,
@@ -242,10 +236,6 @@ typedef enum {
  * @GS_PLUGIN_ACTION_REFINE:                   Refine the application
  * @GS_PLUGIN_ACTION_REFRESH:                  Refresh all the sources
  * @GS_PLUGIN_ACTION_FILE_TO_APP:              Convert the file to an application
- * @GS_PLUGIN_ACTION_AUTH_LOGIN:               Authentication login action
- * @GS_PLUGIN_ACTION_AUTH_LOGOUT:              Authentication logout action
- * @GS_PLUGIN_ACTION_AUTH_REGISTER:            Authentication register action
- * @GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD:       Authentication lost password action
  * @GS_PLUGIN_ACTION_URL_TO_APP:               Convert the file to an application
  * @GS_PLUGIN_ACTION_GET_RECENT:               Get the apps recently released
  * @GS_PLUGIN_ACTION_GET_UPDATES_HISTORICAL:    Get the list of historical updates
@@ -291,10 +281,6 @@ typedef enum {
        GS_PLUGIN_ACTION_REFINE,
        GS_PLUGIN_ACTION_REFRESH,
        GS_PLUGIN_ACTION_FILE_TO_APP,
-       GS_PLUGIN_ACTION_AUTH_LOGIN,
-       GS_PLUGIN_ACTION_AUTH_LOGOUT,
-       GS_PLUGIN_ACTION_AUTH_REGISTER,
-       GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD,
        GS_PLUGIN_ACTION_URL_TO_APP,
        GS_PLUGIN_ACTION_GET_RECENT,
        GS_PLUGIN_ACTION_GET_UPDATES_HISTORICAL,
diff --git a/lib/gs-plugin-vfuncs.h b/lib/gs-plugin-vfuncs.h
index 011acdf4..a30fe7a5 100644
--- a/lib/gs-plugin-vfuncs.h
+++ b/lib/gs-plugin-vfuncs.h
@@ -977,70 +977,6 @@ gboolean    gs_plugin_update                       (GsPlugin       *plugin,
                                                         GCancellable   *cancellable,
                                                         GError         **error);
 
-/**
- * gs_plugin_auth_login:
- * @plugin: a #GsPlugin
- * @auth: a #GsAuth
- * @cancellable: a #GCancellable, or %NULL
- * @error: a #GError, or %NULL
- *
- * Performs a login using the given authentication details.
- *
- * Returns: %TRUE for success or if not relevant
- **/
-gboolean        gs_plugin_auth_login                   (GsPlugin       *plugin,
-                                                        GsAuth         *auth,
-                                                        GCancellable   *cancellable,
-                                                        GError         **error);
-
-/**
- * gs_plugin_auth_logout:
- * @plugin: a #GsPlugin
- * @auth: a #GsAuth
- * @cancellable: a #GCancellable, or %NULL
- * @error: a #GError, or %NULL
- *
- * Performs a logout using the given authentication details.
- *
- * Returns: %TRUE for success or if not relevant
- **/
-gboolean        gs_plugin_auth_logout                  (GsPlugin       *plugin,
-                                                        GsAuth         *auth,
-                                                        GCancellable   *cancellable,
-                                                        GError         **error);
-
-/**
- * gs_plugin_auth_lost_password:
- * @plugin: a #GsPlugin
- * @auth: a #GsAuth
- * @cancellable: a #GCancellable, or %NULL
- * @error: a #GError, or %NULL
- *
- * Performs the lost password action using the given authentication details.
- *
- * Returns: %TRUE for success or if not relevant
- **/
-gboolean        gs_plugin_auth_lost_password           (GsPlugin       *plugin,
-                                                        GsAuth         *auth,
-                                                        GCancellable   *cancellable,
-                                                        GError         **error);
-
-/**
- * gs_plugin_auth_register:
- * @plugin: a #GsPlugin
- * @auth: a #GsAuth
- * @cancellable: a #GCancellable, or %NULL
- * @error: a #GError, or %NULL
- *
- * Performs the registration action using the given authentication details.
- *
- * Returns: %TRUE for success or if not relevant
- **/
-gboolean        gs_plugin_auth_register                (GsPlugin       *plugin,
-                                                        GsAuth         *auth,
-                                                        GCancellable   *cancellable,
-                                                        GError         **error);
-
 G_END_DECLS
 
 #endif /* __GS_PLUGIN_VFUNCS_H */
diff --git a/lib/gs-plugin.c b/lib/gs-plugin.c
index 4af3bc8a..28374bfc 100644
--- a/lib/gs-plugin.c
+++ b/lib/gs-plugin.c
@@ -645,7 +645,7 @@ gs_plugin_add_auth (GsPlugin *plugin, GsAuth *auth)
 /**
  * gs_plugin_get_auth_by_id:
  * @plugin: a #GsPlugin
- * @provider_id: an ID, e.g. "dummy-sso"
+ * @auth_id: an ID, e.g. "dummy-sso"
  *
  * Gets a specific authentication object.
  *
@@ -654,7 +654,7 @@ gs_plugin_add_auth (GsPlugin *plugin, GsAuth *auth)
  * Since: 3.22
  **/
 GsAuth *
-gs_plugin_get_auth_by_id (GsPlugin *plugin, const gchar *provider_id)
+gs_plugin_get_auth_by_id (GsPlugin *plugin, const gchar *auth_id)
 {
        GsPluginPrivate *priv = gs_plugin_get_instance_private (plugin);
        guint i;
@@ -662,7 +662,7 @@ gs_plugin_get_auth_by_id (GsPlugin *plugin, const gchar *provider_id)
        /* match on ID */
        for (i = 0; i < priv->auth_array->len; i++) {
                GsAuth *auth = g_ptr_array_index (priv->auth_array, i);
-               if (g_strcmp0 (gs_auth_get_provider_id (auth), provider_id) == 0)
+               if (g_strcmp0 (gs_auth_get_auth_id (auth), auth_id) == 0)
                        return auth;
        }
        return NULL;
@@ -1544,12 +1544,6 @@ gs_plugin_error_to_string (GsPluginError error)
                return "auth-required";
        if (error == GS_PLUGIN_ERROR_AUTH_INVALID)
                return "auth-invalid";
-       if (error == GS_PLUGIN_ERROR_PIN_REQUIRED)
-               return "pin-required";
-       if (error == GS_PLUGIN_ERROR_ACCOUNT_SUSPENDED)
-               return "account-suspended";
-       if (error == GS_PLUGIN_ERROR_ACCOUNT_DEACTIVATED)
-               return "account-deactivated";
        if (error == GS_PLUGIN_ERROR_PLUGIN_DEPSOLVE_FAILED)
                return "plugin-depsolve-failed";
        if (error == GS_PLUGIN_ERROR_DOWNLOAD_FAILED)
@@ -1650,14 +1644,6 @@ gs_plugin_action_to_function_name (GsPluginAction action)
                return "gs_plugin_add_search_files";
        if (action == GS_PLUGIN_ACTION_SEARCH_PROVIDES)
                return "gs_plugin_add_search_what_provides";
-       if (action == GS_PLUGIN_ACTION_AUTH_LOGIN)
-               return "gs_plugin_auth_login";
-       if (action == GS_PLUGIN_ACTION_AUTH_LOGOUT)
-               return "gs_plugin_auth_logout";
-       if (action == GS_PLUGIN_ACTION_AUTH_REGISTER)
-               return "gs_plugin_auth_register";
-       if (action == GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD)
-               return "gs_plugin_auth_lost_password";
        if (action == GS_PLUGIN_ACTION_GET_CATEGORY_APPS)
                return "gs_plugin_add_category_apps";
        if (action == GS_PLUGIN_ACTION_GET_CATEGORIES)
@@ -1756,14 +1742,6 @@ gs_plugin_action_to_string (GsPluginAction action)
                return "file-to-app";
        if (action == GS_PLUGIN_ACTION_URL_TO_APP)
                return "url-to-app";
-       if (action == GS_PLUGIN_ACTION_AUTH_LOGIN)
-               return "auth-login";
-       if (action == GS_PLUGIN_ACTION_AUTH_LOGOUT)
-               return "auth-logout";
-       if (action == GS_PLUGIN_ACTION_AUTH_REGISTER)
-               return "auth-register";
-       if (action == GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD)
-               return "auth-lost-password";
        if (action == GS_PLUGIN_ACTION_GET_RECENT)
                return "get-recent";
        if (action == GS_PLUGIN_ACTION_GET_UPDATES_HISTORICAL)
@@ -1860,14 +1838,6 @@ gs_plugin_action_from_string (const gchar *action)
                return GS_PLUGIN_ACTION_FILE_TO_APP;
        if (g_strcmp0 (action, "url-to-app") == 0)
                return GS_PLUGIN_ACTION_URL_TO_APP;
-       if (g_strcmp0 (action, "auth-login") == 0)
-               return GS_PLUGIN_ACTION_AUTH_LOGIN;
-       if (g_strcmp0 (action, "auth-logout") == 0)
-               return GS_PLUGIN_ACTION_AUTH_LOGOUT;
-       if (g_strcmp0 (action, "auth-register") == 0)
-               return GS_PLUGIN_ACTION_AUTH_REGISTER;
-       if (g_strcmp0 (action, "auth-lost-password") == 0)
-               return GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD;
        if (g_strcmp0 (action, "get-recent") == 0)
                return GS_PLUGIN_ACTION_GET_RECENT;
        if (g_strcmp0 (action, "get-updates-historical") == 0)
diff --git a/lib/gs-plugin.h b/lib/gs-plugin.h
index 692fa85e..ac0ffaa7 100644
--- a/lib/gs-plugin.h
+++ b/lib/gs-plugin.h
@@ -89,7 +89,7 @@ void           gs_plugin_set_soup_session             (GsPlugin       *plugin,
 void            gs_plugin_add_auth                     (GsPlugin       *plugin,
                                                         GsAuth         *auth);
 GsAuth         *gs_plugin_get_auth_by_id               (GsPlugin       *plugin,
-                                                        const gchar    *provider_id);
+                                                        const gchar    *auth_id);
 void            gs_plugin_add_rule                     (GsPlugin       *plugin,
                                                         GsPluginRule    rule,
                                                         const gchar    *name);
diff --git a/lib/gs-self-test.c b/lib/gs-self-test.c
index b5ba3736..9fd4a45c 100644
--- a/lib/gs-self-test.c
+++ b/lib/gs-self-test.c
@@ -707,54 +707,6 @@ gs_app_func (void)
        gs_app_set_state_recover (app);
 }
 
-static void
-gs_auth_secret_func (void)
-{
-       gboolean ret;
-       g_autoptr(GDBusConnection) conn = NULL;
-       g_autoptr(GError) error = NULL;
-       g_autoptr(GsAuth) auth1 = NULL;
-       g_autoptr(GsAuth) auth2 = NULL;
-
-       /* we not have an active session bus */
-       conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-       if (conn == NULL) {
-               g_prefix_error (&error, "no session bus available: ");
-               g_test_skip (error->message);
-               return;
-       }
-
-       /* save secrets to disk */
-       auth1 = gs_auth_new ("self-test");
-       gs_auth_set_provider_schema (auth1, "org.gnome.Software.Dummy");
-       gs_auth_set_username (auth1, "hughsie");
-       gs_auth_set_password (auth1, "foobarbaz");
-       gs_auth_add_metadata (auth1, "day", "monday");
-       ret = gs_auth_store_save (auth1,
-                                 GS_AUTH_STORE_FLAG_USERNAME |
-                                 GS_AUTH_STORE_FLAG_PASSWORD |
-                                 GS_AUTH_STORE_FLAG_METADATA,
-                                 NULL, &error);
-       g_assert_no_error (error);
-       g_assert (ret);
-
-       /* load secrets from disk */
-       auth2 = gs_auth_new ("self-test");
-       gs_auth_add_metadata (auth2, "day", NULL);
-       gs_auth_add_metadata (auth2, "notgoingtoexist", NULL);
-       gs_auth_set_provider_schema (auth2, "org.gnome.Software.Dummy");
-       ret = gs_auth_store_load (auth2,
-                                 GS_AUTH_STORE_FLAG_USERNAME |
-                                 GS_AUTH_STORE_FLAG_PASSWORD |
-                                 GS_AUTH_STORE_FLAG_METADATA,
-                                 NULL, &error);
-       g_assert_no_error (error);
-       g_assert (ret);
-       g_assert_cmpstr (gs_auth_get_username (auth2), ==, "hughsie");
-       g_assert_cmpstr (gs_auth_get_password (auth2), ==, "foobarbaz");
-       g_assert_cmpstr (gs_auth_get_metadata_item (auth2, "day"), ==, "monday");
-}
-
 static void
 gs_app_list_func (void)
 {
@@ -831,7 +783,6 @@ main (int argc, char **argv)
        g_test_add_func ("/gnome-software/lib/app{list-related}", gs_app_list_related_func);
        g_test_add_func ("/gnome-software/lib/plugin", gs_plugin_func);
        g_test_add_func ("/gnome-software/lib/plugin{download-rewrite}", gs_plugin_download_rewrite_func);
-       g_test_add_func ("/gnome-software/lib/auth{secret}", gs_auth_secret_func);
 
        return g_test_run ();
 }
diff --git a/lib/meson.build b/lib/meson.build
index 7b11e72c..766d379c 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -57,10 +57,10 @@ librarydeps = [
   appstream_glib,
   gio_unix,
   gmodule,
+  goa,
   gtk,
   json_glib,
   libm,
-  libsecret,
   libsoup,
   valgrind,
 ]
@@ -108,10 +108,10 @@ executable(
     appstream_glib,
     gio_unix,
     gmodule,
+    goa,
     gtk,
     json_glib,
     libm,
-    libsecret,
     libsoup,
     valgrind,
   ],
@@ -138,10 +138,10 @@ if get_option('tests')
       appstream_glib,
       gio_unix,
       gmodule,
+      goa,
       gtk,
       json_glib,
       libm,
-      libsecret,
       libsoup
     ],
     link_with : [
diff --git a/meson.build b/meson.build
index ef349e67..34877ece 100644
--- a/meson.build
+++ b/meson.build
@@ -101,10 +101,10 @@ gdk_pixbuf = dependency('gdk-pixbuf-2.0', version : '>= 2.32.0')
 libxmlb = dependency('xmlb', version : '>= 0.1.4', fallback : ['libxmlb', 'libxmlb_dep'])
 gio_unix = dependency('gio-unix-2.0', version : '>= 2.56.0')
 gmodule = dependency('gmodule-2.0')
+goa = dependency('goa-1.0')
 gtk = dependency('gtk+-3.0', version : '>= 3.22.4')
 json_glib = dependency('json-glib-1.0', version : '>= 1.2.0')
 libm = cc.find_library('m', required: false)
-libsecret = dependency('libsecret-1')
 libsoup = dependency('libsoup-2.4', version : '>= 2.52.0')
 
 if get_option('valgrind')
diff --git a/plugins/dummy/gs-plugin-dummy.c b/plugins/dummy/gs-plugin-dummy.c
index cb6c6ce1..cf1769c9 100644
--- a/plugins/dummy/gs-plugin-dummy.c
+++ b/plugins/dummy/gs-plugin-dummy.c
@@ -69,14 +69,11 @@ gs_plugin_initialize (GsPlugin *plugin)
        }
 
        /* set up a dummy authentication provider */
-       priv->auth = gs_auth_new (gs_plugin_get_name (plugin));
-       gs_auth_set_provider_name (priv->auth, "GNOME SSO");
-       gs_auth_set_provider_logo (priv->auth, "/usr/share/pixmaps/gnome-about-logo.png");
-       gs_auth_set_provider_uri (priv->auth, "http://www.gnome.org/sso";);
-       gs_plugin_add_auth (plugin, priv->auth);
-
-       /* lets assume we read this from disk somewhere */
-       gs_auth_set_username (priv->auth, "dummy");
+       priv->auth = gs_auth_new (gs_plugin_get_name (plugin), "google", NULL);
+       if (priv->auth != NULL) {
+               gs_auth_set_provider_name (priv->auth, "GNOME SSO");
+               gs_plugin_add_auth (plugin, priv->auth);
+       }
 
        /* add source */
        priv->cached_origin = gs_app_new (gs_plugin_get_name (plugin));
@@ -980,93 +977,3 @@ gs_plugin_review_remove (GsPlugin *plugin,
        g_debug ("Removing dummy self-review");
        return TRUE;
 }
-
-gboolean
-gs_plugin_auth_login (GsPlugin *plugin, GsAuth *auth,
-                     GCancellable *cancellable, GError **error)
-{
-       GsPluginData *priv = gs_plugin_get_data (plugin);
-
-       /* not us */
-       if (g_strcmp0 (gs_auth_get_provider_id (auth),
-                      gs_auth_get_provider_id (priv->auth)) != 0)
-               return TRUE;
-
-       /* already logged in */
-       if (priv->has_auth)
-               return TRUE;
-
-       /* check username and password */
-       if (g_strcmp0 (gs_auth_get_username (priv->auth), "dummy") != 0 ||
-           g_strcmp0 (gs_auth_get_password (priv->auth), "dummy") != 0) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_AUTH_INVALID,
-                            "The password was not correct.");
-               return FALSE;
-       }
-
-       priv->has_auth = TRUE;
-       gs_auth_add_flags (priv->auth, GS_AUTH_FLAG_VALID);
-       g_debug ("dummy now authenticated");
-       return TRUE;
-}
-
-gboolean
-gs_plugin_auth_logout (GsPlugin *plugin, GsAuth *auth,
-                      GCancellable *cancellable, GError **error)
-{
-       GsPluginData *priv = gs_plugin_get_data (plugin);
-
-       /* not us */
-       if (g_strcmp0 (gs_auth_get_provider_id (auth),
-                      gs_auth_get_provider_id (priv->auth)) != 0)
-               return TRUE;
-
-       /* not logged in */
-       if (!priv->has_auth)
-               return TRUE;
-
-       priv->has_auth = FALSE;
-       gs_auth_set_flags (priv->auth, 0);
-       g_debug ("dummy now not authenticated");
-       return TRUE;
-}
-
-gboolean
-gs_plugin_auth_lost_password (GsPlugin *plugin, GsAuth *auth,
-                             GCancellable *cancellable, GError **error)
-{
-       GsPluginData *priv = gs_plugin_get_data (plugin);
-
-       /* not us */
-       if (g_strcmp0 (gs_auth_get_provider_id (auth),
-                      gs_auth_get_provider_id (priv->auth)) != 0)
-               return TRUE;
-
-       /* return with data */
-       g_set_error_literal (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_AUTH_INVALID,
-                            "do online using @http://www.gnome.org/lost-password/";);
-       return FALSE;
-}
-
-gboolean
-gs_plugin_auth_register (GsPlugin *plugin, GsAuth *auth,
-                        GCancellable *cancellable, GError **error)
-{
-       GsPluginData *priv = gs_plugin_get_data (plugin);
-
-       /* not us */
-       if (g_strcmp0 (gs_auth_get_provider_id (auth),
-                      gs_auth_get_provider_id (priv->auth)) != 0)
-               return TRUE;
-
-       /* return with data */
-       g_set_error_literal (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_AUTH_INVALID,
-                            "do online using @http://www.gnome.org/register/";);
-       return FALSE;
-}
diff --git a/plugins/dummy/gs-self-test.c b/plugins/dummy/gs-self-test.c
index 87a35d0f..1c7cc694 100644
--- a/plugins/dummy/gs-self-test.c
+++ b/plugins/dummy/gs-self-test.c
@@ -566,86 +566,6 @@ gs_plugins_dummy_plugin_cache_func (GsPluginLoader *plugin_loader)
        g_assert (app1 == app2);
 }
 
-static void
-gs_plugins_dummy_authentication_func (GsPluginLoader *plugin_loader)
-{
-       GsAuth *auth;
-       gboolean ret;
-       g_autoptr(GError) error = NULL;
-       g_autoptr(GsApp) app = NULL;
-       g_autoptr(GsAppList) list = NULL;
-       g_autoptr(AsReview) review = NULL;
-       g_autoptr(AsReview) review2 = NULL;
-       g_autoptr(GsPluginJob) plugin_job = NULL;
-
-       /* check initial state */
-       auth = gs_plugin_loader_get_auth_by_id (plugin_loader, "dummy");
-       g_assert (GS_IS_AUTH (auth));
-       g_assert_cmpint (gs_auth_get_flags (auth), ==, 0);
-
-       /* do an action that returns a URL */
-       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_REGISTER,
-                                        "auth", auth,
-                                        NULL);
-       list = gs_plugin_loader_job_process (plugin_loader, plugin_job, NULL, &error);
-       gs_test_flush_main_context ();
-       g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_INVALID);
-       g_assert (list == NULL);
-       g_clear_error (&error);
-       g_assert (!gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
-
-       /* do an action that requires a login */
-       app = gs_app_new (NULL);
-       review = as_review_new ();
-       g_object_unref (plugin_job);
-       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REVIEW_REMOVE,
-                                        "app", app,
-                                        "review", review,
-                                        NULL);
-       ret = gs_plugin_loader_job_action (plugin_loader, plugin_job, NULL, &error);
-       gs_test_flush_main_context ();
-       g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_REQUIRED);
-       g_assert (!ret);
-       g_clear_error (&error);
-
-       /* pretend to auth with no credentials */
-       g_object_unref (plugin_job);
-       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_LOGIN,
-                                        "auth", auth,
-                                        NULL);
-       list = gs_plugin_loader_job_process (plugin_loader, plugin_job, NULL, &error);
-       gs_test_flush_main_context ();
-       g_assert_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_INVALID);
-       g_assert (list == NULL);
-       g_clear_error (&error);
-       g_assert (!gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
-
-       /* auth again with correct credentials */
-       gs_auth_set_username (auth, "dummy");
-       gs_auth_set_password (auth, "dummy");
-       g_object_unref (plugin_job);
-       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_LOGIN,
-                                                "auth", auth,
-                                                NULL);
-       list = gs_plugin_loader_job_process (plugin_loader, plugin_job, NULL, &error);
-       gs_test_flush_main_context ();
-       g_assert_no_error (error);
-       g_assert (list != NULL);
-       g_assert (gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID));
-
-       /* do the action that requires a login */
-       review2 = as_review_new ();
-       g_object_unref (plugin_job);
-       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REVIEW_REMOVE,
-                                        "app", app,
-                                        "review", review2,
-                                        NULL);
-       ret = gs_plugin_loader_job_action (plugin_loader, plugin_job, NULL, &error);
-       gs_test_flush_main_context ();
-       g_assert_no_error (error);
-       g_assert (ret);
-}
-
 static void
 gs_plugins_dummy_wildcard_func (GsPluginLoader *plugin_loader)
 {
@@ -937,9 +857,6 @@ main (int argc, char **argv)
        g_test_add_data_func ("/gnome-software/plugins/dummy/wildcard",
                              plugin_loader,
                              (GTestDataFunc) gs_plugins_dummy_wildcard_func);
-       g_test_add_data_func ("/gnome-software/plugins/dummy/authentication",
-                             plugin_loader,
-                             (GTestDataFunc) gs_plugins_dummy_authentication_func);
        g_test_add_data_func ("/gnome-software/plugins/dummy/plugin-cache",
                              plugin_loader,
                              (GTestDataFunc) gs_plugins_dummy_plugin_cache_func);
diff --git a/plugins/dummy/meson.build b/plugins/dummy/meson.build
index 2359f295..1259c330 100644
--- a/plugins/dummy/meson.build
+++ b/plugins/dummy/meson.build
@@ -12,7 +12,7 @@ shared_module(
   install : true,
   install_dir: plugin_dir,
   c_args : cargs,
-  dependencies : [appstream_glib, gio_unix, gtk, libsoup]
+  dependencies : [appstream_glib, gio_unix, goa, gtk, libsoup]
 )
 
 if get_option('tests')
diff --git a/plugins/meson.build b/plugins/meson.build
index bd182141..f38fc048 100644
--- a/plugins/meson.build
+++ b/plugins/meson.build
@@ -2,6 +2,7 @@ plugin_dir = join_paths(get_option('libdir'), 'gs-plugins-' + gs_plugin_api_vers
 plugin_libs = [
   appstream_glib,
   gio_unix,
+  goa,
   gtk,
   json_glib,
   libsoup
diff --git a/plugins/snap/gs-plugin-snap.c b/plugins/snap/gs-plugin-snap.c
index 85b616a4..0ba51385 100644
--- a/plugins/snap/gs-plugin-snap.c
+++ b/plugins/snap/gs-plugin-snap.c
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
- * Copyright (C) 2015-2016 Canonical Ltd
+ * Copyright (C) 2015-2018 Canonical Ltd
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -54,6 +54,9 @@ get_client (GsPlugin *plugin, GError **error)
        return g_steal_pointer (&client);
 }
 
+static void
+load_auth (GsPlugin *plugin);
+
 void
 gs_plugin_initialize (GsPlugin *plugin)
 {
@@ -72,10 +75,19 @@ gs_plugin_initialize (GsPlugin *plugin)
        priv->store_snaps = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                   g_free, (GDestroyNotify) g_object_unref);
 
-       priv->auth = gs_auth_new ("snapd");
-       gs_auth_set_provider_name (priv->auth, "Snap Store");
-       gs_auth_set_provider_schema (priv->auth, "com.ubuntu.SnapStore.GnomeSoftware");
-       gs_plugin_add_auth (plugin, priv->auth);
+       priv->auth = gs_auth_new ("snapd", "ubuntusso", &error);
+       if (priv->auth) {
+               gs_auth_set_provider_name (priv->auth, "Snap Store");
+               gs_auth_set_header (priv->auth, _("To continue, you need to use an Ubuntu One account."),
+                                               _("To continue, you need to use your Ubuntu One account."),
+                                               _("To continue, you need to use an Ubuntu One account."));
+               gs_plugin_add_auth (plugin, priv->auth);
+               g_signal_connect_object (priv->auth, "changed",
+                                        G_CALLBACK (load_auth),
+                                        plugin, G_CONNECT_SWAPPED);
+       } else {
+               g_warning ("Failed to instantiate the snapd authentication object: %s", error->message);
+       }
 
        gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "desktop-categories");
        gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_BETTER_THAN, "packagekit");
@@ -116,9 +128,6 @@ snapd_error_convert (GError **perror)
                        g_free (error->message);
                        error->message = g_strdup ("Requires authentication with @snapd");
                        break;
-               case SNAPD_ERROR_TWO_FACTOR_REQUIRED:
-                       error->code = GS_PLUGIN_ERROR_PIN_REQUIRED;
-                       break;
                case SNAPD_ERROR_AUTH_DATA_INVALID:
                case SNAPD_ERROR_TWO_FACTOR_INVALID:
                        error->code = GS_PLUGIN_ERROR_AUTH_INVALID;
@@ -160,32 +169,53 @@ load_auth (GsPlugin *plugin)
 {
        GsPluginData *priv = gs_plugin_get_data (plugin);
        GsAuth *auth;
-       const gchar *serialized_macaroon;
-       g_autoptr(GVariant) macaroon_variant = NULL;
-       const gchar *macaroon;
-       g_auto(GStrv) discharges = NULL;
+       GoaObject *goa_object;
+       GoaPasswordBased *password_based;
+       g_autofree gchar *macaroon = NULL;
+       g_autofree gchar *discharges_str = NULL;
+       g_autoptr(GVariant) discharges_var = NULL;
+       g_autofree const gchar **discharges = NULL;
        g_autoptr(SnapdAuthData) auth_data = NULL;
+       g_autoptr(GError) error = NULL;
 
        auth = gs_plugin_get_auth_by_id (plugin, "snapd");
        if (auth == NULL)
                return;
 
-       serialized_macaroon = gs_auth_get_metadata_item (auth, "macaroon");
-       if (serialized_macaroon == NULL)
+       g_clear_object (&priv->auth_data);
+       goa_object = gs_auth_peek_goa_object (auth);
+       if (goa_object == NULL)
+               return;
+
+       password_based = goa_object_peek_password_based (goa_object);
+       g_return_if_fail (password_based != NULL);
+
+       goa_password_based_call_get_password_sync (password_based,
+                                                  "macaroon",
+                                                  &macaroon,
+                                                  NULL, &error);
+       if (error != NULL) {
+               g_warning ("Failed to get macaroon: %s", error->message);
                return;
+       }
 
-       macaroon_variant = g_variant_parse (G_VARIANT_TYPE ("(sas)"),
-                                           serialized_macaroon,
-                                           NULL,
-                                           NULL,
-                                           NULL);
-       if (macaroon_variant == NULL)
+       goa_password_based_call_get_password_sync (password_based,
+                                                  "discharges",
+                                                  &discharges_str,
+                                                  NULL, &error);
+       if (error != NULL) {
+               g_warning ("Failed to get discharges %s", error->message);
                return;
+       }
+
+       if (discharges_str)
+               discharges_var = g_variant_parse (G_VARIANT_TYPE ("as"),
+                                                 discharges_str,
+                                                 NULL, NULL, NULL);
+       if (discharges_var)
+               discharges = g_variant_get_strv (discharges_var, NULL);
 
-       g_variant_get (macaroon_variant, "(&s^as)", &macaroon, &discharges);
-       g_clear_object (&priv->auth_data);
        priv->auth_data = snapd_auth_data_new (macaroon, discharges);
-       gs_auth_add_flags (priv->auth, GS_AUTH_FLAG_VALID);
 }
 
 gboolean
@@ -208,15 +238,6 @@ gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
                                             _("Snap Store"));
        priv->system_confinement = snapd_system_information_get_confinement (system_information);
 
-       /* load from disk */
-       gs_auth_add_metadata (priv->auth, "macaroon", NULL);
-       if (!gs_auth_store_load (priv->auth,
-                                GS_AUTH_STORE_FLAG_USERNAME |
-                                GS_AUTH_STORE_FLAG_METADATA,
-                                cancellable, error))
-               return FALSE;
-       load_auth (plugin);
-
        /* success */
        return TRUE;
 }
@@ -1042,105 +1063,3 @@ gs_plugin_app_remove (GsPlugin *plugin,
        gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
        return TRUE;
 }
-
-gboolean
-gs_plugin_auth_login (GsPlugin *plugin, GsAuth *auth,
-                     GCancellable *cancellable, GError **error)
-{
-       GsPluginData *priv = gs_plugin_get_data (plugin);
-       g_autoptr(SnapdClient) client = NULL;
-       g_autoptr(SnapdUserInformation) user_information = NULL;
-       g_autoptr(GVariant) macaroon_variant = NULL;
-       g_autofree gchar *serialized_macaroon = NULL;
-
-       if (auth != priv->auth)
-               return TRUE;
-
-       g_clear_object (&priv->auth_data);
-
-       client = get_client (plugin, error);
-       if (client == NULL)
-               return FALSE;
-
-       user_information = snapd_client_login2_sync (client, gs_auth_get_username (auth), 
gs_auth_get_password (auth), gs_auth_get_pin (auth), NULL, error);
-       if (user_information == NULL) {
-               snapd_error_convert (error);
-               return FALSE;
-       }
-
-       priv->auth_data = g_object_ref (snapd_user_information_get_auth_data (user_information));
-
-       macaroon_variant = g_variant_new ("(s^as)",
-                                         snapd_auth_data_get_macaroon (priv->auth_data),
-                                         snapd_auth_data_get_discharges (priv->auth_data));
-       serialized_macaroon = g_variant_print (macaroon_variant, FALSE);
-       gs_auth_add_metadata (auth, "macaroon", serialized_macaroon);
-
-       /* store */
-       if (!gs_auth_store_save (auth,
-                                GS_AUTH_STORE_FLAG_USERNAME |
-                                GS_AUTH_STORE_FLAG_METADATA,
-                                cancellable, error))
-               return FALSE;
-
-       gs_auth_add_flags (priv->auth, GS_AUTH_FLAG_VALID);
-
-       return TRUE;
-}
-
-gboolean
-gs_plugin_auth_logout (GsPlugin *plugin, GsAuth *auth,
-                      GCancellable *cancellable, GError **error)
-{
-       GsPluginData *priv = gs_plugin_get_data (plugin);
-
-       if (auth != priv->auth)
-               return TRUE;
-
-       /* clear */
-       if (!gs_auth_store_clear (auth,
-                                 GS_AUTH_STORE_FLAG_USERNAME |
-                                 GS_AUTH_STORE_FLAG_METADATA,
-                                 cancellable, error))
-               return FALSE;
-
-       g_clear_object (&priv->auth_data);
-       gs_auth_set_flags (priv->auth, 0);
-       return TRUE;
-}
-
-gboolean
-gs_plugin_auth_lost_password (GsPlugin *plugin, GsAuth *auth,
-                             GCancellable *cancellable, GError **error)
-{
-       GsPluginData *priv = gs_plugin_get_data (plugin);
-
-       if (auth != priv->auth)
-               return TRUE;
-
-       // FIXME: snapd might not be using Ubuntu One accounts
-       // https://bugs.launchpad.net/bugs/1598667
-       g_set_error_literal (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_AUTH_INVALID,
-                            "do online using @https://login.ubuntu.com/+forgot_password";);
-       return FALSE;
-}
-
-gboolean
-gs_plugin_auth_register (GsPlugin *plugin, GsAuth *auth,
-                        GCancellable *cancellable, GError **error)
-{
-       GsPluginData *priv = gs_plugin_get_data (plugin);
-
-       if (auth != priv->auth)
-               return TRUE;
-
-       // FIXME: snapd might not be using Ubuntu One accounts
-       // https://bugs.launchpad.net/bugs/1598667
-       g_set_error_literal (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_AUTH_INVALID,
-                            "do online using @https://login.ubuntu.com/+login";);
-       return FALSE;
-}
diff --git a/src/gs-auth-dialog.c b/src/gs-auth-dialog.c
index 0b90fa81..6716b7c3 100644
--- a/src/gs-auth-dialog.c
+++ b/src/gs-auth-dialog.c
@@ -2,6 +2,7 @@
  *
  * Copyright (C) 2016 Richard Hughes <richard hughsie com>
  * Copyright (C) 2017 Kalev Lember <klember redhat com>
+ * Copyright (C) 2018 Canonical Ltd
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -23,272 +24,355 @@
 #include "config.h"
 
 #include <glib/gi18n.h>
+#define GOA_API_IS_SUBJECT_TO_CHANGE
+#include <goa/goa.h>
 
 #include "gs-auth-dialog.h"
 #include "gs-common.h"
 
 struct _GsAuthDialog
 {
-       GtkDialog        parent_instance;
-
-       GCancellable    *cancellable;
-       GsPluginLoader  *plugin_loader;
-       GsApp           *app;
-       GsAuth          *auth;
-       GtkWidget       *box_dialog;
-       GtkWidget       *box_error;
-       GtkWidget       *button_cancel;
-       GtkWidget       *button_continue;
-       GtkWidget       *checkbutton_remember;
-       GtkWidget       *entry_password;
-       GtkWidget       *entry_pin;
-       GtkWidget       *entry_username;
-       GtkWidget       *image_vendor;
-       GtkWidget       *label_error;
-       GtkWidget       *label_title;
-       GtkWidget       *radiobutton_already;
-       GtkWidget       *radiobutton_lost_pwd;
-       GtkWidget       *radiobutton_register;
-       GtkWidget       *stack;
+       GtkDialog parent_instance;
+
+       GoaClient *goa_client;
+       GtkListStore *liststore_account;
+
+       GtkWidget *label_header;
+       GtkWidget *combobox_account;
+       GtkWidget *label_account;
+       GtkWidget *button_add_another;
+       GtkWidget *button_cancel;
+       GtkWidget *button_continue;
+
+       gboolean dispose_on_new_account;
+
+       GCancellable *cancellable;
+       GsPluginLoader *plugin_loader;
+       GsApp *app;
+       GsAuth *auth;
 };
 
-G_DEFINE_TYPE (GsAuthDialog, gs_auth_dialog, GTK_TYPE_DIALOG)
+static void gs_auth_dialog_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GsAuthDialog, gs_auth_dialog, GTK_TYPE_DIALOG,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gs_auth_dialog_initable_iface_init))
+
+enum {
+       COLUMN_ID,
+       COLUMN_EMAIL,
+       COLUMN_ACCOUNT,
+       N_COLUMNS
+};
+
+static gboolean
+gs_auth_dialog_ignore_account (GsAuthDialog *self, GoaAccount *account)
+{
+       return g_strcmp0 (goa_account_get_provider_type (account),
+                         gs_auth_get_provider_type (self->auth)) != 0;
+}
 
 static void
-gs_auth_dialog_check_ui (GsAuthDialog *dialog)
+gs_auth_dialog_set_header (GsAuthDialog *self,
+                          const gchar *text)
 {
-       g_autofree gchar *title = NULL;
-       const gchar *tmp;
-       const gchar *username = gtk_entry_get_text (GTK_ENTRY (dialog->entry_username));
-       const gchar *password = gtk_entry_get_text (GTK_ENTRY (dialog->entry_password));
-
-       /* set the header */
-       tmp = gs_auth_get_provider_name (dialog->auth);
-       if (tmp == NULL) {
-               /* TRANSLATORS: this is when the service name is not known */
-               title = g_strdup (_("To continue you need to sign in."));
-               gtk_label_set_label (GTK_LABEL (dialog->label_title), title);
-       } else {
-               /* TRANSLATORS: the %s is a service name, e.g. "Ubuntu One" */
-               title = g_strdup_printf (_("To continue you need to sign in to %s."), tmp);
-               gtk_label_set_label (GTK_LABEL (dialog->label_title), title);
-       }
+       g_autofree gchar *markup = NULL;
+       markup = g_strdup_printf ("<span size='larger' weight='bold'>%s</span>", text);
+       gtk_label_set_markup (GTK_LABEL (self->label_header), markup);
+}
 
-       /* set the vendor image */
-       tmp = gs_auth_get_provider_logo (dialog->auth);
-       if (tmp == NULL) {
-               gtk_widget_hide (dialog->image_vendor);
-       } else {
-               gtk_image_set_from_file (GTK_IMAGE (dialog->image_vendor), tmp);
-               gtk_widget_show (dialog->image_vendor);
+static gint
+gs_auth_dialog_get_naccounts (GsAuthDialog *self)
+{
+       return gtk_tree_model_iter_n_children (GTK_TREE_MODEL (self->liststore_account), NULL);
+}
+
+static gboolean
+gs_auth_dialog_get_nth_account_data (GsAuthDialog *self,
+                                    gint n,
+                                    ...)
+{
+       GtkTreeIter iter;
+       va_list var_args;
+
+       if (!gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (self->liststore_account), &iter, NULL, n))
+               return FALSE;
+
+       va_start (var_args, n);
+       gtk_tree_model_get_valist (GTK_TREE_MODEL (self->liststore_account), &iter, var_args);
+       va_end (var_args);
+
+       return TRUE;
+}
+
+static gboolean
+gs_auth_dialog_get_account_iter (GsAuthDialog *self,
+                                GoaAccount *account,
+                                GtkTreeIter *iter)
+{
+       gboolean valid;
+
+       valid = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (self->liststore_account), iter, NULL, 0);
+
+       while (valid) {
+               g_autofree gchar *id;
+               gtk_tree_model_get (GTK_TREE_MODEL (self->liststore_account), iter, COLUMN_ID, &id, -1);
+               if (g_strcmp0 (id, goa_account_get_id (account)) == 0)
+                       return TRUE;
+               else
+                       valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (self->liststore_account), iter);
        }
 
-       /* need username and password to continue for known account */
-       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radiobutton_already))) {
-               gtk_widget_set_sensitive (dialog->button_continue,
-                                         username[0] != '\0' && password[0] != '\0');
-               gtk_widget_set_sensitive (dialog->checkbutton_remember, TRUE);
+       return FALSE;
+}
+
+
+static void
+gs_auth_dialog_check_ui (GsAuthDialog *self,
+                        gboolean select)
+{
+       gint naccounts = gs_auth_dialog_get_naccounts (self);
+
+       gs_auth_dialog_set_header (self, gs_auth_get_header (self->auth, naccounts));
+
+       if (naccounts == 0) {
+               gtk_widget_set_visible (self->combobox_account, FALSE);
+               gtk_widget_set_visible (self->label_account, FALSE);
+               gtk_widget_set_visible (self->button_add_another, FALSE);
+               gtk_button_set_label (GTK_BUTTON (self->button_continue), _("Sign In / Register…"));
+       } else if (naccounts == 1) {
+               g_autofree gchar *email = NULL;
+
+               gtk_widget_set_visible (self->combobox_account, FALSE);
+               gtk_widget_set_visible (self->label_account, TRUE);
+               gtk_widget_set_visible (self->button_add_another, TRUE);
+               gtk_button_set_label (GTK_BUTTON (self->button_continue), _("Continue"));
+               gs_auth_dialog_get_nth_account_data (self, 0, COLUMN_EMAIL, &email, -1);
+               gtk_label_set_text (GTK_LABEL (self->label_account), email);
        } else {
-               gtk_entry_set_text (GTK_ENTRY (dialog->entry_password), "");
-               gtk_widget_set_sensitive (dialog->button_continue,
-                                         username[0] != '\0');
-               gtk_widget_set_sensitive (dialog->checkbutton_remember, FALSE);
+               gtk_widget_set_visible (self->combobox_account, TRUE);
+               gtk_widget_set_visible (self->label_account, FALSE);
+               gtk_widget_set_visible (self->button_add_another, TRUE);
+               gtk_button_set_label (GTK_BUTTON (self->button_continue), _("Use"));
+
+               if (select)
+                       gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox_account), naccounts - 1);
+               else if (gtk_combo_box_get_active (GTK_COMBO_BOX (self->combobox_account)) == -1)
+                       gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox_account), 0);
        }
 }
 
 static void
-gs_auth_dialog_cancel_button_cb (GtkWidget *widget, GsAuthDialog *dialog)
+gs_auth_dialog_add_account (GsAuthDialog *self,
+                           GoaAccount *account,
+                           gboolean select)
 {
-       gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
+       GtkTreeIter iter;
+
+       if (gs_auth_dialog_ignore_account (self, account) ||
+           gs_auth_dialog_get_account_iter (self, account, &iter))
+               return;
+
+       gtk_list_store_append (self->liststore_account, &iter);
+       gtk_list_store_set (self->liststore_account, &iter,
+                           COLUMN_ID, goa_account_get_id (account),
+                           COLUMN_EMAIL, goa_account_get_presentation_identity (account),
+                           COLUMN_ACCOUNT, account,
+                           -1);
+
+       gs_auth_dialog_check_ui (self, select);
 }
 
 static void
-gs_auth_dialog_authenticate_cb (GObject *source,
-                               GAsyncResult *res,
-                               gpointer user_data)
+gs_auth_dialog_remove_account (GsAuthDialog *self,
+                              GoaAccount *account)
 {
-       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
-       GsAuthDialog *dialog = GS_AUTH_DIALOG (user_data);
-       g_autoptr(GError) error = NULL;
+       GtkTreeIter iter;
 
-       gtk_widget_set_sensitive (dialog->box_dialog, TRUE);
-       gtk_widget_set_sensitive (dialog->button_continue, TRUE);
-
-       gtk_widget_set_visible (dialog->box_error, FALSE);
-
-       /* we failed */
-       if (!gs_plugin_loader_job_action_finish (plugin_loader, res, &error)) {
-               const gchar *url;
-
-               if (g_error_matches (error,
-                                    GS_PLUGIN_ERROR,
-                                    GS_PLUGIN_ERROR_PIN_REQUIRED)) {
-                       gtk_stack_set_visible_child_name (GTK_STACK (dialog->stack), "2fa");
-                       gtk_widget_grab_focus (dialog->entry_pin);
-                       return;
-               }
-
-               /* have we been given a link */
-               url = gs_utils_get_error_value (error);
-               if (url != NULL) {
-                       g_autoptr(GError) error_local = NULL;
-                       g_debug ("showing link in: %s", error->message);
-                       if (!gtk_show_uri_on_window (GTK_WINDOW (dialog),
-                                                    url,
-                                                    GDK_CURRENT_TIME,
-                                                    &error_local)) {
-                               g_warning ("failed to show URI %s: %s",
-                                          url, error_local->message);
-                       }
-                       return;
-               }
-
-               g_warning ("failed to authenticate: %s", error->message);
-               gtk_label_set_label (GTK_LABEL (dialog->label_error), error->message);
-               gtk_widget_set_visible (dialog->box_error, TRUE);
+       if (gs_auth_dialog_ignore_account (self, account) ||
+           !gs_auth_dialog_get_account_iter (self, account, &iter))
                return;
+
+
+       gtk_list_store_remove (self->liststore_account, &iter);
+       gs_auth_dialog_check_ui (self, FALSE);
+}
+
+static void
+gs_auth_dialog_setup_model (GsAuthDialog *self)
+{
+       g_autoptr(GList) accounts = goa_client_get_accounts (self->goa_client);
+
+       for (GList *l = accounts; l != NULL; l = l->next) {
+               gs_auth_dialog_add_account (self,  goa_object_peek_account (l->data), FALSE);
+               g_object_unref (l->data);
        }
+}
 
-       /* we didn't get authenticated */
-       if (!gs_auth_has_flag (dialog->auth, GS_AUTH_FLAG_VALID)) {
-               return;
+static GVariant*
+gs_auth_dialog_build_dbus_parameters (const gchar *action,
+                                     const gchar *arg)
+{
+       GVariantBuilder builder;
+       GVariant *array[1], *params2[3];
+
+       g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
+
+       if (!action && !arg) {
+               g_variant_builder_add (&builder, "v", g_variant_new_string (""));
+       } else {
+               if (action)
+                       g_variant_builder_add (&builder, "v", g_variant_new_string (action));
+
+               if (arg)
+                       g_variant_builder_add (&builder, "v", g_variant_new_string (arg));
        }
 
-       /* success */
-       gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+       array[0] = g_variant_new ("v", g_variant_new ("(sav)", "online-accounts", &builder));
+
+       params2[0] = g_variant_new_string ("launch-panel");
+       params2[1] = g_variant_new_array (G_VARIANT_TYPE ("v"), array, 1);
+       params2[2] = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
+
+       return g_variant_new_tuple (params2, 3);
 }
 
 static void
-gs_auth_dialog_continue_cb (GtkWidget *widget, GsAuthDialog *dialog)
+gs_auth_dialog_spawn_goa_with_args (const gchar *action,
+                                   const gchar *arg)
 {
-       g_autoptr(GsPluginJob) plugin_job = NULL;
-
-       gtk_widget_set_sensitive (dialog->box_dialog, FALSE);
-       gtk_widget_set_sensitive (dialog->button_continue, FALSE);
-
-       /* alternate actions */
-       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radiobutton_lost_pwd))) {
-               plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_LOST_PASSWORD,
-                                                "auth", dialog->auth,
-                                                NULL);
-       } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radiobutton_register))) {
-               plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_REGISTER,
-                                                "auth", dialog->auth,
-                                                NULL);
-       } else {
-               plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_LOGIN,
-                                                "auth", dialog->auth,
-                                                NULL);
+       g_autoptr(GDBusProxy) proxy = NULL;
+
+       proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+                                              G_DBUS_PROXY_FLAGS_NONE,
+                                              NULL,
+                                              "org.gnome.ControlCenter",
+                                              "/org/gnome/ControlCenter",
+                                              "org.gtk.Actions",
+                                              NULL,
+                                              NULL);
+
+       if (!proxy)
+       {
+               g_warning ("Couldn't open Online Accounts panel");
+               return;
        }
-       gs_plugin_loader_job_process_async (dialog->plugin_loader, plugin_job,
-                                           dialog->cancellable,
-                                           gs_auth_dialog_authenticate_cb,
-                                           dialog);
+
+       g_dbus_proxy_call_sync (proxy,
+                               "Activate",
+                               gs_auth_dialog_build_dbus_parameters (action, arg),
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1,
+                               NULL,
+                               NULL);
 }
 
 static void
-gs_auth_dialog_setup (GsAuthDialog *dialog)
+gs_auth_dialog_ensure_crendentials_cb (GObject *source_object,
+                                      GAsyncResult *res,
+                                      gpointer user_data)
 {
+       GsAuthDialog *self = (GsAuthDialog*) user_data;
+       GoaAccount *account = GOA_ACCOUNT (source_object);
+       g_autoptr(GError) error = NULL;
 
-       /* update widgets with known values */
-       if (gs_auth_get_username (dialog->auth) != NULL) {
-               gtk_entry_set_text (GTK_ENTRY (dialog->entry_username),
-                                   gs_auth_get_username (dialog->auth));
-       }
-       if (gs_auth_get_password (dialog->auth) != NULL) {
-               gtk_entry_set_text (GTK_ENTRY (dialog->entry_password),
-                                   gs_auth_get_password (dialog->auth));
-       }
+       if (!goa_account_call_ensure_credentials_finish (account, NULL, res, &error)) {
+               gs_auth_dialog_spawn_goa_with_args (goa_account_get_id (account), NULL);
+       } else {
+               GoaObject *goa_object;
 
-       /* refresh UI */
-       gs_auth_dialog_check_ui (dialog);
+               goa_object = goa_client_lookup_by_id (self->goa_client,
+                                                     goa_account_get_id (account));
+
+               gs_auth_set_goa_object (self->auth, goa_object);
+               gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_OK);
+       }
 }
 
 static void
-gs_auth_dialog_notify_username_cb (GtkEntry *entry,
-                                  GParamSpec *pspec,
-                                  GsAuthDialog *dialog)
+gs_auth_dialog_response_if_valid (GsAuthDialog *self,
+                                 GoaAccount *account)
 {
-       gs_auth_set_username (dialog->auth, gtk_entry_get_text (entry));
-       gs_auth_dialog_check_ui (dialog);
+       goa_account_call_ensure_credentials (account,
+                                            self->cancellable,
+                                            gs_auth_dialog_ensure_crendentials_cb,
+                                            self);
 }
 
 static void
-gs_auth_dialog_notify_password_cb (GtkEntry *entry,
-                                  GParamSpec *pspec,
-                                  GsAuthDialog *dialog)
+gs_auth_dialog_account_added_cb (GoaClient *client,
+                                GoaObject *object,
+                                GsAuthDialog *self)
 {
-       gs_auth_set_password (dialog->auth, gtk_entry_get_text (entry));
-       gs_auth_dialog_check_ui (dialog);
+       GoaAccount *account = goa_object_peek_account (object);
+
+       if (gs_auth_dialog_ignore_account (self, account))
+               return;
+
+       if (!self->dispose_on_new_account)
+               gs_auth_dialog_add_account (self, account, FALSE);
+       else
+               gs_auth_dialog_response_if_valid (self, account);
 }
 
 static void
-gs_auth_dialog_notify_pin_cb (GtkEntry *entry,
-                             GParamSpec *pspec,
-                             GsAuthDialog *dialog)
+gs_auth_dialog_account_removed_cb (GoaClient *client,
+                                  GoaObject *object,
+                                  GsAuthDialog *self)
 {
-       gs_auth_set_pin (dialog->auth, gtk_entry_get_text (entry));
-       gs_auth_dialog_check_ui (dialog);
+       GoaAccount *account = goa_object_peek_account (object);
+       gs_auth_dialog_remove_account (self, account);
 }
 
 static void
-gs_auth_dialog_toggled_cb (GtkToggleButton *togglebutton, GsAuthDialog *dialog)
+gs_auth_dialog_button_add_another_cb (GtkButton *button,
+                                     GsAuthDialog *self)
 {
-       gs_auth_dialog_check_ui (dialog);
+       gs_auth_dialog_spawn_goa_with_args ("add", gs_auth_get_provider_type (self->auth));
+       self->dispose_on_new_account = TRUE;
 }
 
 static void
-gs_auth_dialog_remember_cb (GtkToggleButton *togglebutton, GsAuthDialog *dialog)
+gs_auth_dialog_button_cancel_cb (GtkButton *button,
+                                GsAuthDialog *self)
 {
-       if (gtk_toggle_button_get_active (togglebutton))
-               gs_auth_add_flags (dialog->auth, GS_AUTH_FLAG_REMEMBER);
-       gs_auth_dialog_check_ui (dialog);
+       gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_CANCEL);
 }
 
 static void
-gs_auth_dialog_dispose (GObject *object)
+gs_auth_dialog_button_continue_cb (GtkButton *button,
+                                  GsAuthDialog *self)
 {
-       GsAuthDialog *dialog = GS_AUTH_DIALOG (object);
+       GoaAccount *account = NULL;
+       gint naccounts = gs_auth_dialog_get_naccounts (self);
 
-       g_clear_object (&dialog->plugin_loader);
-       g_clear_object (&dialog->app);
-       g_clear_object (&dialog->auth);
+       if (naccounts == 1) {
+               gs_auth_dialog_get_nth_account_data (self, 0, COLUMN_ACCOUNT, &account, -1);
+       } else {
+               gint active = gtk_combo_box_get_active (GTK_COMBO_BOX (self->combobox_account));
+               gs_auth_dialog_get_nth_account_data (self, active, COLUMN_ACCOUNT, &account, -1);
+       }
 
-       g_cancellable_cancel (dialog->cancellable);
-       g_clear_object (&dialog->cancellable);
+       if (account == NULL)
+               gs_auth_dialog_button_add_another_cb (GTK_BUTTON (self->button_add_another), self);
+       else
+               gs_auth_dialog_response_if_valid (self, account);
 
-       G_OBJECT_CLASS (gs_auth_dialog_parent_class)->dispose (object);
+       g_clear_object (&account);
 }
 
+/* GObject */
+
 static void
-gs_auth_dialog_init (GsAuthDialog *dialog)
+gs_auth_dialog_dispose (GObject *object)
 {
-       gtk_widget_init_template (GTK_WIDGET (dialog));
-
-       dialog->cancellable = g_cancellable_new ();
-
-       g_signal_connect (dialog->entry_username, "notify::text",
-                         G_CALLBACK (gs_auth_dialog_notify_username_cb), dialog);
-       g_signal_connect (dialog->entry_password, "notify::text",
-                         G_CALLBACK (gs_auth_dialog_notify_password_cb), dialog);
-       g_signal_connect (dialog->entry_password, "activate",
-                         G_CALLBACK (gs_auth_dialog_continue_cb), dialog);
-       g_signal_connect (dialog->entry_pin, "notify::text",
-                         G_CALLBACK (gs_auth_dialog_notify_pin_cb), dialog);
-       g_signal_connect (dialog->entry_pin, "activate",
-                         G_CALLBACK (gs_auth_dialog_continue_cb), dialog);
-       g_signal_connect (dialog->checkbutton_remember, "toggled",
-                         G_CALLBACK (gs_auth_dialog_remember_cb), dialog);
-       g_signal_connect (dialog->radiobutton_already, "toggled",
-                         G_CALLBACK (gs_auth_dialog_toggled_cb), dialog);
-       g_signal_connect (dialog->radiobutton_register, "toggled",
-                         G_CALLBACK (gs_auth_dialog_toggled_cb), dialog);
-       g_signal_connect (dialog->radiobutton_lost_pwd, "toggled",
-                         G_CALLBACK (gs_auth_dialog_toggled_cb), dialog);
-       g_signal_connect (dialog->button_cancel, "clicked",
-                         G_CALLBACK (gs_auth_dialog_cancel_button_cb), dialog);
-       g_signal_connect (dialog->button_continue, "clicked",
-                         G_CALLBACK (gs_auth_dialog_continue_cb), dialog);
+       GsAuthDialog *self = GS_AUTH_DIALOG (object);
+
+       g_clear_object (&self->goa_client);
+
+       g_cancellable_cancel (self->cancellable);
+       g_clear_object (&self->cancellable);
+
+       G_OBJECT_CLASS (gs_auth_dialog_parent_class)->dispose (object);
 }
 
 static void
@@ -301,34 +385,72 @@ gs_auth_dialog_class_init (GsAuthDialogClass *klass)
 
        gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-auth-dialog.ui");
 
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, box_dialog);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, box_error);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, label_header);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, combobox_account);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, label_account);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, button_add_another);
        gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, button_cancel);
        gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, button_continue);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, checkbutton_remember);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, entry_password);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, entry_pin);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, entry_username);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, image_vendor);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, label_error);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, label_title);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, radiobutton_already);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, radiobutton_lost_pwd);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, radiobutton_register);
-       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, stack);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, liststore_account);
+
+
+       gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), 
gs_auth_dialog_button_add_another_cb);
+       gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), gs_auth_dialog_button_cancel_cb);
+       gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), gs_auth_dialog_button_continue_cb);
+}
+
+static void
+gs_auth_dialog_init (GsAuthDialog *self)
+{
+       self->cancellable = g_cancellable_new ();
+
+       gtk_widget_init_template (GTK_WIDGET (self));
+       gtk_widget_grab_focus (self->button_continue);
 }
 
+/* GInitable */
+
+static gboolean
+gs_auth_dialog_initable_init (GInitable *initable,
+                             GCancellable *cancellable,
+                             GError  **error)
+{
+       GsAuthDialog *self;
+
+       g_return_val_if_fail (GS_IS_AUTH_DIALOG (initable), FALSE);
+
+       self = GS_AUTH_DIALOG (initable);
+
+       self->goa_client = goa_client_new_sync (NULL, error);
+       if (!self->goa_client)
+               return FALSE;
+
+       /* Be ready to other accounts */
+       g_signal_connect (self->goa_client, "account-added", G_CALLBACK (gs_auth_dialog_account_added_cb), 
self);
+       g_signal_connect (self->goa_client, "account-removed", G_CALLBACK 
(gs_auth_dialog_account_removed_cb), self);
+
+       return TRUE;
+}
+
+static void
+gs_auth_dialog_initable_iface_init (GInitableIface *iface)
+{
+       iface->init = gs_auth_dialog_initable_init;
+}
+
+/* Public API */
+
 GtkWidget *
 gs_auth_dialog_new (GsPluginLoader *plugin_loader,
                    GsApp *app,
-                   const gchar *provider_id,
+                   const gchar *auth_id,
                    GError **error)
 {
        GsAuthDialog *dialog;
        GsAuth *auth;
 
        /* get the authentication provider */
-       if (provider_id == NULL) {
+       if (auth_id == NULL) {
                g_set_error (error,
                             GS_PLUGIN_ERROR,
                             GS_PLUGIN_ERROR_FAILED,
@@ -336,25 +458,32 @@ gs_auth_dialog_new (GsPluginLoader *plugin_loader,
                             app != NULL ? gs_app_get_id (app) : NULL);
                return NULL;
        }
-       auth = gs_plugin_loader_get_auth_by_id (plugin_loader, provider_id);
+       auth = gs_plugin_loader_get_auth_by_id (plugin_loader, auth_id);
        if (auth == NULL) {
                g_set_error (error,
                             GS_PLUGIN_ERROR,
                             GS_PLUGIN_ERROR_NOT_SUPPORTED,
                             "no auth-provider %s for %s",
-                            provider_id,
+                            auth_id,
                             app != NULL ? gs_app_get_id (app) : NULL);
                return NULL;
        }
 
        /* create dialog */
-       dialog = g_object_new (GS_TYPE_AUTH_DIALOG,
-                              "use-header-bar", TRUE,
-                              NULL);
+       dialog = g_initable_new (GS_TYPE_AUTH_DIALOG,
+                                NULL, error,
+                                "use-header-bar", FALSE,
+                                NULL);
+
+       if (dialog == NULL)
+               return NULL;
+
        dialog->plugin_loader = g_object_ref (plugin_loader);
        dialog->app = app != NULL ? g_object_ref (app) : NULL;
        dialog->auth = g_object_ref (auth);
-       gs_auth_dialog_setup (dialog);
+
+       gs_auth_dialog_setup_model (dialog);
+       gs_auth_dialog_check_ui (dialog, FALSE);
 
        return GTK_WIDGET (dialog);
 }
diff --git a/src/gs-auth-dialog.h b/src/gs-auth-dialog.h
index 721a307e..63b7877b 100644
--- a/src/gs-auth-dialog.h
+++ b/src/gs-auth-dialog.h
@@ -32,10 +32,10 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (GsAuthDialog, gs_auth_dialog, GS, AUTH_DIALOG, GtkDialog)
 
-GtkWidget      *gs_auth_dialog_new             (GsPluginLoader *plugin_loader,
-                                                GsApp          *app,
-                                                const gchar    *provider_id,
-                                                GError         **error);
+GtkWidget      *gs_auth_dialog_new     (GsPluginLoader *plugin_loader,
+                                        GsApp          *app,
+                                        const gchar    *auth_id,
+                                        GError         **error);
 
 G_END_DECLS
 
diff --git a/src/gs-auth-dialog.ui b/src/gs-auth-dialog.ui
index aec7b247..f96d0461 100644
--- a/src/gs-auth-dialog.ui
+++ b/src/gs-auth-dialog.ui
@@ -1,317 +1,164 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.20.0 -->
+<!-- Generated with glade 3.22.1 -->
 <interface>
   <requires lib="gtk+" version="3.10"/>
+  <object class="GtkListStore" id="liststore_account">
+    <columns>
+      <!-- column-name Id -->
+      <column type="gchararray"/>
+      <!-- column-name Email -->
+      <column type="gchararray"/>
+      <!-- column-name Account -->
+      <column type="GObject"/>
+    </columns>
+  </object>
   <template class="GsAuthDialog" parent="GtkDialog">
     <property name="resizable">False</property>
-    <property name="modal">True</property>
-    <property name="destroy_with_parent">True</property>
     <property name="type_hint">dialog</property>
-    <property name="deletable">False</property>
+    <child>
+      <placeholder/>
+    </child>
     <child internal-child="vbox">
-      <object class="GtkBox" id="box_dialog">
+      <object class="GtkBox">
+        <property name="border_width">6</property>
         <property name="orientation">vertical</property>
         <property name="spacing">2</property>
         <child internal-child="action_area">
           <object class="GtkButtonBox">
-            <property name="layout_style">end</property>
             <child>
-              <placeholder/>
+              <object class="GtkButton" id="button_add_another">
+                <property name="label" translatable="yes">Add another…</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <signal name="clicked" handler="gs_auth_dialog_button_add_another_cb" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="secondary">True</property>
+                <property name="non_homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button_cancel">
+                <property name="label" translatable="yes">Cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <signal name="clicked" handler="gs_auth_dialog_button_cancel_cb" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="non_homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button_continue">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <signal name="clicked" handler="gs_auth_dialog_button_continue_cb" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="non_homogeneous">True</property>
+              </packing>
             </child>
           </object>
+          <packing>
+            <property name="expand">True</property>
+          </packing>
         </child>
         <child>
-          <object class="GtkGrid">
-            <property name="visible">True</property>
-            <property name="border_width">21</property>
-            <property name="row_spacing">9</property>
-            <property name="column_spacing">21</property>
-            <child>
-              <object class="GtkStack" id="stack">
+          <object class="GtkInfoBar" id="error_bar">
+            <property name="no_show_all">True</property>
+            <property name="message_type">error</property>
+            <property name="revealed">False</property>
+            <child internal-child="action_area">
+              <object class="GtkButtonBox">
                 <property name="visible">True</property>
-                <property name="transition_type">crossfade</property>
+                <property name="spacing">6</property>
+                <property name="layout_style">end</property>
                 <child>
-                  <object class="GtkGrid">
-                    <property name="name">intro</property>
-                    <property name="visible">True</property>
-                    <property name="halign">start</property>
-                    <property name="valign">start</property>
-                    <property name="row_spacing">9</property>
-                    <property name="column_spacing">9</property>
-                    <child>
-                      <object class="GtkLabel" id="label_title">
-                        <property name="visible">True</property>
-                        <property name="halign">start</property>
-                        <property name="label">To continue you need an %NAME% account.</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                        <property name="width">2</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="halign">end</property>
-                        <property name="label" translatable="yes">Email address</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkEntry" id="entry_username">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="margin_bottom">15</property>
-                        <property name="input_purpose">email</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkRadioButton" id="radiobutton_already">
-                        <property name="label" translatable="yes">I have an account already</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="halign">start</property>
-                        <property name="active">True</property>
-                        <property name="draw_indicator">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">2</property>
-                        <property name="width">2</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="halign">end</property>
-                        <property name="label" translatable="yes">Password</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">3</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkEntry" id="entry_password">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="input_purpose">password</property>
-                        <property name="visibility">False</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">3</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkRadioButton" id="radiobutton_register">
-                        <property name="label" translatable="yes">I want to register for an account 
now</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="halign">start</property>
-                        <property name="active">True</property>
-                        <property name="draw_indicator">True</property>
-                        <property name="group">radiobutton_already</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">5</property>
-                        <property name="width">2</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkRadioButton" id="radiobutton_lost_pwd">
-                        <property name="label" translatable="yes">I have forgotten my password</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="halign">start</property>
-                        <property name="active">True</property>
-                        <property name="draw_indicator">True</property>
-                        <property name="group">radiobutton_already</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">6</property>
-                        <property name="width">2</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">4</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkCheckButton" id="checkbutton_remember">
-                        <property name="label" translatable="yes">Sign in automatically next time</property>
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="active">True</property>
-                        <property name="draw_indicator">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">4</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="name">login</property>
-                  </packing>
+                  <placeholder/>
                 </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+              </packing>
+            </child>
+            <child internal-child="content_area">
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <property name="spacing">16</property>
                 <child>
-                  <object class="GtkGrid">
-                    <property name="name">2fa</property>
+                  <object class="GtkLabel" id="label_error">
                     <property name="visible">True</property>
-                    <property name="row_spacing">9</property>
-                    <property name="column_spacing">9</property>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="halign">start</property>
-                        <property name="label" translatable="yes">Enter your one-time pin for two-factor 
authentication.</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                        <property name="width">2</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="halign">end</property>
-                        <property name="label" translatable="yes">PIN</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkEntry" id="entry_pin">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="input_purpose">password</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">1</property>
-                      </packing>
-                    </child>
+                    <property name="justify">fill</property>
+                    <property name="wrap">True</property>
+                    <property name="width_chars">0</property>
+                    <property name="max_width_chars">50</property>
                   </object>
-                  <packing>
-                    <property name="name">2fa</property>
-                  </packing>
                 </child>
               </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">0</property>
-              </packing>
             </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="halign">start</property>
+            <property name="border_width">12</property>
+            <property name="spacing">18</property>
             <child>
-              <object class="GtkImage" id="image_vendor">
-                <property name="visible">False</property>
+              <object class="GtkImage">
+                <property name="visible">True</property>
                 <property name="halign">start</property>
                 <property name="valign">start</property>
-                <property name="stock">gtk-floppy</property>
+                <property name="icon_name">org.gnome.Software</property>
                 <property name="icon_size">6</property>
               </object>
-              <packing>
-                <property name="left_attach">0</property>
-                <property name="top_attach">0</property>
-                <property name="height">2</property>
-              </packing>
             </child>
             <child>
-              <object class="GtkBox" id="box_error">
-                <property name="visible">False</property>
-                <property name="spacing">6</property>
+              <object class="GtkBox" id="box_auth">
+                <property name="visible">True</property>
+                <property name="halign">start</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">12</property>
                 <child>
-                  <object class="GtkImage">
+                  <object class="GtkLabel" id="label_header">
+                    <property name="name">label_header</property>
                     <property name="visible">True</property>
-                    <property name="halign">end</property>
+                    <property name="halign">start</property>
                     <property name="valign">start</property>
-                    <property name="icon_name">dialog-warning-symbolic</property>
-                    <property name="use_fallback">True</property>
-                    <property name="icon_size">5</property>
+                    <property name="use_markup">True</property>
+                    <property name="justify">fill</property>
+                    <property name="wrap">True</property>
+                    <property name="max_width_chars">40</property>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="label_error">
-                    <property name="visible">True</property>
+                  <object class="GtkComboBox" id="combobox_account">
+                    <property name="halign">start</property>
+                    <property name="model">liststore_account</property>
+                    <child>
+                      <object class="GtkCellRendererText"/>
+                      <attributes>
+                        <attribute name="text">1</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label_account">
                     <property name="halign">start</property>
-                    <property name="label">The supplied credentials were not correct</property>
-                    <attributes>
-                      <attribute name="weight" value="bold"/>
-                    </attributes>
                   </object>
                 </child>
               </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">1</property>
-              </packing>
             </child>
           </object>
         </child>
       </object>
     </child>
-    <child type="titlebar">
-      <object class="GtkHeaderBar">
-        <property name="visible">True</property>
-        <property name="title" translatable="yes">Authenticate</property>
-        <child>
-          <object class="GtkButton" id="button_cancel">
-            <property name="label">gtk-cancel</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <property name="use_stock">True</property>
-          </object>
-        </child>
-        <child>
-          <object class="GtkButton" id="button_continue">
-            <property name="label" translatable="yes">Continue</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <style>
-              <class name="suggested-action"/>
-            </style>
-          </object>
-          <packing>
-            <property name="pack_type">end</property>
-          </packing>
-        </child>
-      </object>
-    </child>
   </template>
-  <object class="GtkSizeGroup" id="sizegroup_buttons">
-    <widgets>
-      <widget name="button_continue"/>
-      <widget name="button_cancel"/>
-    </widgets>
-  </object>
 </interface>
diff --git a/src/gs-page.c b/src/gs-page.c
index aa5321ec..823ce338 100644
--- a/src/gs-page.c
+++ b/src/gs-page.c
@@ -99,10 +99,10 @@ gs_page_authenticate_cb (GtkDialog *dialog,
 void
 gs_page_authenticate (GsPage *page,
                      GsApp *app,
-                     const gchar *provider_id,
+                     const gchar *auth_id,
                      GCancellable *cancellable,
-                      GsPageAuthCallback callback,
-                      gpointer user_data)
+                     GsPageAuthCallback callback,
+                     gpointer user_data)
 {
        GsPagePrivate *priv = gs_page_get_instance_private (page);
        g_autoptr(GsPageHelper) helper = NULL;
@@ -117,7 +117,7 @@ gs_page_authenticate (GsPage *page,
 
        dialog = gs_auth_dialog_new (priv->plugin_loader,
                                     app,
-                                    provider_id,
+                                    auth_id,
                                     &error);
        if (dialog == NULL) {
                g_warning ("%s", error->message);
diff --git a/src/gs-page.h b/src/gs-page.h
index 539a0b58..874e8cbc 100644
--- a/src/gs-page.h
+++ b/src/gs-page.h
@@ -63,7 +63,7 @@ void           gs_page_set_header_end_widget          (GsPage         *page,
                                                         GtkWidget      *widget);
 void            gs_page_authenticate                   (GsPage                 *page,
                                                         GsApp                  *app,
-                                                        const gchar            *provider_id,
+                                                        const gchar            *auth_id,
                                                         GCancellable           *cancellable,
                                                         GsPageAuthCallback      callback,
                                                         gpointer                user_data);
diff --git a/src/gs-shell.c b/src/gs-shell.c
index 85d66a31..03aeba9c 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -656,86 +656,104 @@ static void
 signin_activated_cb (GSimpleAction *action, GVariant *parameter, GsShell *shell)
 {
        GsShellPrivate *priv = gs_shell_get_instance_private (shell);
-       const gchar *action_name, *provider_id;
+       const gchar *action_name, *auth_id;
        GsAuth *auth;
 
        action_name = g_action_get_name (G_ACTION (action));
        g_return_if_fail (g_str_has_prefix (action_name, "signin-"));
-       provider_id = action_name + strlen ("signin-");
+       auth_id = action_name + strlen ("signin-");
 
-       auth = gs_plugin_loader_get_auth_by_id (priv->plugin_loader, provider_id);
+       auth = gs_plugin_loader_get_auth_by_id (priv->plugin_loader, auth_id);
        g_return_if_fail (auth != NULL);
 
        gs_page_authenticate (priv->page, NULL,
-                             gs_auth_get_provider_id (auth),
+                             gs_auth_get_auth_id (auth),
                              priv->cancellable,
                              NULL, NULL);
 }
 
-static void
-gs_shell_logout_cb (GObject *source,
-                   GAsyncResult *res,
-                   gpointer user_data)
-{
-       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
-       g_autoptr(GError) error = NULL;
-
-       if (!gs_plugin_loader_job_action_finish (plugin_loader, res, &error)) {
-               g_warning ("failed to logout: %s",  error->message);
-               return;
-       }
-}
-
 static void
 signout_activated_cb (GSimpleAction *action, GVariant *parameter, GsShell *shell)
 {
        GsShellPrivate *priv = gs_shell_get_instance_private (shell);
-       const gchar *action_name, *provider_id;
+       const gchar *action_name, *auth_id;
        g_autoptr(GsPluginJob) plugin_job = NULL;
        GsAuth *auth;
 
        action_name = g_action_get_name (G_ACTION (action));
        g_return_if_fail (g_str_has_prefix (action_name, "signout-"));
-       provider_id = action_name + strlen ("signout-");
+       auth_id = action_name + strlen ("signout-");
 
-       auth = gs_plugin_loader_get_auth_by_id (priv->plugin_loader, provider_id);
+       auth = gs_plugin_loader_get_auth_by_id (priv->plugin_loader, auth_id);
        g_return_if_fail (auth != NULL);
 
-       plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_AUTH_LOGOUT,
-                                        "interactive", TRUE,
-                                        "auth", auth,
-                                        NULL);
-
-       gs_plugin_loader_job_process_async (priv->plugin_loader, plugin_job,
-                                           priv->cancellable,
-                                           gs_shell_logout_cb,
-                                           shell);
+       gs_auth_set_goa_object (auth, NULL);
 }
 
 static void
-menu_button_clicked_cb (GtkButton *button, GsShell *shell)
+gs_shell_reload_auth_menus (GsShell *shell)
 {
        GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+       GMenu *accounts_menu;
        GPtrArray *auth_array;
 
+       accounts_menu = G_MENU (gtk_builder_get_object (priv->builder, "accounts_menu"));
+       g_menu_remove_all (accounts_menu);
+
        auth_array = gs_plugin_loader_get_auths (priv->plugin_loader);
        for (guint i = 0; i < auth_array->len; i++) {
                GsAuth *auth = g_ptr_array_index (auth_array, i);
                gboolean logged_in;
                g_autofree gchar *signin_action_name = NULL;
                GSimpleAction *signin_action;
+               g_autofree gchar *signin_target = NULL;
                g_autofree gchar *signout_action_name = NULL;
                GSimpleAction *signout_action;
+               g_autofree gchar *signout_target = NULL;
+               GoaObject *goa_object;
+               g_autofree gchar *signin_label = NULL;
+               g_autofree gchar *signout_label = NULL;
+               g_autoptr(GMenu) auth_menu = NULL;
+               g_autoptr(GMenuItem) signin_item = NULL;
+               g_autoptr(GMenuItem) signout_item = NULL;
+
+
+               goa_object = gs_auth_peek_goa_object (auth);
+               logged_in = goa_object != NULL;
 
-               logged_in = gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID);
+               auth_menu = g_menu_new ();
+               accounts_menu = G_MENU (gtk_builder_get_object (priv->builder, "accounts_menu"));
+               g_menu_append_section (accounts_menu, gs_auth_get_provider_name (auth), G_MENU_MODEL 
(auth_menu));
 
-               signin_action_name = g_strdup_printf ("signin-%s", gs_auth_get_provider_id (auth));
+               signin_action_name = g_strdup_printf ("signin-%s", gs_auth_get_auth_id (auth));
                signin_action = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP 
(priv->auth_actions), signin_action_name));
                g_simple_action_set_enabled (signin_action, !logged_in);
 
-               signout_action_name = g_strdup_printf ("signout-%s", gs_auth_get_provider_id (auth));
+               signout_action_name = g_strdup_printf ("signout-%s", gs_auth_get_auth_id (auth));
                signout_action = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP 
(priv->auth_actions), signout_action_name));
                g_simple_action_set_enabled (signout_action, logged_in);
+
+
+               if (logged_in) {
+                       GoaAccount *goa_account = goa_object_peek_account (goa_object);
+
+                       /* TRANSLATORS: menu item that signs into the named account with a particular 
username */
+                       signin_label = g_strdup_printf (_("Signed in as %s"),
+                                                       goa_account_get_presentation_identity (goa_account));
+               } else {
+                       /* TRANSLATORS: menu item that signs into the named account */
+                       signin_label = g_strdup_printf (_("Sign in…"));
+               }
+
+               signin_target = g_strdup_printf ("auth.%s", signin_action_name);
+               signin_item = g_menu_item_new (signin_label, signin_target);
+               g_menu_append_item (auth_menu, signin_item);
+
+               /* TRANSLATORS: menu item for signing out from the named account */
+               signout_label = g_strdup_printf (_("Sign out"));
+               signout_target = g_strdup_printf ("auth.%s", signout_action_name);
+               signout_item = g_menu_item_new (signout_label, signout_target);
+               g_menu_append_item (auth_menu, signout_item);
        }
 }
 
@@ -1030,7 +1048,6 @@ gs_shell_show_event_refresh (GsShell *shell, GsPluginEvent *event)
                buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
                break;
        case GS_PLUGIN_ERROR_AUTH_REQUIRED:
-       case GS_PLUGIN_ERROR_PIN_REQUIRED:
                /* TRANSLATORS: failure text for the in-app notification */
                g_string_append (str, _("Unable to download updates: "
                                        "authentication was required"));
@@ -1093,7 +1110,6 @@ gs_shell_show_event_purchase (GsShell *shell, GsPluginEvent *event)
        str_app = gs_shell_get_title_from_app (app);
        switch (error->code) {
        case GS_PLUGIN_ERROR_AUTH_REQUIRED:
-       case GS_PLUGIN_ERROR_PIN_REQUIRED:
                /* TRANSLATORS: failure text for the in-app notification,
                 * where the %s is the application name (e.g. "GIMP") */
                g_string_append_printf (str, _("Unable to purchase %s: "
@@ -1208,7 +1224,6 @@ gs_shell_show_event_install (GsShell *shell, GsPluginEvent *event)
                buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
                break;
        case GS_PLUGIN_ERROR_AUTH_REQUIRED:
-       case GS_PLUGIN_ERROR_PIN_REQUIRED:
                /* TRANSLATORS: failure text for the in-app notification */
                g_string_append_printf (str, _("Unable to install %s: "
                                               "authentication was required"),
@@ -1229,35 +1244,6 @@ gs_shell_show_event_install (GsShell *shell, GsPluginEvent *event)
                                               "install software"),
                                        str_app);
                break;
-       case GS_PLUGIN_ERROR_ACCOUNT_SUSPENDED:
-       case GS_PLUGIN_ERROR_ACCOUNT_DEACTIVATED:
-               if (origin != NULL) {
-                       const gchar *url_homepage;
-
-                       /* TRANSLATORS: failure text for the in-app notification,
-                        * the %s is the name of the authentication service,
-                        * e.g. "Ubuntu One" */
-                       g_string_append_printf (str, _("Your %s account has been suspended."),
-                                               gs_app_get_name (origin));
-                       g_string_append (str, " ");
-                       /* TRANSLATORS: failure text for the in-app notification */
-                       g_string_append (str, _("It is not possible to install "
-                                               "software until this has been resolved."));
-                       url_homepage = gs_app_get_url (origin, AS_URL_KIND_HOMEPAGE);
-                       if (url_homepage != NULL) {
-                               g_autofree gchar *url = NULL;
-                               url = g_strdup_printf ("<a href=\"%s\">%s</a>",
-                                                      url_homepage,
-                                                      url_homepage);
-                               /* TRANSLATORS: failure text for the in-app notification,
-                                * where the %s is the clickable link (e.g.
-                                * "http://example.com/what-did-i-do-wrong/";) */
-                               msg = g_strdup_printf (_("For more information, visit %s."),
-                                                       url);
-                               g_string_append_printf (str, " %s", msg);
-                       }
-               }
-               break;
        case GS_PLUGIN_ERROR_AC_POWER_REQUIRED:
                /* TRANSLATORS: failure text for the in-app notification,
                 * where the %s is the application name (e.g. "Dell XPS 13") */
@@ -1342,7 +1328,6 @@ gs_shell_show_event_update (GsShell *shell, GsPluginEvent *event)
                buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
                break;
        case GS_PLUGIN_ERROR_AUTH_REQUIRED:
-       case GS_PLUGIN_ERROR_PIN_REQUIRED:
                /* TRANSLATORS: failure text for the in-app notification,
                 * where the %s is the application name (e.g. "GIMP") */
                g_string_append_printf (str, _("Unable to update %s: "
@@ -1447,7 +1432,6 @@ gs_shell_show_event_upgrade (GsShell *shell, GsPluginEvent *event)
                buttons |= GS_SHELL_EVENT_BUTTON_NO_SPACE;
                break;
        case GS_PLUGIN_ERROR_AUTH_REQUIRED:
-       case GS_PLUGIN_ERROR_PIN_REQUIRED:
                /* TRANSLATORS: failure text for the in-app notification,
                 * where the %s is the distro name (e.g. "Fedora 25") */
                g_string_append_printf (str, _("Unable to upgrade to %s: "
@@ -1519,7 +1503,6 @@ gs_shell_show_event_remove (GsShell *shell, GsPluginEvent *event)
        str_app = gs_shell_get_title_from_app (app);
        switch (error->code) {
        case GS_PLUGIN_ERROR_AUTH_REQUIRED:
-       case GS_PLUGIN_ERROR_PIN_REQUIRED:
                /* TRANSLATORS: failure text for the in-app notification,
                 * where the %s is the application name (e.g. "GIMP") */
                g_string_append_printf (str, _("Unable to remove %s: authentication was required"),
@@ -2021,10 +2004,10 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
                          shell);
 
        /* show the account popover when clicking on the account button */
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "menu_button"));
+       /* widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "menu_button"));
        g_signal_connect (widget, "clicked",
                          G_CALLBACK (menu_button_clicked_cb),
-                         shell);
+                         shell); */
 
        /* setup buttons */
        widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
@@ -2115,58 +2098,25 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
        auth_array = gs_plugin_loader_get_auths (priv->plugin_loader);
        for (guint i = 0; i < auth_array->len; i++) {
                GsAuth *auth = g_ptr_array_index (auth_array, i);
-               GMenu *accounts_menu;
-               gboolean logged_in;
-               g_autoptr(GMenu) auth_menu = NULL;
                g_autoptr(GSimpleAction) signin_action = NULL;
                g_autofree gchar *signin_action_name = NULL;
-               g_autoptr(GMenuItem) signin_item = NULL;
-               g_autofree gchar *signin_label = NULL;
-               g_autofree gchar *signin_target = NULL;
                g_autoptr(GSimpleAction) signout_action = NULL;
                g_autofree gchar *signout_action_name = NULL;
-               g_autoptr(GMenuItem) signout_item = NULL;
-               g_autofree gchar *signout_label = NULL;
-               g_autofree gchar *signout_target = NULL;
-
-               logged_in = gs_auth_has_flag (auth, GS_AUTH_FLAG_VALID);
 
-               signin_action_name = g_strdup_printf ("signin-%s", gs_auth_get_provider_id (auth));
+               signin_action_name = g_strdup_printf ("signin-%s", gs_auth_get_auth_id (auth));
                signin_action = g_simple_action_new (signin_action_name, NULL);
-               g_simple_action_set_enabled (signin_action, !logged_in);
                g_signal_connect (signin_action, "activate", G_CALLBACK (signin_activated_cb), shell);
                g_action_map_add_action (G_ACTION_MAP (priv->auth_actions), G_ACTION (signin_action));
 
-               signout_action_name = g_strdup_printf ("signout-%s", gs_auth_get_provider_id (auth));
+               signout_action_name = g_strdup_printf ("signout-%s", gs_auth_get_auth_id (auth));
                signout_action = g_simple_action_new (signout_action_name, NULL);
-               g_simple_action_set_enabled (signout_action, logged_in);
                g_signal_connect (signout_action, "activate", G_CALLBACK (signout_activated_cb), shell);
                g_action_map_add_action (G_ACTION_MAP (priv->auth_actions), G_ACTION (signout_action));
 
-               auth_menu = g_menu_new ();
-               accounts_menu = G_MENU (gtk_builder_get_object (priv->builder, "accounts_menu"));
-               g_menu_append_section (accounts_menu, NULL, G_MENU_MODEL (auth_menu));
-
-               if (logged_in) {
-                       /* TRANSLATORS: menu item that signs into the named account with a particular 
username */
-                       signin_label = g_strdup_printf (_("Signed in into %s as %s"),
-                                                       gs_auth_get_provider_name (auth),
-                                                       gs_auth_get_username (auth));
-               } else {
-                       /* TRANSLATORS: menu item that signs into the named account */
-                       signin_label = g_strdup_printf (_("Sign in to %s…"),
-                                                       gs_auth_get_provider_name (auth));
-               }
-               signin_target = g_strdup_printf ("auth.%s", signin_action_name);
-               signin_item = g_menu_item_new (signin_label, signin_target);
-               g_menu_append_item (auth_menu, signin_item);
-
-               /* TRANSLATORS: menu item for signing out from the named account */
-               signout_label = g_strdup_printf (_("Sign out from %s"),
-                                                gs_auth_get_provider_name (auth));
-               signout_target = g_strdup_printf ("auth.%s", signout_action_name);
-               signout_item = g_menu_item_new (signout_label, signout_target);
-               g_menu_append_item (auth_menu, signout_item);
+               g_signal_connect_object (auth, "changed",
+                                        G_CALLBACK (gs_shell_reload_auth_menus),
+                                        shell, G_CONNECT_SWAPPED);
+               gs_shell_reload_auth_menus (shell);
        }
 
        /* show loading page, which triggers the initial refresh */
diff --git a/src/meson.build b/src/meson.build
index ebcaaa98..aafc9b7a 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -74,10 +74,10 @@ gnome_software_dependencies = [
   appstream_glib,
   gio_unix,
   gmodule,
+  goa,
   gtk,
   json_glib,
   libm,
-  libsecret,
   libsoup
 ]
 
@@ -296,10 +296,10 @@ if get_option('tests')
       appstream_glib,
       gio_unix,
       gmodule,
+      goa,
       gtk,
       json_glib,
       libm,
-      libsecret,
       libsoup,
     ],
     link_with : [


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]