diff --git a/include/NetworkManager.h b/include/NetworkManager.h
index 9df444f..d374b96 100644
--- a/include/NetworkManager.h
+++ b/include/NetworkManager.h
@@ -48,6 +48,7 @@
 #define NM_DBUS_SERVICE_USER_SETTINGS     "org.freedesktop.NetworkManagerUserSettings"
 #define NM_DBUS_SERVICE_SYSTEM_SETTINGS   "org.freedesktop.NetworkManagerSystemSettings"
 #define NM_DBUS_IFACE_SETTINGS            "org.freedesktop.NetworkManagerSettings"
+#define NM_DBUS_IFACE_SETTINGS_SECRETS    "org.freedesktop.NetworkManagerSettings.Secrets"
 #define NM_DBUS_IFACE_SETTINGS_SYSTEM     "org.freedesktop.NetworkManagerSettings.System"
 #define NM_DBUS_PATH_SETTINGS             "/org/freedesktop/NetworkManagerSettings"
 
diff --git a/introspection/nm-settings.xml b/introspection/nm-settings.xml
index b252c00..f198bad 100644
--- a/introspection/nm-settings.xml
+++ b/introspection/nm-settings.xml
@@ -43,5 +43,54 @@
     </signal>
 
   </interface>
+
+  <interface name="org.freedesktop.NetworkManagerSettings.Secrets">
+    <tp:docstring>
+        Secrets have a separate interface so that they can be locked down via
+        D-Bus policy configuration.
+    </tp:docstring>
+
+    <method name="GetSecretsForConnection">
+      <tp:docstring>
+        Get the secrets for the requested connection.  If the connection is
+        provided by the settings service, it should save the updated secrets
+        if they are changed by the user.  If the connection is not provided
+        by the settings service, the new secrets will be saved by the settings
+        service that provides the connection.
+      </tp:docstring>
+      <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_get_secrets_for_connection"/>
+      <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+      <arg name="service_name" type="s" direction="in">
+        <tp:docstring>
+          The D-Bus service name of the settings service that provides this connection.
+        </tp:docstring>
+      </arg>
+      <arg name="connection" type="o" direction="in">
+        <tp:docstring>
+          Object path of the connection.
+        </tp:docstring>
+      </arg>
+      <arg name="setting_name" type="s" direction="in">
+        <tp:docstring>
+          Name of the setting for which secrets are requested.
+        </tp:docstring>
+      </arg>
+      <arg name="hints" type="as" direction="in">
+        <tp:docstring>
+          Array of strings of key names in the Setting for which NM thinks
+          a secrets may be required.
+        </tp:docstring>
+      </arg>
+
+      <arg name="secrets" type="a{sa{sv}}" direction="out" tp:type="String_String_Variant_Map_Map">
+        <tp:docstring>
+          Nested settings maps containing secrets.  Each setting MUST contain at
+          least the 'name' field, containing the name of the setting, and one or
+          more secrets.
+        </tp:docstring>
+      </arg>
+    </method>
+
+  </interface>
 </node>
 
diff --git a/libnm-glib/libnm-glib.ver b/libnm-glib/libnm-glib.ver
index 1596afa..74640ef 100644
--- a/libnm-glib/libnm-glib.ver
+++ b/libnm-glib/libnm-glib.ver
@@ -139,6 +139,7 @@ global:
 	nm_settings_interface_error_get_type;
 	nm_settings_interface_error_quark;
 	nm_settings_interface_get_connection_by_path;
+	nm_settings_interface_get_secrets_for_connection;
 	nm_settings_interface_get_type;
 	nm_settings_interface_list_connections;
 	nm_settings_service_export;
diff --git a/libnm-glib/nm-settings-interface.c b/libnm-glib/nm-settings-interface.c
index a1d548e..c03f349 100644
--- a/libnm-glib/nm-settings-interface.c
+++ b/libnm-glib/nm-settings-interface.c
@@ -143,6 +143,48 @@ nm_settings_interface_add_connection (NMSettingsInterface *settings,
 	return FALSE;
 }
 
