2025, Nov 24 09:00
How to Create Outlook Mailbox Rules via Microsoft Graph for Personal Accounts: Avoid ROPC and Fix AADSTS50034
Getting AADSTS50034 adding Outlook mailbox rules with Microsoft Graph? See why ROPC fails for personal accounts and how Auth Code Flow returns a refresh token.
When you try to add Outlook mailbox rules through Microsoft Graph for personal Outlook accounts, it’s tempting to exchange username and password directly for a token or to reuse an existing refresh token from another client. That path often leads to the AADSTS50034 error and dead ends. Here’s why it happens and a straightforward way to get a working refresh token and create rules reliably.
What goes wrong
The attempt below uses the Resource Owner Password Credentials (ROPC) flow against a tenant-specific token endpoint. For a personal Outlook account that doesn’t belong to your Azure AD tenant, this fails with a directory lookup error.
The user account {EUII Hidden} does not exist in the a7163cca-35ea-483a-837e-ae68f9820cff directory. To sign into this application, the account must be added to the directory.
In other words, the token endpoint scoped to a specific tenant only authenticates users in that tenant. Even when pointed at /common or /consumers, ROPC is no longer supported for certain flows, especially for personal accounts. That means you need the Authorization Code Flow to get the first refresh token interactively, then you can automate afterward.
Problem demonstration
This is the pattern that triggers AADSTS50034 when the account is a personal Outlook identity and the endpoint is tenant-scoped.
import requests
def ropc_token_exchange(dir_guid, app_client_id, app_client_secret, user_login, user_pwd):
token_endpoint = f"https://login.microsoftonline.com/{dir_guid}/oauth2/v2.0/token"
form = {
"grant_type": "password",
"client_id": app_client_id,
"client_secret": app_client_secret,
"scope": "https://graph.microsoft.com/.default",
"username": user_login,
"password": user_pwd
}
res = requests.post(token_endpoint, data=form)
return res.json()
reply = ropc_token_exchange(
dir_guid=TENANT_GUID,
app_client_id=APP_ID,
app_client_secret=APP_SECRET,
user_login="JobyTrible235@outlook.com",
user_pwd="5Bfhac7yKB"
)
Previously, a nonstandard username/password flow against the live.com and common endpoints might have yielded an access token. That approach stopped working and isn’t a supported path to obtain refresh tokens for personal accounts.
Why it fails
The personal Outlook account isn’t part of your Azure AD tenant, so a tenant-specific token endpoint can’t find or authenticate it. ROPC is additionally restricted and not supported for certain flows, particularly for personal accounts. As a result, you can’t bootstrap a refresh token this way.
The fix: interactive Authorization Code Flow, then automate
The correct approach is to perform a one-time interactive sign-in with the Authorization Code Flow to obtain the initial refresh token with the scopes you need. After that, you can use the refresh token to get access tokens and call Microsoft Graph to create mailbox rules.
import requests
import webbrowser
import threading
from flask import Flask, request
# Application values
APP_CLIENT_ID = "client_id_of your_app"
APP_CLIENT_SECRET = "client_secret"
LOCAL_REDIRECT = "http://localhost:8000/callback"
REQ_SCOPES = "offline_access Mail.ReadWrite MailboxSettings.ReadWrite"
authorize_page = (
f"https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
f"?client_id={APP_CLIENT_ID}"
f"&response_type=code"
f"&redirect_uri={LOCAL_REDIRECT}"
f"&response_mode=query"
f"&scope={REQ_SCOPES}"
f"&state=12345"
)
# Local endpoint to capture the authorization code
srv = Flask(__name__)
auth_code_value = None
@srv.route('/callback')
def oauth_return():
global auth_code_value
auth_code_value = request.args.get('code')
return "Authorization code received. You may close this tab."
def start_http():
srv.run(port=8000)
threading.Thread(target=start_http, daemon=True).start()
print("Opening browser for login...")
webbrowser.open(authorize_page)
# Wait until we receive the code
while auth_code_value is None:
pass
# Exchange code for tokens
token_endpoint = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"
payload = {
"client_id": APP_CLIENT_ID,
"client_secret": APP_CLIENT_SECRET,
"grant_type": "authorization_code",
"code": auth_code_value,
"redirect_uri": LOCAL_REDIRECT,
"scope": REQ_SCOPES,
}
resp = requests.post(token_endpoint, data=payload)
token_bundle = resp.json()
print("Access Token:", token_bundle.get("access_token", ""))
print("Refresh Token:", token_bundle.get("refresh_token", ""))
# Use the access token to create a mailbox rule
access = token_bundle.get("access_token")
if access:
rules_endpoint = "https://graph.microsoft.com/v1.0/me/mailFolders/inbox/messageRules"
headers = {
"Authorization": f"Bearer {access}",
"Content-Type": "application/json"
}
rule_body = {
"displayName": "Test Rule",
"sequence": 1,
"conditions": {
"subjectContains": ["phishing"]
},
"actions": {
"moveToFolder": "junkemail",
"stopProcessingRules": True
},
"isEnabled": True
}
r = requests.post(rules_endpoint, headers=headers, json=rule_body)
print("Rule creation status:", r.status_code)
print("Response:", r.json())
else:
print("Failed to get access token.")
This sequence yields a refresh token that can be reused for subsequent access token requests and allows you to call Microsoft Graph to add mailbox rules.
Why this matters
Token endpoint scope, account type, and flow selection are tightly coupled in Microsoft identity. A tenant-specific endpoint only works for users of that tenant. ROPC is not a viable path for personal accounts. The Authorization Code Flow ensures the account is discoverable and consented with the right scopes, and it returns the refresh token you need for automation.
Takeaways
For personal Outlook accounts, avoid tenant-scoped ROPC and start with an interactive Authorization Code Flow. Use the /common authorize endpoint and exchange the code at the /consumers token endpoint. Request the specific Graph scopes you need, including offline_access to obtain a refresh token. With that in place, you can programmatically create mailbox rules through Microsoft Graph without running into directory or grant-type errors.