diff --git a/configure.ac b/configure.ac
index 4ed8d9e..b0ef0ed 100644
--- a/configure.ac
+++ b/configure.ac
@@ -39,7 +39,7 @@ KEYRING_REQUIRED=2.26.0
 LIBCANBERRA_GTK_REQUIRED=0.25
 LIBNOTIFY_REQUIRED=0.7.0
 TELEPATHY_FARSIGHT_REQUIRED=0.0.14
-TELEPATHY_GLIB_REQUIRED=0.13.7
+TELEPATHY_GLIB_REQUIRED=0.13.9
 TELEPATHY_LOGGER=0.1.5
 
 # Optional deps
diff --git a/data/Empathy.Auth.client b/data/Empathy.Auth.client
index 1fbf103..7fb5bba 100644
--- a/data/Empathy.Auth.client
+++ b/data/Empathy.Auth.client
@@ -1,5 +1,5 @@
 [org.freedesktop.Telepathy.Client]
-Interfaces=org.freedesktop.Telepathy.Client.Handler
+Interfaces=org.freedesktop.Telepathy.Client.Handler;org.freedesktop.Telepathy.Client.Observer
 
 [org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 0]
 org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.ServerTLSConnection
@@ -8,3 +8,7 @@ org.freedesktop.Telepathy.Channel.TargetHandleType u=0
 [org.freedesktop.Telepathy.Client.Handler.HandlerChannelFilter 1]
 org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.ServerAuthentication
 org.freedesktop.Telepathy.Channel.Type.ServerAuthentication s=org.freedesktop.Telepathy.Channel.Interface.SASLAuthentication
+
+[org.freedesktop.Telepathy.Client.Observer.ObserverChannelFilter 0]
+org.freedesktop.Telepathy.Channel.ChannelType s=org.freedesktop.Telepathy.Channel.Type.ServerAuthentication
+org.freedesktop.Telepathy.Channel.Type.ServerAuthentication s=org.freedesktop.Telepathy.Channel.Interface.SASLAuthentication
diff --git a/libempathy-gtk/empathy-account-widget-aim.ui b/libempathy-gtk/empathy-account-widget-aim.ui
index b590eea..fb2e518 100644
--- a/libempathy-gtk/empathy-account-widget-aim.ui
+++ b/libempathy-gtk/empathy-account-widget-aim.ui
@@ -15,7 +15,7 @@
     <child>
       <object class="GtkTable" id="table_common_settings">
         <property name="visible">True</property>
-        <property name="n_rows">3</property>
+        <property name="n_rows">4</property>
         <property name="n_columns">2</property>
         <property name="column_spacing">12</property>
         <property name="row_spacing">6</property>
@@ -91,6 +91,25 @@
           </packing>
         </child>
         <child>
+          <object class="GtkCheckButton" id="remember_password">
+            <property name="label" translatable="yes">Remember Password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="right_attach">2</property>
+            <property name="top_attach">3</property>
+            <property name="bottom_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
           <placeholder/>
         </child>
       </object>
@@ -273,5 +292,18 @@
         <property name="position">3</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkCheckButton" id="remember_password_simple">
+        <property name="label" translatable="yes">Remember Password</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="position">4</property>
+      </packing>
+    </child>
   </object>
 </interface>
diff --git a/libempathy-gtk/empathy-account-widget-groupwise.ui b/libempathy-gtk/empathy-account-widget-groupwise.ui
index 1629a01..1cf2ea7 100644
--- a/libempathy-gtk/empathy-account-widget-groupwise.ui
+++ b/libempathy-gtk/empathy-account-widget-groupwise.ui
@@ -14,7 +14,7 @@
     <child>
       <object class="GtkTable" id="table_common_groupwise_settings">
         <property name="visible">True</property>
-        <property name="n_rows">3</property>
+        <property name="n_rows">4</property>
         <property name="n_columns">2</property>
         <property name="column_spacing">12</property>
         <property name="row_spacing">6</property>
@@ -75,9 +75,6 @@
           </packing>
         </child>
         <child>
-          <placeholder/>
-        </child>
-        <child>
           <object class="GtkEntry" id="entry_password">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
@@ -90,6 +87,28 @@
             <property name="bottom_attach">3</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkCheckButton" id="remember_password">
+            <property name="label" translatable="yes">Remember Password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="right_attach">2</property>
+            <property name="top_attach">3</property>
+            <property name="bottom_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
       </object>
       <packing>
         <property name="expand">False</property>
@@ -270,5 +289,18 @@
         <property name="position">3</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkCheckButton" id="remember_password_simple">
+        <property name="label" translatable="yes">Remember Password</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="position">4</property>
+      </packing>
+    </child>
   </object>
 </interface>
diff --git a/libempathy-gtk/empathy-account-widget-icq.ui b/libempathy-gtk/empathy-account-widget-icq.ui
index 654174f..4d95978 100644
--- a/libempathy-gtk/empathy-account-widget-icq.ui
+++ b/libempathy-gtk/empathy-account-widget-icq.ui
@@ -15,7 +15,7 @@
     <child>
       <object class="GtkTable" id="table_common_settings">
         <property name="visible">True</property>
-        <property name="n_rows">3</property>
+        <property name="n_rows">4</property>
         <property name="n_columns">2</property>
         <property name="column_spacing">12</property>
         <property name="row_spacing">6</property>
@@ -91,6 +91,25 @@
           </packing>
         </child>
         <child>
+          <object class="GtkCheckButton" id="remember_password">
+            <property name="label" translatable="yes">Remember Password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="right_attach">2</property>
+            <property name="top_attach">3</property>
+            <property name="bottom_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
           <placeholder/>
         </child>
       </object>
@@ -301,5 +320,18 @@
         <property name="position">3</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkCheckButton" id="remember_password_simple">
+        <property name="label" translatable="yes">Remember Password</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="position">4</property>
+      </packing>
+    </child>
   </object>
 </interface>
diff --git a/libempathy-gtk/empathy-account-widget-jabber.ui b/libempathy-gtk/empathy-account-widget-jabber.ui
index 3136f51..ca476e5 100644
--- a/libempathy-gtk/empathy-account-widget-jabber.ui
+++ b/libempathy-gtk/empathy-account-widget-jabber.ui
@@ -21,7 +21,7 @@
     <child>
       <object class="GtkTable" id="table_common_settings">
         <property name="visible">True</property>
-        <property name="n_rows">3</property>
+        <property name="n_rows">4</property>
         <property name="n_columns">2</property>
         <property name="column_spacing">12</property>
         <property name="row_spacing">6</property>
@@ -46,8 +46,6 @@
           <packing>
             <property name="left_attach">1</property>
             <property name="right_attach">2</property>
-            <property name="top_attach">0</property>
-            <property name="bottom_attach">1</property>
           </packing>
         </child>
         <child>
@@ -60,10 +58,6 @@
           </object>
           <packing>
             <property name="x_options">GTK_FILL</property>
-            <property name="left_attach">0</property>
-            <property name="right_attach">1</property>
-            <property name="top_attach">0</property>
-            <property name="bottom_attach">1</property>
           </packing>
         </child>
         <child>
@@ -76,11 +70,9 @@
             <property name="mnemonic_widget">entry_password</property>
           </object>
           <packing>
-            <property name="x_options">GTK_FILL</property>
-            <property name="left_attach">0</property>
-            <property name="right_attach">1</property>
             <property name="top_attach">2</property>
             <property name="bottom_attach">3</property>
+            <property name="x_options">GTK_FILL</property>
           </packing>
         </child>
         <child>
@@ -141,6 +133,25 @@ Use &lt;a href="http://www.facebook.com/username/"&gt;this page&lt;/a&gt; to cho
           </packing>
         </child>
         <child>
+          <object class="GtkCheckButton" id="remember_password">
+            <property name="label" translatable="yes">Remember Password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="right_attach">2</property>
+            <property name="top_attach">3</property>
+            <property name="bottom_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
           <placeholder/>
         </child>
       </object>
@@ -508,6 +519,19 @@ Use &lt;a href="http://www.facebook.com/username/"&gt;this page&lt;/a&gt; to cho
         <property name="position">5</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkCheckButton" id="remember_password_simple">
+        <property name="label" translatable="yes">Remember Password</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="position">6</property>
+      </packing>
+    </child>
   </object>
   <object class="GtkVBox" id="vbox_gtalk_simple">
     <property name="visible">True</property>
@@ -598,6 +622,19 @@ Use &lt;a href="http://www.facebook.com/username/"&gt;this page&lt;/a&gt; to cho
         <property name="position">3</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkCheckButton" id="remember_password_g_simple">
+        <property name="label" translatable="yes">Remember Password</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="position">4</property>
+      </packing>
+    </child>
   </object>
   <object class="GtkVBox" id="vbox_fb_simple">
     <property name="visible">True</property>
@@ -690,5 +727,18 @@ Use &lt;a href="http://www.facebook.com/username/"&gt;this page&lt;/a&gt; to cho
         <property name="position">3</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkCheckButton" id="remember_password_fb_simple">
+        <property name="label" translatable="yes">Remember Password</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="position">4</property>
+      </packing>
+    </child>
   </object>
 </interface>