+/**
+ * nm_settings_interface_get_secrets_for_connection:
+ * @settings: a object implementing %NMSettingsInterface
+ * @settings_service: name of the settings service providing this connection
+ * @connection_path: object path of the connection provided by @settings_service
+ * @setting_name: the name of the setting for which to get secrets
+ * @hints: a list of hints
+ * @callback: function to call when the operation is complete
+ * @user_data: context-specific data passed to @callback
+ *
+ * Requests that the settings service get the secrets for the requested connection.
+ *
+ * Returns: TRUE if the request was successful, FALSE if it failed
+ **/
+gboolean
+nm_settings_interface_get_secrets_for_connection (NMSettingsInterface *settings,
+                                                  const char *settings_service,
+                                                  const char *connection_path,
+                                                  const char *setting_name,
+                                                  const char **hints,
+                                                  NMSettingsGetSecretsForConnectionFunc callback,
+                                                  gpointer user_data)
+{
+	g_return_val_if_fail (settings != NULL, FALSE);
+	g_return_val_if_fail (NM_IS_SETTINGS_INTERFACE (settings), FALSE);
+	g_return_val_if_fail (connection_path != NULL, FALSE);
+	g_return_val_if_fail (setting_name != NULL, FALSE);
+	g_return_val_if_fail (hints != NULL, FALSE);
+	g_return_val_if_fail (callback != NULL, FALSE);
+
+	if (NM_SETTINGS_INTERFACE_GET_INTERFACE (settings)->get_secrets_for_connection) {
+		return NM_SETTINGS_INTERFACE_GET_INTERFACE (settings)->get_secrets_for_connection (settings,
+		                                                                                   settings_service,
+		                                                                                   connection_path,
+		                                                                                   setting_name,
+		                                                                                   hints,
+		                                                                                   callback,
+		                                                                                   user_data);
+	}
+	return FALSE;
+}
+
 /*****************************************************************/
 
 static void
diff --git a/libnm-glib/nm-settings-interface.h b/libnm-glib/nm-settings-interface.h
index dc7bd0e..47ca3f7 100644
--- a/libnm-glib/nm-settings-interface.h
+++ b/libnm-glib/nm-settings-interface.h
@@ -60,6 +60,11 @@ typedef void (*NMSettingsAddConnectionFunc) (NMSettingsInterface *settings,
                                              GError *error,
                                              gpointer user_data);
 
