diff --git a/src/common/config.py b/src/common/config.py
index 75cc1a13d3d2635f6e8896fc61084c9ba4d16690..7de2de3e3cf5b094a5b387297c16b6d768b7c338 100644
--- a/src/common/config.py
+++ b/src/common/config.py
@@ -384,6 +384,9 @@ class Config:
                     'last_archiving_time': [opt_str, '1970-01-01T00:00:00Z', _('Last time we syncronized with logs from server.')],
                     'enable_message_carbons': [ opt_bool, False, _('If enabled and if server supports this feature, Gajim will receive messages sent and received by other resources.')],
                     'ft_send_local_ips': [ opt_bool, True, _('If enabled, Gajim will send your local IPs so your contact can connect to your machine to transfer files.')],
+                    'oauth2_refresh_token': [ opt_str, '', _('Latest token for Oauth2 authentication.')],
+                    'oauth2_client_id': [ opt_str, '0000000044077801', _('client_id for Oauth2 authentication.')],
+                    'oauth2_redirect_url': [ opt_str, 'http%3A%2F%2Fgajim.org%2Fmsnauth%2Findex.cgi', _('redirect_url for Oauth2 authentication.')],
             }, {}),
             'statusmsg': ({
                     'message': [ opt_str, '' ],
diff --git a/src/common/connection.py b/src/common/connection.py
index 2067be7f0bd958eaf8ee1267463fc430a709fb6f..2eaf4a2dc31aca2f1dcff2d65b6ff932beaa9bde 100644
--- a/src/common/connection.py
+++ b/src/common/connection.py
@@ -40,6 +40,7 @@ import operator
 import time
 import locale
 import hmac
+import json
 
 try:
     randomsource = random.SystemRandom()
@@ -2492,6 +2493,32 @@ class Connection(CommonConnection, ConnectionHandlers):
 
     def get_password(self, callback, type_):
         self.pasword_callback = (callback, type_)
+        if type_ == 'X-MESSENGER-OAUTH2':
+            client_id = gajim.config.get_per('accounts', self.name,
+                'oauth2_client_id')
+            refresh_token = gajim.config.get_per('accounts', self.name,
+                'oauth2_refresh_token')
+            if refresh_token:
+                renew_URL = 'https://oauth.live.com/token?client_id=' \
+                    '%(client_id)s&redirect_uri=https%%3A%%2F%%2Foauth.live.' \
+                    'com%%2Fdesktop&grant_type=refresh_token&refresh_token=' \
+                    '%(refresh_token)s' % locals()
+                result = helpers.download_image(self.name, {'src': renew_URL})[0]
+                if result:
+                    dict_ = json.loads(result)
+                    if 'access_token' in dict_:
+                        self.set_password(dict_['access_token'])
+                        return
+            script_url = gajim.config.get_per('accounts', self.name,
+                'oauth2_redirect_url')
+            token_URL = 'https://oauth.live.com/authorize?client_id=' \
+                '%(client_id)s&scope=wl.messenger%%20wl.offline_access&' \
+                'response_type=code&redirect_uri=%(script_url)s' % locals()
+            helpers.launch_browser_mailer('url', token_URL)
+            self.disconnect(on_purpose=True)
+            gajim.nec.push_incoming_event(Oauth2CredentialsRequiredEvent(None,
+                conn=self))
+            return
         if self.password:
             self.set_password(self.password)
             return
diff --git a/src/common/connection_handlers_events.py b/src/common/connection_handlers_events.py
index 99e0617dcd854a5391c6ceb08eadf3fb8e94091d..28068a8122a67ed4522ade2e8a231948afb07e2e 100644
--- a/src/common/connection_handlers_events.py
+++ b/src/common/connection_handlers_events.py
@@ -1783,6 +1783,10 @@ class PasswordRequiredEvent(nec.NetworkIncomingEvent):
     name = 'password-required'
     base_network_events = []
 
+class Oauth2CredentialsRequiredEvent(nec.NetworkIncomingEvent):
+    name = 'oauth2-credentials-required'
+    base_network_events = []
+
 class FailedDecryptEvent(nec.NetworkIncomingEvent):
     name = 'failed-decrypt'
     base_network_events = []
diff --git a/src/common/xmpp/auth_nb.py b/src/common/xmpp/auth_nb.py
index dd7d13097ab0be72b2c6784d5076b69b9984393d..1063ed9a75adbac1dbfaffb1f3b8012d65242ebd 100644
--- a/src/common/xmpp/auth_nb.py
+++ b/src/common/xmpp/auth_nb.py
@@ -264,6 +264,12 @@ class SASL(PlugIn):
             self._owner._caller.get_password(self.set_password, self.mechanism)
             self.startsasl = SASL_IN_PROCESS
             raise NodeProcessed
+        if 'X-MESSENGER-OAUTH2' in self.mecs:
+            self.mecs.remove('X-MESSENGER-OAUTH2')
+            self.mechanism = 'X-MESSENGER-OAUTH2'
+            self._owner._caller.get_password(self.set_password, self.mechanism)
+            self.startsasl = SASL_IN_PROCESS
+            raise NodeProcessed
         self.startsasl = SASL_FAILURE
         log.info('I can only use EXTERNAL, SCRAM-SHA-1, DIGEST-MD5, GSSAPI and '
             'PLAIN mecanisms.')
@@ -497,6 +503,10 @@ class SASL(PlugIn):
                 '\n', '')
             node = Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'PLAIN'},
                 payload=[sasl_data])