diff --git a/libempathy-gtk/empathy-account-widget-msn.ui b/libempathy-gtk/empathy-account-widget-msn.ui
index 133ce48..6665133 100644
--- a/libempathy-gtk/empathy-account-widget-msn.ui
+++ b/libempathy-gtk/empathy-account-widget-msn.ui
@@ -14,7 +14,7 @@
     <child>
       <object class="GtkTable" id="table_common_msn_settings">
         <property name="visible">True</property>
-        <property name="n_rows">3</property>
+        <property name="n_rows">4</property>
         <property name="n_columns">2</property>
         <property name="column_spacing">12</property>
         <property name="row_spacing">6</property>
@@ -75,9 +75,6 @@
           </packing>
         </child>
         <child>
-          <placeholder/>
-        </child>
-        <child>
           <object class="GtkEntry" id="entry_password">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
@@ -90,6 +87,28 @@
             <property name="bottom_attach">3</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkCheckButton" id="remember_password">
+            <property name="label" translatable="yes">Remember Password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="right_attach">2</property>
+            <property name="top_attach">3</property>
+            <property name="bottom_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
       </object>
       <packing>
         <property name="expand">False</property>
@@ -270,5 +289,18 @@
         <property name="position">3</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkCheckButton" id="remember_password_simple">
+        <property name="label" translatable="yes">Remember Password</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="position">4</property>
+      </packing>
+    </child>
   </object>
 </interface>
diff --git a/libempathy-gtk/empathy-account-widget-sip.ui b/libempathy-gtk/empathy-account-widget-sip.ui
index b00eda9..98a8f2c 100644
--- a/libempathy-gtk/empathy-account-widget-sip.ui
+++ b/libempathy-gtk/empathy-account-widget-sip.ui
@@ -13,7 +13,7 @@
     <child>
       <object class="GtkTable" id="table_common_settings">
         <property name="visible">True</property>
-        <property name="n_rows">3</property>
+        <property name="n_rows">4</property>
         <property name="n_columns">2</property>
         <property name="column_spacing">12</property>
         <property name="row_spacing">6</property>
@@ -75,9 +75,6 @@
           </packing>
         </child>
         <child>
-          <placeholder/>
-        </child>
-        <child>
           <object class="GtkEntry" id="entry_password">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
@@ -89,6 +86,28 @@
             <property name="bottom_attach">3</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkCheckButton" id="remember_password">
+            <property name="label" translatable="yes">Remember Password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="right_attach">2</property>
+            <property name="top_attach">3</property>
+            <property name="bottom_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
       </object>
       <packing>
         <property name="expand">False</property>
@@ -583,6 +602,19 @@
         <property name="position">3</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkCheckButton" id="remember_password_simple">
+        <property name="label" translatable="yes">Remember Password</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="position">4</property>
+      </packing>
+    </child>
   </object>
   <object class="GtkAdjustment" id="adjustment2">
     <property name="upper">65535</property>
diff --git a/libempathy-gtk/empathy-account-widget-yahoo.ui b/libempathy-gtk/empathy-account-widget-yahoo.ui
index acc60de..16044f3 100644
--- a/libempathy-gtk/empathy-account-widget-yahoo.ui
+++ b/libempathy-gtk/empathy-account-widget-yahoo.ui
@@ -16,7 +16,7 @@
     <child>
       <object class="GtkTable" id="table_common_settings">
         <property name="visible">True</property>
-        <property name="n_rows">3</property>
+        <property name="n_rows">4</property>
         <property name="n_columns">2</property>
         <property name="column_spacing">12</property>
         <property name="row_spacing">6</property>
@@ -92,6 +92,25 @@
           </packing>
         </child>
         <child>
+          <object class="GtkCheckButton" id="remember_password">
+            <property name="label" translatable="yes">Remember Password</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="right_attach">2</property>
+            <property name="top_attach">3</property>
+            <property name="bottom_attach">4</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
           <placeholder/>
         </child>
       </object>
@@ -357,5 +376,18 @@
         <property name="position">3</property>
       </packing>
     </child>
+    <child>
+      <object class="GtkCheckButton" id="remember_password_simple">
+        <property name="label" translatable="yes">Remember password</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">False</property>
+        <property name="active">True</property>
+        <property name="draw_indicator">True</property>
+      </object>
+      <packing>
+        <property name="position">4</property>
+      </packing>
+    </child>
   </object>
 </interface>
diff --git a/libempathy-gtk/empathy-account-widget.c b/libempathy-gtk/empathy-account-widget.c
index d96de2b..d2a1c56 100644
--- a/libempathy-gtk/empathy-account-widget.c
+++ b/libempathy-gtk/empathy-account-widget.c
@@ -109,6 +109,9 @@ typedef struct {
   GtkWidget *param_account_widget;
   GtkWidget *param_password_widget;
 
+  gboolean automatic_change;
+  GtkWidget *remember_password_widget;
+
   /* Used only for IRC accounts */
   EmpathyIrcNetworkChooser *irc_network_chooser;
 
@@ -311,6 +314,11 @@ static void
 account_widget_entry_changed_cb (GtkEditable *entry,
     EmpathyAccountWidget *self)
 {
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
+
+  if (priv->automatic_change)
+    return;
+
   account_widget_entry_changed_common (self, GTK_ENTRY (entry), FALSE);
   empathy_account_widget_changed (self);
 }
@@ -1220,6 +1228,17 @@ account_widget_build_sip (EmpathyAccountWidget *self,
   EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
   empathy_account_widget_sip_build (self, filename,
     &priv->table_common_settings);
+
+  if (priv->simple)
+    {
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password_simple"));
+    }
+  else
+    {
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password"));
+    }
 }
 
 static void
@@ -1243,6 +1262,9 @@ account_widget_build_msn (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_id_simple");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password_simple"));
     }
   else
     {
@@ -1259,6 +1281,9 @@ account_widget_build_msn (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_id");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password"));
     }
 }
 
@@ -1401,6 +1426,9 @@ account_widget_build_jabber (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_id_simple");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password_simple"));
     }
   else if (priv->simple && service == GTALK_SERVICE)
     {
@@ -1415,6 +1443,9 @@ account_widget_build_jabber (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_id_g_simple");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password_g_simple"));
     }
   else if (priv->simple && service == FACEBOOK_SERVICE)
     {
@@ -1431,6 +1462,9 @@ account_widget_build_jabber (EmpathyAccountWidget *self,
       setup_id_widget_with_suffix (self, entry_id, "@chat.facebook.com");
 
       self->ui_details->default_focus = g_strdup ("entry_id_fb_simple");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password_fb_simple"));
     }
   else
     {
@@ -1476,6 +1510,9 @@ account_widget_build_jabber (EmpathyAccountWidget *self,
       self->ui_details->default_focus = g_strdup ("entry_id");
       priv->spinbutton_port = spinbutton_port;
 
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password"));
+
       g_signal_connect (checkbutton_ssl, "toggled",
           G_CALLBACK (account_widget_jabber_ssl_toggled_cb),
           self);
@@ -1522,6 +1559,9 @@ account_widget_build_icq (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_uin_simple");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password_simple"));
     }
   else
     {
@@ -1540,6 +1580,9 @@ account_widget_build_icq (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_uin");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password"));
     }
 }
 
@@ -1562,6 +1605,9 @@ account_widget_build_aim (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_screenname_simple");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password_simple"));
     }
   else
     {
@@ -1579,6 +1625,9 @@ account_widget_build_aim (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_screenname");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password"));
     }
 }
 
@@ -1603,6 +1652,9 @@ account_widget_build_yahoo (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_id_simple");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password_simple"));
     }
   else
     {
@@ -1622,6 +1674,9 @@ account_widget_build_yahoo (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_id");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password"));
     }
 }
 
@@ -1643,6 +1698,9 @@ account_widget_build_groupwise (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_id_simple");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password_simple"));
     }
   else
     {
@@ -1659,6 +1717,9 @@ account_widget_build_groupwise (EmpathyAccountWidget *self,
           NULL);
 
       self->ui_details->default_focus = g_strdup ("entry_id");
+
+      priv->remember_password_widget = GTK_WIDGET (gtk_builder_get_object (
+              self->ui_details->gui, "remember_password"));
     }
 }
 
@@ -1990,6 +2051,48 @@ add_register_buttons (EmpathyAccountWidget *self,
 #endif /* HAVE_MEEGO */
 
 static void
+remember_password_toggled_cb (GtkToggleButton *button,
+    EmpathyAccountWidget *self)
+{
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
+
+  if (gtk_toggle_button_get_active (button))
+    {
+      gtk_widget_set_sensitive (priv->param_password_widget, TRUE);
+    }
+  else
+    {
+      gtk_widget_set_sensitive (priv->param_password_widget, FALSE);
+      gtk_entry_set_text (GTK_ENTRY (priv->param_password_widget), "");
+      empathy_account_settings_unset (priv->settings, "password");
+    }
+}
+
+static void
+account_settings_password_retrieved_cb (GObject *object,
+    gpointer user_data)
+{
+  EmpathyAccountWidget *self = user_data;
+  EmpathyAccountWidgetPriv *priv = GET_PRIV (self);
+  const gchar *password = empathy_account_settings_get_string (
+      priv->settings, "password");
+
+  if (password != NULL)
+    {
+      /* We have to do this so that when we call gtk_entry_set_text,
+       * the ::changed callback doesn't think the user made the
+       * change. */
+      priv->automatic_change = TRUE;
+      gtk_entry_set_text (GTK_ENTRY (priv->param_password_widget), password);
+      priv->automatic_change = FALSE;
+    }
+
+  gtk_toggle_button_set_active (
+      GTK_TOGGLE_BUTTON (priv->remember_password_widget),
+      !EMP_STR_EMPTY (password));
+}
+
+static void
 do_constructed (GObject *obj)
 {
   EmpathyAccountWidget *self = EMPATHY_ACCOUNT_WIDGET (obj);
@@ -2074,6 +2177,42 @@ do_constructed (GObject *obj)
           NULL);
     }
 
