59 lines
2 KiB
Python
Executable file
59 lines
2 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Microsoft Graph OAuth authentication (device code flow)."""
|
|
|
|
import msal
|
|
import json
|
|
import os
|
|
|
|
TOKEN_FILE = os.path.expanduser("~/.config/microsoft-graph-tokens.json")
|
|
CLIENT_ID = "14d82eec-204b-4c2f-b7e8-296a70dab67e"
|
|
SCOPES = [
|
|
"https://graph.microsoft.com/Mail.Read",
|
|
"https://graph.microsoft.com/Mail.ReadWrite",
|
|
"https://graph.microsoft.com/Mail.Send",
|
|
"https://graph.microsoft.com/Files.Read",
|
|
"https://graph.microsoft.com/Files.ReadWrite",
|
|
"https://graph.microsoft.com/User.Read"
|
|
]
|
|
|
|
def main():
|
|
app = msal.PublicClientApplication(CLIENT_ID, authority="https://login.microsoftonline.com/consumers")
|
|
|
|
flow = app.initiate_device_flow(scopes=SCOPES)
|
|
|
|
if "user_code" not in flow:
|
|
print(f"❌ Failed to create device flow: {flow}")
|
|
return
|
|
|
|
print("\n🔐 Microsoft Sign-In Required\n")
|
|
print(f"1. Go to: {flow['verification_uri']}")
|
|
print(f"2. Enter code: {flow['user_code']}")
|
|
print("3. Sign in with your Microsoft account\n")
|
|
print("Waiting for authorization...")
|
|
|
|
result = app.acquire_token_by_device_flow(flow)
|
|
|
|
if "access_token" in result:
|
|
tokens = {
|
|
"access_token": result["access_token"],
|
|
"refresh_token": result.get("refresh_token"),
|
|
"id_token": result.get("id_token"),
|
|
"expires_in": result.get("expires_in"),
|
|
"client_id": CLIENT_ID,
|
|
"scopes": SCOPES,
|
|
"account": result.get("id_token_claims", {}).get("preferred_username", "unknown")
|
|
}
|
|
|
|
os.makedirs(os.path.dirname(TOKEN_FILE), exist_ok=True)
|
|
with open(TOKEN_FILE, "w") as f:
|
|
json.dump(tokens, f, indent=2)
|
|
|
|
print(f"\n✅ Authorization successful!")
|
|
print(f"Account: {tokens['account']}")
|
|
print(f"Token saved to: {TOKEN_FILE}")
|
|
else:
|
|
print(f"\n❌ Error: {result.get('error')}")
|
|
print(f"Description: {result.get('error_description')}")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|