Created
August 6, 2022 10:40
-
-
Save alfonsrv/4f610f847d24274ea831b1a3bf91950f to your computer and use it in GitHub Desktop.
Microsoft 365 XOAuth IMAP – create token and test login
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import base64 | |
import imaplib | |
from time import sleep | |
from typing import Union, Tuple | |
import requests | |
MAIL = '[email protected]' | |
SERVER = 'outlook.office365.com' # used for IMAP Auth | |
AUTH_URL = 'https://login.microsoftonline.com' # OAuth2 endpoint | |
# Simply register your own Azure Enterprise App in your tenant with the scopes | |
# below (offline_access imap.accessasuser.all) + enable "Allow public client flows" | |
CLIENT_ID = '' # Your Azure AD client ID | |
def test_imap(auth_string: str) -> None: | |
imap_conn = imaplib.IMAP4_SSL(SERVER) | |
imap_conn.debug = 10 | |
imap_conn.authenticate('XOAUTH2', lambda x: auth_string.encode()) | |
imap_conn.select('INBOX') | |
imap_conn.list() | |
def generate_xoauth2(username: str, access_token: str, base64_encode: bool = True) -> Union[bytes, str]: | |
""" Generates XOauth2 String """ | |
auth_string = f'user={username}\1auth=Bearer {access_token}\1\1' | |
if base64_encode: auth_string = base64.b64encode(auth_string.encode()).decode() | |
return auth_string | |
def device_auth_initiate() -> str: | |
data = { | |
'scope': 'offline_access https://outlook.office.com/IMAP.AccessAsUser.All', | |
'client_id': CLIENT_ID | |
} | |
r = requests.post(f'{AUTH_URL}/common/oauth2/v2.0/devicecode', data=data) | |
response = r.json() | |
print(response.get('message')) | |
return response.get('device_code') | |
def device_auth_acquire(device_code: str) -> Tuple[str, str]: | |
""" Polls M365 backend for successful device authentication of the user | |
and returns the current OAuth2 Token + Refresh Token """ | |
data = { | |
'grant_type': 'urn:ietf:params:oauth:grant-type:device_code', | |
'code': device_code, | |
'client_id': CLIENT_ID | |
} | |
while True: | |
print('Polling M365 Graph API for successful authentication...') | |
r = requests.post(f'{AUTH_URL}/common/oauth2/v2.0/token', data=data) | |
response = r.json() | |
if response.get('refresh_token'): | |
print('Successfully authenticated M365 user!') | |
return response.get('access_token'), response.get('refresh_token') | |
sleep(10) | |
if __name__ == '__main__': | |
device_code = device_auth_initiate() | |
access_token, _ = device_auth_acquire(device_code) | |
print(f'OAuth2 token: {access_token}') | |
auth_string = generate_xoauth2( | |
username=MAIL, | |
access_token=access_token, | |
base64_encode=False | |
) | |
# print(auth_string) | |
test_imap(auth_string) | |
print('Authentication successful') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment