Reputation: 684
I've been retrieving my emails in Outlook by only using python requests to GET the endpoint https://outlook.office365.com/api/v1.0/me/messages
Example code:
import requests
requests.get('https://outlook.office365.com/api/v1.0/me/messages', auth=(email, pwd))
I would get a json object back, parse through it, and get the contents of my email. But now Microsoft has deprecated it and I have been trying to migrate over to using Microsoft Graph. My question is, how do I get an OAuth2 token without having to launch a browser using http requests?
So far I've been reading through the docs and registered my "app" (just a regular python script) in the Application Registration Portal. Every example that I come across, I always have to go visit an authorization url where I have to manually log in through a front end UI which looks like this: I want to be able to do this through http requests/without a frontend UI but I can't seem to find any answers on how to do this.
This is the code I have so far:
import requests
authorize_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
token_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
payload = {
'client_id': app_client_id, # Variable exists but not exposed in this question
'response_type': 'code',
'redirect_uri': 'https://login.microsoftonline.com/common/oauth2/nativeclient',
'response_mode': 'form_post',
'scope': 'mail.read',
'state': '12345'
}
r = requests.get(authorize_url, params=payload)
print(r.status_code)
print(r.text)
This is what I get back:
200
<!DOCTYPE html>
<html dir="ltr" class="" lang="en">
<head>
<title>Sign in to your account</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=2.0, user-scal able=yes">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="-1">
<meta name="PageID" content="ConvergedSignIn" />
<meta name="SiteID" content="" />
<meta name="ReqLC" content="1033" />
<meta name="LocLC" content="en-US" />
<noscript>
<meta http-equiv="Refresh" content="0; URL=https://login.microsoftonline.com/jsdisabled" />
</noscript>
<link rel="shortcut icon" href="https://secure.aadcdn.microsoftonline-p.com/ests/2.1.8502.8/co ntent/images/favicon_a_eupayfgghqiai7k9sol6lg2.ico" />
<meta name="robots" content="none" />
...
This is what I have in my platform settings when I registered my app if it helps:
Is there any way I can get the authorization code programatically? I tried passing in the auth parameter as well but that didn't work.
I recently found out that python requests handles OAuth2 but now I am getting a different error when trying to follow their examples. This is the error that I'm getting:
File "outlook_test.py", line 31, in <module>
token = oauth.fetch_token(token_url=token_url, auth=auth)
File "C:\Users\ryee\Documents\gitLabQA\QA_BDD\outlook_env\lib\site-packages\requests_oauthlib\oauth2_session.py", line 307, in fetch_token
self._client.parse_request_body_response(r.text, scope=self.scope)
File "C:\Users\ryee\Documents\gitLabQA\QA_BDD\outlook_env\lib\site-packages\oauthlib\oauth2\rfc6749\clients\base.py", line 415, in parse_request_body_response
self.token = parse_token_response(body, scope=scope)
File "C:\Users\ryee\Documents\gitLabQA\QA_BDD\outlook_env\lib\site-packages\oauthlib\oauth2\rfc6749\parameters.py", line 425, in parse_token_response
validate_token_parameters(params)
File "C:\Users\ryee\Documents\gitLabQA\QA_BDD\outlook_env\lib\site-packages\oauthlib\oauth2\rfc6749\parameters.py", line 432, in validate_token_parameters
raise_from_error(params.get('error'), params)
File "C:\Users\ryee\Documents\gitLabQA\QA_BDD\outlook_env\lib\site-packages\oauthlib\oauth2\rfc6749\errors.py", line 405, in raise_from_error
raise cls(**kwargs)
oauthlib.oauth2.rfc6749.errors.InvalidClientIdError: (invalid_request) AADSTS90014: The required field 'scope' is missing.
Trace ID: 2359d8a6-0140-43c1-8ff5-8103045d2f00
Correlation ID: dff39a1f-ffe1-493e-aea3-1536974b777d
I tried '[Mail.Read]'
as a scope but I'm getting an "Invalid Scope parameter".
My new python script:
from oauthlib.oauth2 import BackendApplicationClient
from requests.auth import HTTPBasicAuth
from requests_oauthlib import OAuth2Session
auth = HTTPBasicAuth(client_app_id, app_secret)
client = BackendApplicationClient(client_id=client_app_id)
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(token_url=token_url, auth=auth)
Upvotes: 4
Views: 9444
Reputation: 301
The scope you are using, Mail.Read requires user consent. What you want is Application permission Mail.Read which requires admin consent(This link shows how to get Admin Consent). You are trying to access a user's messages, thus the user needs to consent to that action. According to the docs:-
Upvotes: 0
Reputation: 3756
I found this tutorial very helpful for getting access codes:
This tutorial uses Microsoft Graph (which covers several Microsoft products including Microsoft Outlook) rather than the outlook REST API (which covers just Outlook).
https://learn.microsoft.com/en-us/outlook/rest/python-tutorial
At first, I thought setting up a Django server was overkill. Then I realized that I wanted a way for my Python instance to capture the access code after going through single-sign-on. (I MUST use my browser for single-sign-on because my institution uses multi-factor authentation.) Having a Django server is a natural way to do this.
So I created a new PyCharm Django project (which is straight-forward in PyCharm) and began following the tutorial.
I found it essential to continue following the tutorial all the way through displaying my emails to avoid getting authentication errors -- deviate from the tutorial, and I got error messages (such as this one) that were unpenetrable.
(I previously posted this answer here in response to a different question.)
Upvotes: -1