+  /* remember password */
+  if (priv->param_password_widget != NULL
+      && priv->remember_password_widget != NULL
+      && empathy_account_settings_supports_sasl (priv->settings))
+    {
+      if (priv->simple)
+        {
+          gtk_toggle_button_set_active (
+              GTK_TOGGLE_BUTTON (priv->remember_password_widget), TRUE);
+        }
+      else
+        {
+          gtk_toggle_button_set_active (
+              GTK_TOGGLE_BUTTON (priv->remember_password_widget),
+              !EMP_STR_EMPTY (empathy_account_settings_get_string (
+                      priv->settings, "password")));
+
+          /* The password might not have been retrieved from the
+           * keyring yet. We should update the remember password
+           * toggle button and the password entry when/if it is. */
+          g_signal_connect (priv->settings, "password-retrieved",
+              G_CALLBACK (account_settings_password_retrieved_cb), self);
+        }
+
+      g_signal_connect (priv->remember_password_widget, "toggled",
+          G_CALLBACK (remember_password_toggled_cb), self);
+
+      remember_password_toggled_cb (
+          GTK_TOGGLE_BUTTON (priv->remember_password_widget), self);
+    }
+  else if (priv->remember_password_widget != NULL
+      && !empathy_account_settings_supports_sasl (priv->settings))
+    {
+      gtk_widget_set_visible (priv->remember_password_widget, FALSE);
+    }
+
   /* dup and init the account-manager */
   priv->account_manager = tp_account_manager_dup ();
 
diff --git a/libempathy-gtk/empathy-password-dialog.c b/libempathy-gtk/empathy-password-dialog.c
index 3c514ee..5608bb0 100644
--- a/libempathy-gtk/empathy-password-dialog.c
+++ b/libempathy-gtk/empathy-password-dialog.c
@@ -264,15 +264,8 @@ empathy_password_dialog_constructed (GObject *object)
   /* remember password ticky box */
   priv->ticky = gtk_check_button_new_with_label (_("Remember password"));
 
-  /* Don't add this to the dialog yet because we haven't set up
-   * everything in the UI properly yet and the MC transition isn't
-   * ready etc. so we'll just force it to never remember a
-   * password. */
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->ticky), FALSE);
-  /*
   gtk_box_pack_start (box, priv->ticky, FALSE, FALSE, 0);
   gtk_widget_show (priv->ticky);
-  */
 
   g_signal_connect (dialog, "response",
       G_CALLBACK (password_dialog_response_cb), dialog);
diff --git a/libempathy/empathy-account-settings.c b/libempathy/empathy-account-settings.c
index e5191a9..c1452ac 100644
--- a/libempathy/empathy-account-settings.c
+++ b/libempathy/empathy-account-settings.c
@@ -29,6 +29,7 @@
 
 #include "empathy-account-settings.h"
 #include "empathy-connection-managers.h"
+#include "empathy-keyring.h"
 #include "empathy-utils.h"
 #include "empathy-idle.h"
 
@@ -49,6 +50,13 @@ enum {
   PROP_READY
 };
 
+enum {
+  PASSWORD_RETRIEVED = 1,
+  LAST_SIGNAL
+};
+
+static gulong signals[LAST_SIGNAL] = { 0, };
+
 /* private structure */
 typedef struct _EmpathyAccountSettingsPriv EmpathyAccountSettingsPriv;
 
@@ -59,6 +67,7 @@ struct _EmpathyAccountSettingsPriv
   TpAccountManager *account_manager;
 
   TpConnectionManager *manager;
+  TpProtocol *protocol_obj;
 
   TpAccount *account;
   gchar *cm_name;
@@ -69,6 +78,15 @@ struct _EmpathyAccountSettingsPriv
   gboolean display_name_overridden;
   gboolean ready;
 
+  gboolean supports_sasl;
+  gboolean password_changed;
+
+  gchar *password;
+  gchar *password_original;
+
+  gboolean password_retrieved;
+  gboolean password_requested;
+
   /* Parameter name (gchar *) -> parameter value (GValue) */
   GHashTable *parameters;
   /* Keys are parameter names from the hash above (gchar *).
@@ -80,6 +98,7 @@ struct _EmpathyAccountSettingsPriv
   GList *required_params;
 
   gulong managers_ready_id;
+  gboolean preparing_protocol;
 
   GSimpleAsyncResult *apply_result;
 };
@@ -226,8 +245,12 @@ empathy_account_settings_constructed (GObject *object)
           TP_ACCOUNT_FEATURE_STORAGE,
           0 };
 
-      tp_proxy_prepare_async (priv->account, features,
-          empathy_account_settings_account_ready_cb, self);
+      if (priv->account != NULL)
+        {
+          tp_proxy_prepare_async (priv->account, features,
+              empathy_account_settings_account_ready_cb, self);
+        }
+
       tp_g_signal_connect_object (priv->managers, "notify::ready",
         G_CALLBACK (empathy_account_settings_managers_ready_cb), object, 0);
     }
@@ -303,6 +326,13 @@ empathy_account_settings_class_init (
       "Whether this account is ready to be used",
       FALSE,
       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
+
+  signals[PASSWORD_RETRIEVED] =
+      g_signal_new ("password-retrieved",
+          G_TYPE_FROM_CLASS (empathy_account_settings_class),
+          G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+          g_cclosure_marshal_VOID__VOID,
+          G_TYPE_NONE, 0);
 }
 
 static void
@@ -336,6 +366,10 @@ empathy_account_settings_dispose (GObject *object)
     g_object_unref (priv->account);
   priv->account = NULL;
 
+  if (priv->protocol_obj != NULL)
+    g_object_unref (priv->protocol_obj);
+  priv->protocol_obj = NULL;
+
   /* release any references held by the object here */
   if (G_OBJECT_CLASS (empathy_account_settings_parent_class)->dispose)
     G_OBJECT_CLASS (empathy_account_settings_parent_class)->dispose (object);
@@ -367,6 +401,8 @@ empathy_account_settings_finalize (GObject *object)
   g_free (priv->service);
   g_free (priv->display_name);
   g_free (priv->icon_name);
+  g_free (priv->password);
+  g_free (priv->password_original);
 
   if (priv->required_params != NULL)
     {
@@ -385,10 +421,60 @@ empathy_account_settings_finalize (GObject *object)
 }
 
 static void
+empathy_account_settings_protocol_obj_prepared_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  EmpathyAccountSettings *self = user_data;
+  GError *error = NULL;
+
+  if (!tp_proxy_prepare_finish (source, result, &error))
+    {
+      DEBUG ("Failed to prepare protocol object: %s", error->message);
+      g_clear_error (&error);
+      return;
+    }
+
+  empathy_account_settings_check_readyness (self);
+}
+
+static void
+empathy_account_settings_get_password_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  EmpathyAccountSettings *self = user_data;
+  EmpathyAccountSettingsPriv *priv = GET_PRIV (self);
+  const gchar *password;
+  GError *error = NULL;
+
+  password = empathy_keyring_get_password_finish (TP_ACCOUNT (source),
+      result, &error);
+
+  if (error != NULL)
+    {
+      DEBUG ("Failed to get password: %s", error->message);
+      g_clear_error (&error);
+    }
+
+  /* It doesn't really matter if getting the password failed; that
+   * just means that it's not there, or let's act like that at
+   * least. */
+
+  g_assert (priv->password == NULL);
+
+  priv->password = g_strdup (password);
+  priv->password_original = g_strdup (password);
+
+  g_signal_emit (self, signals[PASSWORD_RETRIEVED], 0);
+}
+
+static void
 empathy_account_settings_check_readyness (EmpathyAccountSettings *self)
 {
   EmpathyAccountSettingsPriv *priv = GET_PRIV (self);
   const TpConnectionManagerProtocol *tp_protocol;
+  GQuark features[] = { TP_PROTOCOL_FEATURE_CORE, 0 };
 
   if (priv->ready)
     return;
@@ -400,12 +486,17 @@ empathy_account_settings_check_readyness (EmpathyAccountSettings *self)
   if (!empathy_connection_managers_is_ready (priv->managers))
     return;
 
-  priv->manager = empathy_connection_managers_get_cm (
-    priv->managers, priv->cm_name);
+  if (priv->manager == NULL)
+    {
+      priv->manager = empathy_connection_managers_get_cm (
+          priv->managers, priv->cm_name);
+    }
 
   if (priv->manager == NULL)
     return;
 
+  g_object_ref (priv->manager);
+
   if (priv->account != NULL)
     {
       g_free (priv->display_name);
@@ -440,7 +531,43 @@ empathy_account_settings_check_readyness (EmpathyAccountSettings *self)
         }
     }
 