+typedef void (*NMSettingsGetSecretsForConnectionFunc) (NMSettingsInterface *settings,
+                                                       GHashTable *secrets,
+                                                       GError *error,
+                                                       gpointer user_data);
+
 struct _NMSettingsInterface {
 	GTypeInterface g_iface;
 
@@ -81,13 +86,21 @@ struct _NMSettingsInterface {
 
 	void (*connections_read) (NMSettingsInterface *settings);
 
+	/* Function */
+	gboolean (*get_secrets_for_connection) (NMSettingsInterface *self,
+	                                        const char *settings_service,
+	                                        const char *connection_path,
+	                                        const char *setting_name,
+	                                        const char **hints,
+	                                        NMSettingsGetSecretsForConnectionFunc callback,
+	                                        gpointer user_data);
+
 	/* Padding for future expansion */
 	void (*_reserved1) (void);
 	void (*_reserved2) (void);
 	void (*_reserved3) (void);
 	void (*_reserved4) (void);
 	void (*_reserved5) (void);
-	void (*_reserved6) (void);
 };
 
 GType nm_settings_interface_get_type (void);
@@ -103,6 +116,14 @@ gboolean nm_settings_interface_add_connection (NMSettingsInterface *settings,
                                                NMSettingsAddConnectionFunc callback,
                                                gpointer user_data);
 
+gboolean nm_settings_interface_get_secrets_for_connection (NMSettingsInterface *settings,
+                                                           const char *settings_service,
+                                                           const char *connection_path,
+                                                           const char *setting_name,
+                                                           const char **hints,
+                                                           NMSettingsGetSecretsForConnectionFunc callback,
+                                                           gpointer user_data);
+
 G_END_DECLS
 
 #endif /* NM_SETTINGS_INTERFACE_H */
diff --git a/libnm-glib/nm-settings-service.c b/libnm-glib/nm-settings-service.c
index 6266d10..58f678d 100644
--- a/libnm-glib/nm-settings-service.c
+++ b/libnm-glib/nm-settings-service.c
@@ -36,6 +36,13 @@ static void impl_settings_add_connection (NMSettingsService *self,
                                           GHashTable *settings,
                                           DBusGMethodInvocation *context);
 
+static void impl_settings_get_secrets_for_connection (NMSettingsService *self,
+                                                      const char *settings_service,
+                                                      const char *connection_path,
+                                                      const char *setting_name,
+                                                      const char **hints,
+                                                      DBusGMethodInvocation *context);
+
 #include "nm-settings-glue.h"
 
 static void settings_interface_init (NMSettingsInterface *class);
@@ -219,6 +226,49 @@ impl_settings_add_connection (NMSettingsService *self,
 	g_object_unref (tmp);
 }
 
+static void
+dbus_get_secrets_cb (NMSettingsInterface *settings,
+                     GHashTable *secrets,
+                     GError *error,
+                     gpointer user_data)
+{
+	DBusGMethodInvocation *context = user_data;
+
+	if (error)
+		dbus_g_method_return_error (context, error);
+	else
+		dbus_g_method_return (context, secrets);
+}
+
+static void
+impl_settings_get_secrets_for_connection (NMSettingsService *self,
+                                          const char *settings_service,
+                                          const char *connection_path,
+                                          const char *setting_name,
+                                          const char **hints,
+                                          DBusGMethodInvocation *context)
+{
+	GError *error = NULL;
+
+	if (NM_SETTINGS_SERVICE_GET_CLASS (self)->get_secrets_for_connection)
+		NM_SETTINGS_SERVICE_GET_CLASS (self)->get_secrets_for_connection (self,
+		                                                                  settings_service,
+		                                                                  connection_path,
+		                                                                  setting_name,
+		                                                                  hints,
+		                                                                  context,
+		                                                                  dbus_get_secrets_cb,
+		                                                                  context);
+	else {
+		error = g_error_new (NM_SETTINGS_INTERFACE_ERROR,
+		                     NM_SETTINGS_INTERFACE_ERROR_INTERNAL_ERROR,
+		                     "%s: %s:%d get_secrets_for_connection() not implemented",
+		                     __func__, __FILE__, __LINE__);
+		dbus_g_method_return_error (context, error);
+		g_error_free (error);
+	}
+}
+
 void
 nm_settings_service_export_connection (NMSettingsService *self,
                                        NMSettingsConnectionInterface *connection)
diff --git a/libnm-glib/nm-settings-service.h b/libnm-glib/nm-settings-service.h
index 9f4b95f..e59b074 100644
--- a/libnm-glib/nm-settings-service.h
+++ b/libnm-glib/nm-settings-service.h
@@ -58,13 +58,21 @@ typedef struct {
 	                        NMSettingsAddConnectionFunc callback,
 	                        gpointer user_data);
 
+	void (*get_secrets_for_connection) (NMSettingsService *self,
+	                                    const char *settings_service,
+	                                    const char *connection_path,
+	                                    const char *setting_name,
+	                                    const char **hints,
+	                                    DBusGMethodInvocation *context,
+	                                    NMSettingsGetSecretsForConnectionFunc callback,
+	                                    gpointer user_data);
+
 	/* Padding for future expansion */
 	void (*_reserved1) (void);
 	void (*_reserved2) (void);
 	void (*_reserved3) (void);
 	void (*_reserved4) (void);
 	void (*_reserved5) (void);
-	void (*_reserved6) (void);
 } NMSettingsServiceClass;
 
 GType nm_settings_service_get_type (void);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index b52c6ce..c8a9b55 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -2447,7 +2447,7 @@ typedef struct GetSecretsInfo {
 	guint32 idle_id;
 	char *hint1;
 	char *hint2;
-	char *connection_path;
+	NMConnection *connection;
 } GetSecretsInfo;
 
 static void
@@ -2472,7 +2472,7 @@ free_get_secrets_info (gpointer data)
 	g_free (info->hint1);
 	g_free (info->hint2);
 	g_free (info->setting_name);
-	g_free (info->connection_path);
+	g_object_unref (info->connection);
 	memset (info, 0, sizeof (GetSecretsInfo));
 	g_free (info);
 }
@@ -2494,6 +2494,16 @@ provider_cancel_secrets (NMSecretsProviderInterface *provider, gpointer user_dat
 }
 
 static void
+system_connection_update_cb (NMSettingsConnectionInterface *connection,
+                             GError *error,
+                             gpointer user_data)
+{
+	if (error != NULL) {
+		nm_log_warn (LOGD_SYS_SET, "could not update system connection: %s", error->message);
+	}
+}
+
+static void
 user_get_secrets_cb (DBusGProxy *proxy,
                      DBusGProxyCall *call,
                      gpointer user_data)
@@ -2517,6 +2527,14 @@ user_get_secrets_cb (DBusGProxy *proxy,
 		                                                  info->caller,
 		                                                  settings,
 		                                                  NULL);
