Skip to content

Instantly share code, notes, and snippets.

@alfonsrv
Created August 6, 2022 10:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alfonsrv/4f610f847d24274ea831b1a3bf91950f to your computer and use it in GitHub Desktop.
Save alfonsrv/4f610f847d24274ea831b1a3bf91950f to your computer and use it in GitHub Desktop.
Microsoft 365 XOAuth IMAP – create token and test login
import base64
import imaplib
from time import sleep
from typing import Union, Tuple
import requests
MAIL = 'migrate@domain.tld'
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