+        elif self.mechanism == 'X-MESSENGER-OAUTH2':
+            node = Node('auth', attrs={'xmlns': NS_SASL,
+                'mechanism': 'X-MESSENGER-OAUTH2'})
+            node.addData(password)
         self._owner.send(str(node))
 
 
diff --git a/src/dialogs.py b/src/dialogs.py
index 5e348eeff910a52ac8330fbb8ca2a373ac6cc2a5..647b6f96b09088204fdabdf53569bf57309e9ee4 100644
--- a/src/dialogs.py
+++ b/src/dialogs.py
@@ -2165,6 +2165,7 @@ class DoubleInputDialog:
     def on_okbutton_clicked(self, widget):
         user_input1 = self.input_entry1.get_text().decode('utf-8')
         user_input2 = self.input_entry2.get_text().decode('utf-8')
+        self.cancel_handler = None
         self.dialog.destroy()
         if not self.ok_handler:
             return
diff --git a/src/gajim.py b/src/gajim.py
index 4042f031aa6b2d586f32f4b3a8e216869b78233f..e02a1a8f47d7f252d161d3a4e0a6cddf53a5ec82 100644
--- a/src/gajim.py
+++ b/src/gajim.py
@@ -63,7 +63,7 @@ if os.name == 'nt':
         os.environ['PATH'] = ';'.join(new_list)
 
 from common import demandimport
-#demandimport.enable()
+demandimport.enable()
 demandimport.ignore += ['gobject._gobject', 'libasyncns', 'i18n',
     'logging.NullHandler', 'dbus.glib', 'dbus.service',
     'command_system.implementation.standard',
diff --git a/src/gui_interface.py b/src/gui_interface.py
index 13ce60d7efdae8a3590987a0221fc4de19f15830..00852f2d061086af44a9344cfab882b50f1598f7 100644
--- a/src/gui_interface.py
+++ b/src/gui_interface.py
@@ -701,6 +701,30 @@ class Interface:
             _('Password Required'), text, _('Save password'), ok_handler=on_ok,
             cancel_handler=on_cancel)
 
+    def handle_oauth2_credentials(self, obj):
+        account = obj.conn.name
+        def on_ok(refresh):
+            gajim.config.set_per('accounts', account, 'oauth2_refresh_token',
+                refresh)
+            st = gajim.config.get_per('accounts', account, 'last_status')
+            msg = helpers.from_one_line(gajim.config.get_per('accounts',
+                account, 'last_status_msg'))
+            gajim.interface.roster.send_status(account, st, msg)
+            del self.pass_dialog[account]
+
+        def on_cancel():
+            gajim.config.set_per('accounts', account, 'oauth2_refresh_token',
+                '')
+            self.roster.set_state(account, 'offline')
+            self.roster.update_status_combobox()
+            del self.pass_dialog[account]
+
+        instruction = _('Please copy / paste the refresh token from the website'
+            ' that has just been opened.')
+        self.pass_dialog[account] = dialogs.InputTextDialog(
+            _('Oauth2 Credentials'), instruction, is_modal=False,
+            ok_handler=on_ok, cancel_handler=on_cancel)
+
     def handle_event_roster_info(self, obj):
         #('ROSTER_INFO', account, (jid, name, sub, ask, groups))
         account = obj.conn.name
@@ -1412,6 +1436,7 @@ class Interface:
             'metacontacts-received': [self.handle_event_metacontacts],
             'muc-admin-received': [self.handle_event_gc_affiliation],
             'muc-owner-received': [self.handle_event_gc_config],
+            'oauth2-credentials-required': [self.handle_oauth2_credentials],
             'our-show': [self.handle_event_status],
             'password-required': [self.handle_event_password_required],
             'plain-connection': [self.handle_event_plain_connection],