-  g_object_ref (priv->manager);
+  if (priv->protocol_obj == NULL)
+    {
+      priv->protocol_obj = g_object_ref (
+          tp_connection_manager_get_protocol_object (priv->manager,
+              priv->protocol));
+    }
+
+  if (!tp_proxy_is_prepared (priv->protocol_obj, TP_PROTOCOL_FEATURE_CORE)
+      && !priv->preparing_protocol)
+    {
+      priv->preparing_protocol = TRUE;
+      tp_proxy_prepare_async (priv->protocol_obj, features,
+          empathy_account_settings_protocol_obj_prepared_cb, self);
+      return;
+    }
+  else
+    {
+      if (tp_strv_contains (tp_protocol_get_authentication_types (
+                  priv->protocol_obj),
+              TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION))
+        {
+          priv->supports_sasl = TRUE;
+        }
+    }
+
+  /* priv->account won't be a proper account if it's the account
+   * assistant showing this widget. */
+  if (priv->supports_sasl && !priv->password_requested
+      && priv->account != NULL)
+    {
+      priv->password_requested = TRUE;
+
+      /* Make this call but don't block on its readiness. We'll signal
+       * if it's updated later with ::password-retrieved. */
+      empathy_keyring_get_password_async (priv->account,
+          empathy_account_settings_get_password_cb, self);
+    }
 
   priv->ready = TRUE;
   g_object_notify (G_OBJECT (self), "ready");
@@ -701,6 +828,14 @@ empathy_account_settings_unset (EmpathyAccountSettings *settings,
   if (empathy_account_settings_is_unset (settings, param))
     return;
 
+  if (priv->supports_sasl && !tp_strdiff (param, "password"))
+    {
+      g_free (priv->password);
+      priv->password = NULL;
+      priv->password_changed = TRUE;
+      return;
+    }
+
   v = g_strdup (param);
 
   g_array_append_val (priv->unset_parameters, v);
@@ -714,14 +849,24 @@ empathy_account_settings_discard_changes (EmpathyAccountSettings *settings)
 
   g_hash_table_remove_all (priv->parameters);
   empathy_account_settings_free_unset_parameters (settings);
+
+  priv->password_changed = FALSE;
+  g_free (priv->password);
+  priv->password = g_strdup (priv->password_original);
 }
 
 const gchar *
 empathy_account_settings_get_string (EmpathyAccountSettings *settings,
     const gchar *param)
 {
+  EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
   const GValue *v;
 
+  if (!tp_strdiff (param, "password") && priv->supports_sasl)
+    {
+      return priv->password;
+    }
+
   v = empathy_account_settings_get (settings, param);
 
   if (v == NULL || !G_VALUE_HOLDS_STRING (v))
@@ -916,7 +1061,16 @@ empathy_account_settings_set_string (EmpathyAccountSettings *settings,
   g_return_if_fail (param != NULL);
   g_return_if_fail (value != NULL);
 
-  tp_asv_set_string (priv->parameters, g_strdup (param), value);
+  if (!tp_strdiff (param, "password") && priv->supports_sasl)
+    {
+      g_free (priv->password);
+      priv->password = g_strdup (value);
+      priv->password_changed = TRUE;
+    }
+  else
+    {
+      tp_asv_set_string (priv->parameters, g_strdup (param), value);
+    }
 
   account_settings_remove_from_unset (settings, param);
 }
@@ -1152,6 +1306,55 @@ empathy_account_settings_set_icon_name_finish (
 }
 
 static void
+empathy_account_settings_processed_password (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data,
+    gpointer finish_func)
+{
+  EmpathyAccountSettings *settings = EMPATHY_ACCOUNT_SETTINGS (user_data);
+  EmpathyAccountSettingsPriv *priv = GET_PRIV (settings);
+  GSimpleAsyncResult *r;
+  GError *error = NULL;
+  gboolean (*func) (TpAccount *source, GAsyncResult *result, GError **error) =
+    finish_func;
+
+  g_free (priv->password_original);
+  priv->password_original = g_strdup (priv->password);
+
+  if (!func (TP_ACCOUNT (source), result, &error))
+    {
+      g_simple_async_result_set_from_error (priv->apply_result, error);
+      g_error_free (error);
+    }
+
+  empathy_account_settings_discard_changes (settings);
+
+  r = priv->apply_result;
+  priv->apply_result = NULL;
+
+  g_simple_async_result_complete (r);
+  g_object_unref (r);
+}
+
+static void
+empathy_account_settings_set_password_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  empathy_account_settings_processed_password (source, result, user_data,
+      empathy_keyring_set_password_finish);
+}
+
+static void
+empathy_account_settings_delete_password_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  empathy_account_settings_processed_password (source, result, user_data,
+      empathy_keyring_delete_password_finish);
+}
+
+static void
 empathy_account_settings_account_updated (GObject *source,
     GAsyncResult *result,
     gpointer user_data)
@@ -1166,12 +1369,30 @@ empathy_account_settings_account_updated (GObject *source,
     {
       g_simple_async_result_set_from_error (priv->apply_result, error);
       g_error_free (error);
+      goto out;
     }
-  else
+
+  /* Only set the password in the keyring if the CM supports SASL and
+   * it's changed. */
+  if (priv->supports_sasl && priv->password_changed)
     {
-      empathy_account_settings_discard_changes (settings);
+      if (priv->password != NULL)
+        {
+          empathy_keyring_set_password_async (priv->account, priv->password,
+              empathy_account_settings_set_password_cb, settings);
+        }
+      else
+        {
+          empathy_keyring_delete_password_async (priv->account,
+              empathy_account_settings_delete_password_cb, settings);
+        }
+
+      return;
     }
 
+out:
+  empathy_account_settings_discard_changes (settings);
+
   r = priv->apply_result;
   priv->apply_result = NULL;
 
@@ -1451,3 +1672,11 @@ empathy_account_settings_get_tp_protocol (EmpathyAccountSettings *self)
 
   return tp_connection_manager_get_protocol (priv->manager, priv->protocol);
 }
+
+gboolean
+empathy_account_settings_supports_sasl (EmpathyAccountSettings *self)
+{
+  EmpathyAccountSettingsPriv *priv = GET_PRIV (self);
+
+  return priv->supports_sasl;
+}
diff --git a/libempathy/empathy-account-settings.h b/libempathy/empathy-account-settings.h
index 8f3634a..4d5f6dd 100644
--- a/libempathy/empathy-account-settings.h
+++ b/libempathy/empathy-account-settings.h
@@ -189,6 +189,8 @@ gboolean empathy_account_settings_is_valid (EmpathyAccountSettings *settings);
 const TpConnectionManagerProtocol * empathy_account_settings_get_tp_protocol (
     EmpathyAccountSettings *settings);
 
+gboolean empathy_account_settings_supports_sasl (EmpathyAccountSettings *self);
+
 G_END_DECLS
 
 #endif /* #ifndef __EMPATHY_ACCOUNT_SETTINGS_H__*/
diff --git a/libempathy/empathy-auth-factory.c b/libempathy/empathy-auth-factory.c
index 578b6d6..59c256e 100644
--- a/libempathy/empathy-auth-factory.c
+++ b/libempathy/empathy-auth-factory.c
@@ -26,17 +26,16 @@
 
 #define DEBUG_FLAG EMPATHY_DEBUG_TLS
 #include "empathy-debug.h"
+#include "empathy-keyring.h"
 #include "empathy-server-sasl-handler.h"
 #include "empathy-server-tls-handler.h"
 #include "empathy-utils.h"
 
 #include "extensions/extensions.h"
 