+
+		/* If this connection is a system one, we need to update it on our end */
+		if (nm_connection_get_scope (info->connection) == NM_CONNECTION_SCOPE_SYSTEM) {
+			nm_settings_connection_interface_update (NM_SETTINGS_CONNECTION_INTERFACE (info->connection),
+			                                         system_connection_update_cb,
+			                                         NULL);
+		}
+
 		g_hash_table_destroy (settings);
 	} else {
 		nm_secrets_provider_interface_get_secrets_result (info->provider,
@@ -2608,18 +2626,62 @@ system_get_secrets_reply_cb (NMSettingsConnectionInterface *connection,
 }
 
 static gboolean
+system_get_secrets_from_user (GetSecretsInfo *info)
+{
+	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (info->manager);
+	DBusGConnection *g_connection;
+	GPtrArray *hints = NULL;
+
+	/* Only user settings services that are allowed to control the network
+	 * are allowed to provide new secrets for system connections.
+	 */
+	if (priv->user_net_perm != NM_AUTH_CALL_RESULT_YES)
+		return FALSE;
+
+	g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr);
+	info->proxy = dbus_g_proxy_new_for_name (g_connection,
+	                                         NM_DBUS_SERVICE_USER_SETTINGS,
+	                                         NM_DBUS_PATH_SETTINGS,
+	                                         NM_DBUS_IFACE_SETTINGS_SECRETS);
+	if (!info->proxy) {
+		nm_log_warn (LOGD_SYS_SET, "could not create user settings secrets proxy");
+		system_get_secrets_reply_cb (NULL, NULL, NULL, info); // FIXME pass error
+		return FALSE;
+	}
+
+	hints = g_ptr_array_sized_new (2);
+	if (info->hint1)
+		g_ptr_array_add (hints, (char *) info->hint1);
+	if (info->hint2)
+		g_ptr_array_add (hints, (char *) info->hint2);
+
+	info->call = dbus_g_proxy_begin_call_with_timeout (info->proxy, "GetSecretsForConnection",
+	                                                   user_get_secrets_cb,
+	                                                   info,
+	                                                   NULL,
+	                                                   G_MAXINT32,
+	                                                   G_TYPE_STRING, NM_DBUS_SERVICE_SYSTEM_SETTINGS,
+	                                                   DBUS_TYPE_G_OBJECT_PATH, nm_connection_get_path (info->connection),
+	                                                   G_TYPE_STRING, info->setting_name,
+	                                                   DBUS_TYPE_G_ARRAY_OF_STRING, hints,
+	                                                   G_TYPE_INVALID);
+	g_ptr_array_free (hints, TRUE);
+	return TRUE;
+}
+
+static gboolean
 system_get_secrets_idle_cb (gpointer user_data)
 {
 	GetSecretsInfo *info = user_data;
 	NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (info->manager);
 	NMSettingsConnectionInterface *connection;
 	GError *error = NULL;
-	const char *hints[3] = { NULL, NULL, NULL };
+	gboolean success = FALSE;
 
 	info->idle_id = 0;
 
 	connection = nm_settings_interface_get_connection_by_path (NM_SETTINGS_INTERFACE (priv->sys_settings), 
-	                                                           info->connection_path);
+	                                                           nm_connection_get_path (info->connection));
 	if (!connection) {
 		error = g_error_new_literal (NM_MANAGER_ERROR,
 		                             NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
@@ -2634,14 +2696,29 @@ system_get_secrets_idle_cb (gpointer user_data)
 		return FALSE;
 	}
 
-	hints[0] = info->hint1;
-	hints[1] = info->hint2;
-	nm_settings_connection_interface_get_secrets (connection,
-	                                              info->setting_name,
-	                                              hints,
-	                                              info->request_new,
-	                                              system_get_secrets_reply_cb,
-	                                              info);
+	/* If new secrets are requested, try asking the user settings service for
+	 * them since the system settings service can't interact with anything
+	 * to get new secrets.
+	 */
+	if (info->request_new)
+		success = system_get_secrets_from_user (info);
+
+	/* If the user wasn't authorized, or we should retry using existing
+	 * secrets, just ask the system settings service.
+	 */
+	if (!success) {
+		const char *hints[3] = { NULL, NULL, NULL };
+
+		hints[0] = info->hint1;
+		hints[1] = info->hint2;
+		nm_settings_connection_interface_get_secrets (connection,
+		                                              info->setting_name,
+		                                              hints,
+		                                              info->request_new,
+		                                              system_get_secrets_reply_cb,
+		                                              info);
+	}
+
 	return FALSE;
 }
 
@@ -2664,7 +2741,7 @@ system_get_secrets (NMManager *self,
 	info->setting_name = g_strdup (setting_name);
 	info->hint1 = hint1 ? g_strdup (hint1) : NULL;
 	info->hint2 = hint2 ? g_strdup (hint2) : NULL;
-	info->connection_path = g_strdup (nm_connection_get_path (connection));
+	info->connection = g_object_ref (connection);
 	info->request_new = request_new;
 
 	g_object_weak_ref (G_OBJECT (provider), (GWeakNotify) free_get_secrets_info, info);