-G_DEFINE_TYPE (EmpathyAuthFactory, empathy_auth_factory, G_TYPE_OBJECT);
+G_DEFINE_TYPE (EmpathyAuthFactory, empathy_auth_factory, TP_TYPE_BASE_CLIENT);
 
 typedef struct {
-  TpBaseClient *handler;
-
   /* Keep a ref here so the auth client doesn't have to mess with
    * refs. It will be cleared when the channel (and so the handler)
    * gets invalidated. */
@@ -79,7 +78,9 @@ handler_context_data_new (EmpathyAuthFactory *self,
 
   data = g_slice_new0 (HandlerContextData);
   data->self = g_object_ref (self);
-  data->context = g_object_ref (context);
+
+  if (context != NULL)
+    data->context = g_object_ref (context);
 
   return data;
 }
@@ -145,13 +146,16 @@ server_sasl_handler_ready_cb (GObject *source,
     {
       DEBUG ("Failed to create a server SASL handler; error %s",
           error->message);
-      tp_handle_channels_context_fail (data->context, error);
+
+      if (data->context != NULL)
+        tp_handle_channels_context_fail (data->context, error);
 
       g_error_free (error);
     }
   else
     {
-      tp_handle_channels_context_accept (data->context);
+      if (data->context != NULL)
+        tp_handle_channels_context_accept (data->context);
 
       g_signal_connect (priv->sasl_handler, "invalidated",
           G_CALLBACK (sasl_handler_invalidated_cb), data->self);
@@ -163,26 +167,17 @@ server_sasl_handler_ready_cb (GObject *source,
   handler_context_data_free (data);
 }
 
-static void
-handle_channels_cb (TpSimpleHandler *handler,
-    TpAccount *account,
-    TpConnection *connection,
+static gboolean
+common_checks (EmpathyAuthFactory *self,
     GList *channels,
-    GList *requests_satisfied,
-    gint64 user_action_time,
-    TpHandleChannelsContext *context,
-    gpointer user_data)
+    gboolean must_be_sasl,
+    GError **error)
 {
-  TpChannel *channel;
-  const GError *dbus_error;
-  GError *error = NULL;
-  EmpathyAuthFactory *self = user_data;
   EmpathyAuthFactoryPriv *priv = GET_PRIV (self);
-  HandlerContextData *data;
+  TpChannel *channel;
   GHashTable *props;
   const gchar * const *available_mechanisms;
-
-  DEBUG ("Handle TLS or SASL carrier channels.");
+  const GError *dbus_error;
 
   /* there can't be more than one ServerTLSConnection or
    * ServerAuthentication channels at the same time, for the same
@@ -190,35 +185,38 @@ handle_channels_cb (TpSimpleHandler *handler,
    */
   if (g_list_length (channels) != 1)
     {
-      g_set_error_literal (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+      g_set_error_literal (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
           "Can't handle more than one ServerTLSConnection or ServerAuthentication "
           "channel for the same connection.");
 
-      goto error;
+      return FALSE;
     }
 
   channel = channels->data;
 
   if (tp_channel_get_channel_type_id (channel) !=
-      EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION
-      && tp_channel_get_channel_type_id (channel) !=
       TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION)
     {
-      g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
-          "Can only handle ServerTLSConnection or ServerAuthentication channels, "
-          "this was a %s channel", tp_channel_get_channel_type (channel));
-
-      goto error;
+      if (must_be_sasl
+          || tp_channel_get_channel_type_id (channel) !=
+          EMP_IFACE_QUARK_CHANNEL_TYPE_SERVER_TLS_CONNECTION)
+        {
+          g_set_error (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+              "Can only handle ServerTLSConnection or ServerAuthentication channels, "
+              "this was a %s channel", tp_channel_get_channel_type (channel));
+
+          return FALSE;
+        }
     }
 
   if (tp_channel_get_channel_type_id (channel) ==
       TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION
       && priv->sasl_handler != NULL)
     {
-      g_set_error_literal (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+      g_set_error_literal (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
           "Can't handle more than one ServerAuthentication channel at one time");
 
-      goto error;
+      return FALSE;
     }
 
   props = tp_channel_borrow_immutable_properties (channel);
@@ -230,20 +228,50 @@ handle_channels_cb (TpSimpleHandler *handler,
       TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION
       && !tp_strv_contains (available_mechanisms, "X-TELEPATHY-PASSWORD"))
     {
-      g_set_error_literal (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+      g_set_error_literal (error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
           "Only the X-TELEPATHY-PASSWORD SASL mechanism is supported");
 
-      goto error;
+      return FALSE;
     }
 
   dbus_error = tp_proxy_get_invalidated (channel);
 
   if (dbus_error != NULL)
     {
-      error = g_error_copy (dbus_error);
-      goto error;
+      *error = g_error_copy (dbus_error);
+      return FALSE;
     }
 
+  return TRUE;
+}
+
+static void
+handle_channels (TpBaseClient *handler,
+    TpAccount *account,
+    TpConnection *connection,
+    GList *channels,
+    GList *requests_satisfied,
+    gint64 user_action_time,
+    TpHandleChannelsContext *context)
+{
+  TpChannel *channel;
+  GError *error = NULL;
+  EmpathyAuthFactory *self = EMPATHY_AUTH_FACTORY (handler);
+  HandlerContextData *data;
+
+  DEBUG ("Handle TLS or SASL carrier channels.");
+
+  if (!common_checks (self, channels, FALSE, &error))
+    {
+      DEBUG ("Failed checks: %s", error->message);
+      tp_handle_channels_context_fail (context, error);
+      g_clear_error (&error);
+      return;
+    }
+
+  /* The common checks above have checked this is fine. */
+  channel = channels->data;
+
   data = handler_context_data_new (self, context);
   tp_handle_channels_context_delay (context);
 
@@ -260,11 +288,125 @@ handle_channels_cb (TpSimpleHandler *handler,
       empathy_server_sasl_handler_new_async (account, channel,
           server_sasl_handler_ready_cb, data);
     }
-  return;
+}
+
+typedef struct
+{
+  EmpathyAuthFactory *self;
+  TpObserveChannelsContext *context;
+  TpChannelDispatchOperation *dispatch_operation;
+  TpAccount *account;
+  TpChannel *channel;
+} ObserveChannelsData;
+
+static void
+observe_channels_data_free (ObserveChannelsData *data)
+{
+  g_object_unref (data->context);
+  g_object_unref (data->account);
+  g_object_unref (data->channel);
+  g_object_unref (data->dispatch_operation);
+  g_slice_free (ObserveChannelsData, data);
+}
+
+static void
+claim_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  ObserveChannelsData *data = user_data;
+  GError *error = NULL;
+
+  if (!tp_channel_dispatch_operation_claim_finish (
+          TP_CHANNEL_DISPATCH_OPERATION (source), result, &error))
+    {
+      DEBUG ("Failed to call Claim: %s", error->message);
+      g_clear_error (&error);
+    }
+  else
+    {
+      HandlerContextData *h_data;
+
+      DEBUG ("Claim called successfully");
+
+      h_data = handler_context_data_new (data->self, NULL);
+
+      empathy_server_sasl_handler_new_async (TP_ACCOUNT (data->account),
+          data->channel, server_sasl_handler_ready_cb, h_data);
+    }
 
- error:
-  tp_handle_channels_context_fail (context, error);
-  g_clear_error (&error);
+  observe_channels_data_free (data);
+}
+
+static void
+get_password_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  ObserveChannelsData *data = user_data;
+
+  if (empathy_keyring_get_password_finish (TP_ACCOUNT (source), result, NULL) == NULL)
+    {
+      /* We don't actually mind if this fails, just let the approver
+       * go ahead and take the channel. */
+
+      DEBUG ("We don't have a password for account %s, letting the event "
+          "manager approver take it", tp_proxy_get_object_path (source));
+
+      tp_observe_channels_context_accept (data->context);
+      observe_channels_data_free (data);
+    }
+  else
+    {
+      DEBUG ("We have a password for account %s, calling Claim",
+          tp_proxy_get_object_path (source));
+
+      tp_channel_dispatch_operation_claim_async (data->dispatch_operation,
+          claim_cb, data);
+
+      tp_observe_channels_context_accept (data->context);
+    }
+}
+
+static void
+observe_channels (TpBaseClient *client,
+    TpAccount *account,
+    TpConnection *connection,
+    GList *channels,
+    TpChannelDispatchOperation *dispatch_operation,
+    GList *requests,
+    TpObserveChannelsContext *context)
+{
+  EmpathyAuthFactory *self = EMPATHY_AUTH_FACTORY (client);
+  TpChannel *channel;
+  GError *error = NULL;
+  ObserveChannelsData *data;
+
+  DEBUG ("New auth channel to observe");
+
+  if (!common_checks (self, channels, TRUE, &error))
+    {
+      DEBUG ("Failed checks: %s", error->message);
+      tp_observe_channels_context_fail (context, error);
+      g_clear_error (&error);
+      return;
+    }
+
+  /* We're now sure this is a server auth channel using the SASL auth
+   * type and X-TELEPATHY-PASSWORD is available. Great. */
+
+  channel = channels->data;
+
+  data = g_slice_new0 (ObserveChannelsData);
+  data->self = self;
+  data->context = g_object_ref (context);
+  data->dispatch_operation = g_object_ref (dispatch_operation);
+  data->account = g_object_ref (account);
+  data->channel = g_object_ref (channel);
+
+  empathy_keyring_get_password_async (account, get_password_cb, data);
+
+  tp_observe_channels_context_delay (context);
 }
 
 static GObject *
@@ -293,14 +435,20 @@ empathy_auth_factory_constructor (GType type,
 static void
 empathy_auth_factory_init (EmpathyAuthFactory *self)
 {
-  EmpathyAuthFactoryPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
       EMPATHY_TYPE_AUTH_FACTORY, EmpathyAuthFactoryPriv);
-  TpDBusDaemon *bus;
+}
+
+static void
+empathy_auth_factory_constructed (GObject *obj)
+{
+  EmpathyAuthFactory *self = EMPATHY_AUTH_FACTORY (obj);
+  TpBaseClient *client = TP_BASE_CLIENT (self);
   GError *error = NULL;
 
-  self->priv = priv;
+  /* chain up to TpBaseClient first */
+  G_OBJECT_CLASS (empathy_auth_factory_parent_class)->constructed (obj);
 
-  bus = tp_dbus_daemon_dup (&error);
   if (error != NULL)
     {
       g_critical ("Failed to get TpDBusDaemon: %s", error->message);
@@ -308,10 +456,9 @@ empathy_auth_factory_init (EmpathyAuthFactory *self)
       return;
     }
 
-  priv->handler = tp_simple_handler_new (bus, FALSE, FALSE, "Empathy.Auth",
-      FALSE, handle_channels_cb, self, NULL);
+  tp_base_client_set_handler_bypass_approval (client, FALSE);
 
-  tp_base_client_take_handler_filter (priv->handler, tp_asv_new (
+  tp_base_client_take_handler_filter (client, tp_asv_new (
           /* ChannelType */
           TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
           EMP_IFACE_CHANNEL_TYPE_SERVER_TLS_CONNECTION,
@@ -319,7 +466,7 @@ empathy_auth_factory_init (EmpathyAuthFactory *self)
           TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
           TP_HANDLE_TYPE_NONE, NULL));
 
-  tp_base_client_take_handler_filter (priv->handler, tp_asv_new (
+  tp_base_client_take_handler_filter (client, tp_asv_new (
           /* ChannelType */
           TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
           TP_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION,
@@ -328,7 +475,14 @@ empathy_auth_factory_init (EmpathyAuthFactory *self)
           G_TYPE_STRING, TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
           NULL));
 
- g_object_unref (bus);
+  tp_base_client_take_observer_filter (client, tp_asv_new (
+          /* ChannelType */
+          TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
+          TP_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION,
+          /* AuthenticationMethod */
+          TP_PROP_CHANNEL_TYPE_SERVER_AUTHENTICATION_AUTHENTICATION_METHOD,
+          G_TYPE_STRING, TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
+          NULL));
 }
 
 static void
@@ -341,7 +495,6 @@ empathy_auth_factory_dispose (GObject *object)
 
   priv->dispose_run = TRUE;
 
-  tp_clear_object (&priv->handler);
   tp_clear_object (&priv->sasl_handler);
 
   G_OBJECT_CLASS (empathy_auth_factory_parent_class)->dispose (object);
@@ -351,10 +504,15 @@ static void
 empathy_auth_factory_class_init (EmpathyAuthFactoryClass *klass)
 {
   GObjectClass *oclass = G_OBJECT_CLASS (klass);
+  TpBaseClientClass *base_client_cls = TP_BASE_CLIENT_CLASS (klass);
 
   oclass->constructor = empathy_auth_factory_constructor;
+  oclass->constructed = empathy_auth_factory_constructed;
   oclass->dispose = empathy_auth_factory_dispose;
 
+  base_client_cls->handle_channels = handle_channels;
+  base_client_cls->observe_channels = observe_channels;
+
   g_type_class_add_private (klass, sizeof (EmpathyAuthFactoryPriv));
 
   signals[NEW_SERVER_TLS_HANDLER] =
@@ -379,14 +537,22 @@ empathy_auth_factory_class_init (EmpathyAuthFactoryClass *klass)
 EmpathyAuthFactory *
 empathy_auth_factory_dup_singleton (void)
 {
-  return g_object_new (EMPATHY_TYPE_AUTH_FACTORY, NULL);
+  EmpathyAuthFactory *out = NULL;
+  TpDBusDaemon *bus;
+
+  bus = tp_dbus_daemon_dup (NULL);
+  out = g_object_new (EMPATHY_TYPE_AUTH_FACTORY,
+      "dbus-daemon", bus,
+      "name", "Empathy.Auth",
+      NULL);
+  g_object_unref (bus);
+
+  return out;
 }
 
 gboolean
 empathy_auth_factory_register (EmpathyAuthFactory *self,
     GError **error)
 {
-  EmpathyAuthFactoryPriv *priv = GET_PRIV (self);
-
-  return tp_base_client_register (priv->handler, error);
+  return tp_base_client_register (TP_BASE_CLIENT (self), error);
 }
diff --git a/libempathy/empathy-auth-factory.h b/libempathy/empathy-auth-factory.h
index 507f69b..6f62a7a 100644
--- a/libempathy/empathy-auth-factory.h
+++ b/libempathy/empathy-auth-factory.h
@@ -23,17 +23,19 @@
 
 #include <glib-object.h>
 
+#include <telepathy-glib/base-client.h>
+
 G_BEGIN_DECLS
 
 typedef struct _EmpathyAuthFactory EmpathyAuthFactory;
 typedef struct _EmpathyAuthFactoryClass EmpathyAuthFactoryClass;
 
 struct _EmpathyAuthFactoryClass {
-    GObjectClass parent_class;
+    TpBaseClientClass parent_class;
 };
 
 struct _EmpathyAuthFactory {
-    GObject parent;
+    TpBaseClient parent;
     gpointer priv;
 };
 
diff --git a/src/empathy-event-manager.c b/src/empathy-event-manager.c
index 5516328..f657cae 100644
--- a/src/empathy-event-manager.c
+++ b/src/empathy-event-manager.c
@@ -76,6 +76,7 @@ typedef struct {
 
 typedef struct {
   TpBaseClient *approver;
+  TpBaseClient *auth_approver;
   EmpathyContactManager *contact_manager;
   GSList *events;
   /* Ongoing approvals */
@@ -170,6 +171,11 @@ event_free (EventPriv *event)
       g_object_unref (event->public.contact);
     }
 
+  if (event->public.account)
+    {
+      g_object_unref (event->public.account);
+    }
+
   g_slice_free (EventPriv, event);
 }
 
@@ -212,6 +218,7 @@ display_notify_area (EmpathyEventManager *self)
 
 static void
 event_manager_add (EmpathyEventManager *manager,
+    TpAccount *account,
     EmpathyContact *contact,
     EmpathyEventType type,
     const gchar *icon_name,
@@ -225,6 +232,7 @@ event_manager_add (EmpathyEventManager *manager,
   EventPriv               *event;
 
   event = g_slice_new0 (EventPriv);
+  event->public.account = account != NULL ? g_object_ref (account) : NULL;
   event->public.contact = contact ? g_object_ref (contact) : NULL;
   event->public.type = type;
   event->public.icon_name = g_strdup (icon_name);
@@ -421,11 +429,46 @@ out:
 }
 
 static void
+reject_auth_channel_claim_cb (GObject *source,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  TpChannelDispatchOperation *cdo = TP_CHANNEL_DISPATCH_OPERATION (source);
+  GError *error = NULL;
+
+  if (!tp_channel_dispatch_operation_claim_finish (cdo, result, &error))
+    {
+      DEBUG ("Failed to claim channel: %s", error->message);
+
+      g_error_free (error);
+      return;
+    }
+
+  tp_cli_channel_call_close (TP_CHANNEL (user_data), -1,
+      NULL, NULL, NULL, NULL);
+}
+
+static void
 reject_approval (EventManagerApproval *approval)
 {
   /* We have to claim the channel before closing it */
-  tp_channel_dispatch_operation_claim_async (approval->operation,
-      reject_channel_claim_cb, g_object_ref (approval->handler_instance));
+
+  /* Unfortunately, we need to special case the auth channels for the
+   * time being as they don't have a wrapper object handler in
+   * approval->handler_instance as they're not actually handled by
+   * this process, so we can just use a noddy callback to call Close()
+   * directly. */
+  if (approval->handler_instance != NULL)
+    {
+      tp_channel_dispatch_operation_claim_async (approval->operation,
+          reject_channel_claim_cb, g_object_ref (approval->handler_instance));
+    }
+  else if (tp_channel_get_channel_type_id (approval->main_channel)
+      == TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION)
+    {
+      tp_channel_dispatch_operation_claim_async (approval->operation,
+          reject_auth_channel_claim_cb, approval->main_channel);
+    }
 }
 
 static void
@@ -549,9 +592,9 @@ event_manager_chat_message_received_cb (EmpathyTpChat *tp_chat,
     event_update (approval->manager, event, EMPATHY_IMAGE_NEW_MESSAGE, header,
         msg);
   else
-    event_manager_add (approval->manager, sender, EMPATHY_EVENT_TYPE_CHAT,
-        EMPATHY_IMAGE_NEW_MESSAGE, header, msg, approval,
-        event_text_channel_process_func, NULL);
+    event_manager_add (approval->manager, NULL, sender,
+        EMPATHY_EVENT_TYPE_CHAT, EMPATHY_IMAGE_NEW_MESSAGE, header, msg,
+        approval, event_text_channel_process_func, NULL);
 
   empathy_sound_manager_play (priv->sound_mgr, window,
       EMPATHY_SOUND_CONVERSATION_NEW);
@@ -625,8 +668,8 @@ event_manager_media_channel_got_contact (EventManagerApproval *approval)
     video ? _("Incoming video call from %s") :_("Incoming call from %s"),
     empathy_contact_get_alias (approval->contact));
 
-  event_manager_add (approval->manager, approval->contact,
-      EMPATHY_EVENT_TYPE_VOIP,
+  event_manager_add (approval->manager, NULL,
+      approval->contact, EMPATHY_EVENT_TYPE_VOIP,
       video ? EMPATHY_IMAGE_VIDEO_CALL : EMPATHY_IMAGE_VOIP,
       header, NULL, approval,
       event_channel_process_voip_func, NULL);
@@ -758,9 +801,10 @@ display_invite_room_dialog (EventManagerApproval *approval)
           tp_channel_get_identifier (approval->main_channel));
     }
 
-  event_manager_add (approval->manager, approval->contact,
-      EMPATHY_EVENT_TYPE_INVITATION, EMPATHY_IMAGE_GROUP_MESSAGE, msg,
-      invite_msg, approval, event_room_channel_process_func, NULL);
+  event_manager_add (approval->manager, NULL,
+      approval->contact, EMPATHY_EVENT_TYPE_INVITATION,
+      EMPATHY_IMAGE_GROUP_MESSAGE, msg, invite_msg, approval,
+      event_room_channel_process_func, NULL);
 
   empathy_sound_manager_play (priv->sound_mgr, window,
       EMPATHY_SOUND_CONVERSATION_NEW);
@@ -807,8 +851,9 @@ event_manager_ft_got_contact_cb (TpConnection *connection,
   header = g_strdup_printf (_("Incoming file transfer from %s"),
                             empathy_contact_get_alias (approval->contact));
 
-  event_manager_add (approval->manager, approval->contact,
-      EMPATHY_EVENT_TYPE_TRANSFER, EMPATHY_IMAGE_DOCUMENT_SEND, header, NULL,
+  event_manager_add (approval->manager, NULL,
+      approval->contact, EMPATHY_EVENT_TYPE_TRANSFER,
+      EMPATHY_IMAGE_DOCUMENT_SEND, header, NULL,
       approval, event_channel_process_func, NULL);
 
   /* FIXME better sound for incoming file transfers ?*/
@@ -819,8 +864,14 @@ event_manager_ft_got_contact_cb (TpConnection *connection,
   g_object_unref (window);
 }
 
-/* If there is a file-transfer or media channel consider it as the
- * main one. */
+static void
+event_manager_auth_process_func (EventPriv *event)
+{
+  empathy_event_approve ((EmpathyEvent *) event);
+}
+
+/* If there is a file-transfer, media, or auth channel consider it as
+ * the main one. */
 static TpChannel *
 find_main_channel (GList *channels)
 {
@@ -838,7 +889,8 @@ find_main_channel (GList *channels)
       channel_type = tp_channel_get_channel_type_id (channel);
 
       if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_STREAMED_MEDIA ||
-          channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER)
+          channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_FILE_TRANSFER ||
+          channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION)
         return channel;
 
       else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
@@ -962,6 +1014,13 @@ approve_channels (TpSimpleApprover *approver,
       empathy_tp_contact_factory_get_from_handle (connection, handle,
         event_manager_ft_got_contact_cb, approval, NULL, G_OBJECT (self));
     }
+  else if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_SERVER_AUTHENTICATION)
+    {
+      event_manager_add (approval->manager, account, NULL, EMPATHY_EVENT_TYPE_AUTH,
+          GTK_STOCK_DIALOG_AUTHENTICATION, tp_account_get_display_name (account),
+          _("Password required"), approval,
+          event_manager_auth_process_func, NULL);
+    }
   else
     {
       GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
@@ -1023,7 +1082,7 @@ event_manager_pendings_changed_cb (EmpathyContactList  *list,
   else
     event_msg = NULL;
 
-  event_manager_add (manager, contact, EMPATHY_EVENT_TYPE_SUBSCRIPTION,
+  event_manager_add (manager, NULL, contact, EMPATHY_EVENT_TYPE_SUBSCRIPTION,
       GTK_STOCK_DIALOG_QUESTION, header, event_msg, NULL,
       event_pending_subscribe_func, NULL);
 
@@ -1066,7 +1125,7 @@ event_manager_presence_changed_cb (EmpathyContact *contact,
               header = g_strdup_printf (_("%s is now offline."),
                   empathy_contact_get_alias (contact));
 
-              event_manager_add (manager, contact, EMPATHY_EVENT_TYPE_PRESENCE,
+              event_manager_add (manager, NULL, contact, EMPATHY_EVENT_TYPE_PRESENCE,
                   EMPATHY_IMAGE_AVATAR_DEFAULT, header, NULL, NULL, NULL, NULL);
             }
         }
@@ -1087,7 +1146,7 @@ event_manager_presence_changed_cb (EmpathyContact *contact,
               header = g_strdup_printf (_("%s is now online."),
                   empathy_contact_get_alias (contact));
 
-              event_manager_add (manager, contact, EMPATHY_EVENT_TYPE_PRESENCE,
+              event_manager_add (manager, NULL, contact, EMPATHY_EVENT_TYPE_PRESENCE,
                   EMPATHY_IMAGE_AVATAR_DEFAULT, header, NULL, NULL, NULL, NULL);
             }
         }
@@ -1150,6 +1209,7 @@ event_manager_finalize (GObject *object)
   g_slist_free (priv->approvals);
   g_object_unref (priv->contact_manager);
   g_object_unref (priv->approver);
+  g_object_unref (priv->auth_approver);
   g_object_unref (priv->gsettings_notif);
   g_object_unref (priv->gsettings_ui);
   g_object_unref (priv->sound_mgr);
@@ -1191,7 +1251,6 @@ empathy_event_manager_class_init (EmpathyEventManagerClass *klass)
       g_cclosure_marshal_VOID__POINTER,
       G_TYPE_NONE, 1, G_TYPE_POINTER);
 
-
   g_type_class_add_private (object_class, sizeof (EmpathyEventManagerPriv));
 }
 
@@ -1262,12 +1321,41 @@ empathy_event_manager_init (EmpathyEventManager *manager)
         TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
         NULL));
 
+  /* I don't feel good about doing this, and I'm sorry, but the
+   * capabilities connection feature is added earlier because it's
+   * needed for EmpathyTpChat. If the capabilities feature is required
+   * then preparing an auth channel (which of course appears in the
+   * CONNECTING state) will never be prepared. So the options are
+   * either to create another approver like I've done, or to port
+   * EmpathyTpChat and its users to not depend on the connection being
+   * prepared with capabilities. I chose the former, obviously. :-) */
+
+  priv->auth_approver = tp_simple_approver_new (dbus,
+      "Empathy.AuthEventManager", FALSE, approve_channels, manager,
+      NULL);
+
+  /* SASL auth channels */
+  tp_base_client_take_approver_filter (priv->auth_approver,
+      tp_asv_new (
+        TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
+          TP_IFACE_CHANNEL_TYPE_SERVER_AUTHENTICATION,
+        TP_PROP_CHANNEL_TYPE_SERVER_AUTHENTICATION_AUTHENTICATION_METHOD,
+          G_TYPE_STRING,
+          TP_IFACE_CHANNEL_INTERFACE_SASL_AUTHENTICATION,
+        NULL));
+
   if (!tp_base_client_register (priv->approver, &error))
     {
       DEBUG ("Failed to register Approver: %s", error->message);
       g_error_free (error);
     }
 
+  if (!tp_base_client_register (priv->auth_approver, &error))
+    {
+      DEBUG ("Failed to register auth Approver: %s", error->message);
+      g_error_free (error);
+    }
+
   g_object_unref (dbus);
 }
 
diff --git a/src/empathy-event-manager.h b/src/empathy-event-manager.h
index cc81d2d..16d97c6 100644
--- a/src/empathy-event-manager.h
+++ b/src/empathy-event-manager.h
@@ -55,9 +55,11 @@ typedef enum {
     EMPATHY_EVENT_TYPE_SUBSCRIPTION,
     EMPATHY_EVENT_TYPE_PRESENCE,
     EMPATHY_EVENT_TYPE_INVITATION,
+    EMPATHY_EVENT_TYPE_AUTH,
 } EmpathyEventType;
 
 typedef struct {
+    TpAccount *account;
     EmpathyContact *contact;
     EmpathyEventType type;
     gchar *icon_name;
diff --git a/src/empathy-main-window.c b/src/empathy-main-window.c
index db5818c..e04a6bb 100644
--- a/src/empathy-main-window.c
+++ b/src/empathy-main-window.c
@@ -122,6 +122,7 @@ struct _EmpathyMainWindowPriv {
 	GtkWidget              *presence_toolbar;
 	GtkWidget              *presence_chooser;
 	GtkWidget              *errors_vbox;
+	GtkWidget              *auth_vbox;
 	GtkWidget              *search_bar;
 	GtkWidget              *notebook;
 	GtkWidget              *no_entry_label;
@@ -143,6 +144,7 @@ struct _EmpathyMainWindowPriv {
 
 	guint                   size_timeout_id;
 	GHashTable             *errors;
+	GHashTable             *auths;
 
 	/* stores a mapping from TpAccount to Handler ID to prevent
 	 * to listen more than once to the status-changed signal */
@@ -286,12 +288,146 @@ main_window_flash_start (EmpathyMainWindow *window)
 }
 
 static void
+main_window_remove_auth (EmpathyMainWindow *window,
+			 EmpathyEvent      *event)
+{
+	EmpathyMainWindowPriv *priv = GET_PRIV (window);
+	GtkWidget *error_widget;
+
+	error_widget = g_hash_table_lookup (priv->auths, event);
+	if (error_widget != NULL) {
+		gtk_widget_destroy (error_widget);
+		g_hash_table_remove (priv->auths, event);
+	}
+}
+
+static void
+main_window_auth_add_clicked_cb (GtkButton         *button,
+				 EmpathyMainWindow *window)
+{
+	EmpathyEvent *event;
+
+	event = g_object_get_data (G_OBJECT (button), "event");
+
+	empathy_event_approve (event);
+
+	main_window_remove_auth (window, event);
+}
+
+static void
+main_window_auth_close_clicked_cb (GtkButton         *button,
+				   EmpathyMainWindow *window)
+{
+	EmpathyEvent *event;
+
+	event = g_object_get_data (G_OBJECT (button), "event");
+
+	empathy_event_decline (event);
+	main_window_remove_auth (window, event);
+}
+
+static void
+main_window_auth_display (EmpathyMainWindow *window,
+			  EmpathyEvent      *event)
+{
+	EmpathyMainWindowPriv *priv = GET_PRIV (window);
+	TpAccount *account = event->account;
+	GtkWidget *info_bar;
+	GtkWidget *content_area;
+	GtkWidget *image;
+	GtkWidget *label;
+	GtkWidget *add_button;
+	GtkWidget *close_button;
+	GtkWidget *action_area;
+	GtkWidget *action_table;
+	const gchar *icon_name;
+	gchar *str;
+
+	if (g_hash_table_lookup (priv->auths, event) != NULL) {
+		return;
+	}
+
+	info_bar = gtk_info_bar_new ();
+	gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar), GTK_MESSAGE_QUESTION);
+
+	gtk_widget_set_no_show_all (info_bar, TRUE);
+	gtk_box_pack_start (GTK_BOX (priv->auth_vbox), info_bar, FALSE, TRUE, 0);
+	gtk_widget_show (info_bar);
+
+	icon_name = tp_account_get_icon_name (account);
+	image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_SMALL_TOOLBAR);
+	gtk_widget_show (image);
+
+	str = g_markup_printf_escaped ("<b>%s</b>\n%s",
+				       tp_account_get_display_name (account),
+				       _("Password required"));
+
+	label = gtk_label_new (str);
+	gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+	gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+	gtk_widget_show (label);
+
+	g_free (str);
+
+	content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar));
+	gtk_box_pack_start (GTK_BOX (content_area), image, FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (content_area), label, TRUE, TRUE, 0);
+
+	image = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON);
+	add_button = gtk_button_new ();
+	gtk_button_set_image (GTK_BUTTON (add_button), image);
+	gtk_widget_set_tooltip_text (add_button, _("Provide Password"));
+	gtk_widget_show (add_button);
+
+	image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_BUTTON);
+	close_button = gtk_button_new ();
+	gtk_button_set_image (GTK_BUTTON (close_button), image);
+	gtk_widget_set_tooltip_text (close_button, _("Cancel"));
+	gtk_widget_show (close_button);
+
+	action_table = gtk_table_new (1, 2, FALSE);
+	gtk_table_set_col_spacings (GTK_TABLE (action_table), 6);
+	gtk_widget_show (action_table);
+
+	action_area = gtk_info_bar_get_action_area (GTK_INFO_BAR (info_bar));
+	gtk_box_pack_start (GTK_BOX (action_area), action_table, FALSE, FALSE, 0);
+
+	gtk_table_attach (GTK_TABLE (action_table), add_button, 0, 1, 0, 1,
+			  (GtkAttachOptions) (GTK_SHRINK),
+			  (GtkAttachOptions) (GTK_SHRINK), 0, 0);
+	gtk_table_attach (GTK_TABLE (action_table), close_button, 1, 2, 0, 1,
+			  (GtkAttachOptions) (GTK_SHRINK),
+			  (GtkAttachOptions) (GTK_SHRINK), 0, 0);
+
+	g_object_set_data_full (G_OBJECT (info_bar),
+				"event", event, NULL);
+	g_object_set_data_full (G_OBJECT (add_button),
+				"event", event, NULL);
+	g_object_set_data_full (G_OBJECT (close_button),
+				"event", event, NULL);
+
+	g_signal_connect (add_button, "clicked",
+			  G_CALLBACK (main_window_auth_add_clicked_cb),
+			  window);
+	g_signal_connect (close_button, "clicked",
+			  G_CALLBACK (main_window_auth_close_clicked_cb),
+			  window);
+
+	gtk_widget_show (priv->auth_vbox);
+
+	g_hash_table_insert (priv->auths, event, info_bar);
+}
+
+static void
 main_window_event_added_cb (EmpathyEventManager *manager,
 			    EmpathyEvent        *event,
 			    EmpathyMainWindow   *window)
 {
 	if (event->contact) {
 		main_window_flash_start (window);
+	} else if (event->type == EMPATHY_EVENT_TYPE_AUTH) {
+		main_window_auth_display (window, event);
 	}
 }
 
@@ -303,6 +439,11 @@ main_window_event_removed_cb (EmpathyEventManager *manager,
 	EmpathyMainWindowPriv *priv = GET_PRIV (window);
 	FlashForeachData data;
 
+	if (event->type == EMPATHY_EVENT_TYPE_AUTH) {
+		main_window_remove_auth (window, event);
+		return;
+	}
+
 	if (!event->contact) {
 		return;
 	}
@@ -711,6 +852,7 @@ empathy_main_window_finalize (GObject *window)
 	g_object_unref (priv->contact_manager);
 	g_object_unref (priv->sound_mgr);
 	g_hash_table_destroy (priv->errors);
+	g_hash_table_destroy (priv->auths);
 
 	/* disconnect all handlers of status-changed signal */
 	g_hash_table_iter_init (&iter, priv->status_changed_handlers);
@@ -1591,6 +1733,7 @@ empathy_main_window_init (EmpathyMainWindow *window)
 	gui = empathy_builder_get_file (filename,
 				       "main_vbox", &priv->main_vbox,
 				       "errors_vbox", &priv->errors_vbox,
+				       "auth_vbox", &priv->auth_vbox,
 				       "ui_manager", &priv->ui_manager,
 				       "view_show_offline", &show_offline_widget,
 				       "view_show_protocols", &priv->show_protocols,
@@ -1660,6 +1803,11 @@ empathy_main_window_init (EmpathyMainWindow *window)
 					      g_object_unref,
 					      NULL);
 
+	priv->auths = g_hash_table_new_full (g_direct_hash,
+					     g_direct_equal,
+					     NULL,
+					     NULL);
+
 	priv->status_changed_handlers = g_hash_table_new_full (g_direct_hash,
 							       g_direct_equal,
 							       NULL,
diff --git a/src/empathy-main-window.ui b/src/empathy-main-window.ui
index 8356a1a..e684c6b 100644
--- a/src/empathy-main-window.ui
+++ b/src/empathy-main-window.ui
@@ -309,6 +309,18 @@
           </packing>
         </child>
         <child>
+          <object class="GtkVBox" id="auth_vbox">
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
           <object class="GtkNotebook" id="notebook">
             <property name="visible">True</property>
             <property name="can_focus">True</property>
@@ -340,7 +352,7 @@
             </child>
           </object>
           <packing>
-            <property name="position">3</property>
+            <property name="position">4</property>
           </packing>
         </child>
       </object>
diff --git a/src/empathy-notifications-approver.c b/src/empathy-notifications-approver.c
index 0bfe032..e0d540c 100644
--- a/src/empathy-notifications-approver.c
+++ b/src/empathy-notifications-approver.c
@@ -314,7 +314,11 @@ event_added_cb (EmpathyEventManager *manager,
   if (self->priv->event != NULL)
     return;
 
+  if (event->type == EMPATHY_EVENT_TYPE_AUTH)
+    return;
+
   self->priv->event = event;
+
   update_notification (self);
 }
 
@@ -326,6 +330,9 @@ event_removed_cb (EmpathyEventManager *manager,
   if (event != self->priv->event)
     return;
 
+  if (event->type == EMPATHY_EVENT_TYPE_AUTH)
+    return;
+
   self->priv->event = empathy_event_manager_get_top_event (
       self->priv->event_mgr);
 
@@ -340,6 +347,9 @@ event_updated_cb (EmpathyEventManager *manager,
   if (event != self->priv->event)
     return;
 
+  if (event->type == EMPATHY_EVENT_TYPE_AUTH)
+    return;
+
   if (empathy_notify_manager_notification_is_enabled (self->priv->notify_mgr))
     update_notification (self);
 }
diff --git a/src/empathy-status-icon.c b/src/empathy-status-icon.c
index 0c834a6..38a68d4 100644
--- a/src/empathy-status-icon.c
+++ b/src/empathy-status-icon.c
@@ -159,7 +159,7 @@ status_icon_event_added_cb (EmpathyEventManager *manager,
 	DEBUG ("New event %p", event);
 
 	priv->event = event;
-	if (event->must_ack) {
+	if (event->must_ack || event->type == EMPATHY_EVENT_TYPE_AUTH) {
 		priv->showing_event_icon = TRUE;
 		status_icon_update_icon (icon);
 		status_icon_update_tooltip (icon);
