I am trying to access some mailboxes using the Pop3 protocol through my works proxy. I can get my oauth token, and access my information using Chilkat2 HTTP Library.
Using this code gets me a response of my profile:
http = chilkat2.Http()
http.AuthToken = accesstoken
http.ProxyDomain = "Some Proxy"
http.ProxyPort = Some Port
answer = http.QuickGetStr("https://graph.microsoft.com/v1.0/me")
print(answer)
which retunrs this
{"#odata.context":"https://graph.microsoft.com/v1.0/$metadata#users/$entity"................ ect
This returns my profile details from the Windows servers so I know my oauth2 token is valid and works.
I then try and use the MailMan protocol to open up my POP3 Mailbox I run in to an authentication error, I run the code below
mailman = chilkat2.MailMan()
mailman.HttpProxyHostname = "Some Proxy"
mailman.HttpProxyPort = Some Port
mailman.MailHost = "outlook.office365.com"
mailman.MailPort = 995
mailman.PopSsl = True
mailman.PopUsername = username
mailman.PopPassword = ""
mailman.OAuth2AccessToken = accesstoken
mailman.Pop3EndSession() #close session as program keeps breaking and leaving session open
success = mailman.Pop3Connect()
if (success != True):
print(mailman.LastErrorText)
sys.exit()
# Authenticate..
success = mailman.Pop3Authenticate()
if (success != True):
print(mailman.LastErrorText)
sys.exit()
However the authenticate command always returns as false, the Chilkat error log shows as below:
ChilkatLog:
Pop3Authenticate:
DllDate: Feb 9 2021
ChilkatVersion: 9.5.0.86
UnlockPrefix: Auto unlock for 30-day trial
Architecture: Little Endian; 64-bit
Language: Python 3.9.4 (tags/v3.9.4:1f2e308, Apr 6 2021, 13:40:21) [MSC v.1928 64 bit (AMD64)], win32
VerboseLogging: 0
Pop3Authenticate:
username: my username
popSPA: 0
greeting: +OK The Microsoft Exchange POP3 service is ready. [TABPADIAUAAyADYANQBDAEEAMAAzADgANgAuAEcAQgBSAFAAMgA2ADUALgBQAFIATwBEAC4ATwBVAFQATABPAE8ASwAuAEMATwBNAA==]
pop_office365_xoauth2:
PopCmdSent: AUTH XOAUTH2
PopCmdResp: +
auth_xoauth2_response_1: +
PopCmdSent: <base64 string in XOAUTH2 format>
PopCmdResp: -ERR Authentication failure: unknown user name or bad password.
POP3 response indicates failure.
AUTH_XOAUTH2_response: -ERR Authentication failure: unknown user name or bad password.
--pop_office365_xoauth2
POP3 authentication failed
--Pop3Authenticate
Failed.
--Pop3Authenticate
--ChilkatLog
I am at a loss, I have used every combination of scope that should allow me this access with my token, but I cannot get it to work with any of the email libraries in Chilkat; seems to connect fine with the servers but always fails the authentication. Anyone got any idea on this?
My guess is that something wasn't setup correctly in Azure, and/or you're not asking for the correct scopes when getting the OAuth2 access token.
This example has comments that describe the App Registration in Azure Active Directory: https://www.example-code.com/chilkat2-python/office365_oauth2_access_token.asp
At each step, there is a link to the Azure Console screen as I was doing it.
Also, your scope should look like this:
oauth2.Scope = "openid profile offline_access https://outlook.office365.com/SMTP.Send https://outlook.office365.com/POP.AccessAsUser.All https://outlook.office365.com/IMAP.AccessAsUser.All"
There are places in the Microsoft documentation where the scopes are different (or old?).
The interactive 3-legged OAuth2 flow only has to be done once. After you have the OAuth2 access token, you can continually refresh without user interaction
as shown here: https://www.example-code.com/chilkat2-python/office365_refresh_access_token.asp
Alternatively, you can try the resource owner grant flow as shown here:
https://www.example-code.com/chilkat2-python/office365_resource_owner_password_credentials_grant.asp
The resource-owner flow is non-interactive and is for apps accessing its own O365 account.
Please let me know if that helps.
Related
I've been using basic auth to log in to my outlook email with imap.
imap = imaplib.IMAP4_SSL("imap-mail.outlook.com")
# authenticate
imap.login(username, password)
status, messages = imap.select("INBOX")
Now that Microsoft moved to oauth2 I'm getting "Login failed" messages even although the credentials are correct.
Can anyone share a code example that connects with oauth2?
I found this guide, but it only shows the steps on the account side, not the actual connection in the app.
https://docs.emailengine.app/setting-up-oauth2-with-outlook/#:~:text=Navigate%20to%20Configuration-%3EOAuth2%20and,of%20accounts%20your%20application%20supports.
Thanks
This is my solution,
follow this guide to create an app with necessary permissions.
https://docs.emailengine.app/setting-up-oauth2-with-outlook/#:%7E:text=Navigate%20to%20Configuration-%3EOAuth2%20and,of%20accounts%20your%20application%20supports
use the following code in your app.
imap = imaplib.IMAP4_SSL(imap_host, 993)
imap.debug = 4
access_token = get_access_token_to_authenticate_imap()
imap.authenticate("XOAUTH2", lambda x:generate_auth_string(
'useremail',
access_token['access_token']))
imap.select('inbox')
I am trying to build an flask app on AWS lambda, which needs to access https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly to get the Mac Address of chrome devices by domain name and chrome device id.
Basically the working flow is blew:
A Chrome Extension deployed by G-Suit sends an request with domain name and device id to AWS(as we are using AWS), then the AWS sends an request with domain name and device id to Google Cloud to get Mac Address.
I started with using an access the directory API as a service account like service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES, subject="username#domainName.com"), and it works. However, I realised it was wrong implementation as the domainName would be changed and subject will be different for each domain as the Chrome Extension can be deployed via different domains.
Then I started to use the sample code from Google(https://developers.google.com/api-client-library/python/auth/web-app), and I was able to access the domain and get the Mac Address of each device.
However, the problem is it requires to choose the email when you call the google api for the first time. But as I mentioned above, this app is going to run on AWS, so clearly users cannot choose the email.
So is that possible that we just use the domainName instead of choosing email to do the authentication and access the different directories? If so, is there any examples or documentations I need to read?
I suspect I need to modify this part from the sample, but I am still getting confused how it works.
#app.route('/adminlogin')
def authorize():
# Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
CLIENT_SECRETS_FILE, scopes=SCOPES)
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)
authorization_url, state = flow.authorization_url(
# Enable offline access so that you can refresh an access token without
# re-prompting the user for permission. Recommended for web server apps.
access_type='offline',
approval_prompt="force",
# Enable incremental authorization. Recommended as a best practice.
#include_granted_scopes='true'
)
# Store the state so the callback can verify the auth server response.
flask.session['state'] = state
return flask.redirect(authorization_url)
Any hint will be helpful.
I'm trying to connect cassandraDB using python. I have used authentication as PlainTextAuthProvider. This is my code snippet.
auth_provider = PlainTextAuthProvider(username="foo", password="bar")
cluster = Cluster([1.1.1.1], protocol_version=2, auth_provider=auth_provider)
session = cluster.connect()
session.set_keyspace('keyspace')
cluster.connect()
It's throwing following error:
An authentication challenge was not sent, this is suspicious because the driver expects authentication (configured authenticator = PlainTextAuthenticator)
That's PYTHON-940, added in version 3.14.0 of the driver. It should not be throwing the error, but warning if the connection occurs without auth. The intent is to flag when a client configures, and expects to be using auth, but the server is not. Verify auth settings in cassandra.yaml, and check that it's mentioned in system.log at startup.
I am trying to obtain a token from Azure AD from Python client application. I want users to seamlessly authenticate with just a username and password (client_id / secret will be embedded in the app). I registered my app and given it all permissions and hit the "grant permissions" button in the new portal according to this post:
The user or administrator has not consented to use the application - Send an interactive authorization request for this user and resource
I am sending an http post to:
https://login.microsoftonline.com/{tenant_id}/oauth2/token
with the following data:
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
body = "resource={0}&grant_type=password&username={1}&password={2}&client_id={3}&client_secret={4}&scope=openid".format(app_id_uri,user,password,client_id,client_secret)
I cannot seem to get past this error no matter what I try:
b'{"error":"invalid_grant","error_description":"AADSTS65001: The user or administrator has not consented to use the application with ID \'078c1175-e384-4ac7-9116-efbebda7ccc2\'. Send an interactive authorization request for this user and resource.
Again, my goal:
User enters user / pass and nothing else. App sends user / pass / client_id / client_secret, obtains token.
According to your comment:
The message I'm receiving says to do an interactive request but that is exactly what I'm trying to avoid because this is a python app with no web browser and I'm trying to avoid complexity.
I think you want to build a daemon app or an app only application integrating with Azure AD. You can refer to https://graph.microsoft.io/en-us/docs/authorization/app_only for the general introduction.
Furthermore, you can leverage the ADAL for Python to implement this functionality with a ease. Also, you can refer to client_credentials_sample.py for a quick start.
You should try logging in as an admin to be able to give consent to use the application on your tenant at all.
I am having trouble generating a refresh token using Python for the AdWords API & need some help. Here is the situation:
I have a client on AdWords that I want to pull reports for through the AdWords API (we have a developer token now for this). Let's say that, in AdWords, the clients account is 521-314-0974 (making this up). Here is where I am confused:
Below is the following code snippet needed to generate a refresh token that I am trying to get working:
"""Generates a refresh token for use with AdWords."""
__author__ = 'Nathaniel Payne'
import sys
import urllib2
from oauthlib import oauth2
# Your OAuth 2.0 Client ID and Secret. If you do not have an ID and Secret yet,
# please go to https://console.developers.google.com and create a set.
CLIENT_ID = 'INSERT_CLIENT_ID_HERE'
CLIENT_SECRET = 'INSERT_CLIENT_SECRET_HERE'
# You may optionally provide an HTTPS proxy.
HTTPS_PROXY = None
# The AdWords API OAuth 2.0 scope.
SCOPE = u'https://adwords.google.com/api/adwords'
# This callback URL will allow you to copy the token from the success screen.
CALLBACK_URL = 'urn:ietf:wg:oauth:2.0:oob'
# The HTTP headers needed on OAuth 2.0 refresh requests.
OAUTH2_REFRESH_HEADERS = {'content-type':
'application/x-www-form-urlencoded'}
# The web address for generating new OAuth 2.0 credentials at Google.
GOOGLE_OAUTH2_AUTH_ENDPOINT = 'https://accounts.google.com/o/oauth2/auth'
GOOGLE_OAUTH2_GEN_ENDPOINT = 'https://accounts.google.com/o/oauth2/token'
def main():
oauthlib_client = oauth2.WebApplicationClient(CLIENT_ID)
authorize_url = oauthlib_client.prepare_request_uri(
GOOGLE_OAUTH2_AUTH_ENDPOINT, redirect_uri=CALLBACK_URL, scope=SCOPE)
print ('Log in to your AdWords account and open the following URL: \n%s\n' %
authorize_url)
print 'After approving the token enter the verification code (if specified).'
code = raw_input('Code: ').strip()
post_body = oauthlib_client.prepare_request_body(
client_secret=CLIENT_SECRET, code=code, redirect_uri=CALLBACK_URL)
if sys.version_info[0] == 3:
post_body = bytes(post_body, 'utf8')
request = urllib2.Request(GOOGLE_OAUTH2_GEN_ENDPOINT, post_body,
OAUTH2_REFRESH_HEADERS)
if HTTPS_PROXY:
request.set_proxy(HTTPS_PROXY, 'https')
raw_response = urllib2.urlopen(request).read().decode()
oauth2_credentials = oauthlib_client.parse_request_body_response(raw_response)
print ('Your access token is %s and your refresh token is %s'
% (oauth2_credentials['access_token'],
oauth2_credentials['refresh_token']))
print ('You can cache these credentials into a yaml file with the '
'following keys:\nadwords:\n client_id: %s\n client_secret: %s\n'
' refresh_token: %s\n'
% (CLIENT_ID, CLIENT_SECRET, oauth2_credentials['refresh_token']))
if __name__ == '__main__':
main()
Questions:
1) Do I need to have a special project set-up for every AdWords customer in the console.developers.google.com, in order to pull from the AdWords Reporting API? Or, can I simply provide the client secret and ID for a generic account in the console?
2) Following from this, can someone please confirm what should go in place of the client_ID & Client_Secret in order to make the Python code block below work. What I mean is, I was using the client ID and client secret from https://console.developers.google.com ... for the analytics account that we have billing set-up on (and which I have used for BigQuery API access previously). Is that correct? I am not seeing clearly how this will be linked to the AdWords account for this client.
2) In the consent screen, I put my own e-mail, since I am owner of the project,. That said, when I run the code, I get the link to the URL that I need to run to generate the code. That said, when I sun this snippet:
print ('Log in to your AdWords account and open the following URL: \n%s\n' %
authorize_url)
print 'After approving the token enter the verification code (if specified).'
code = raw_input('Code: ').strip()
I get an error. This is the message that I get in error:
Error: redirect_uri_mismatch
The redirect URI in the request: urn:ietf:wg:oauth:2.0:oob did not match a registered redirect URI
Learn more
Request Details
cookie_policy_enforce=false
scope=https://adwords.google.com/api/adwords
response_type=code
access_type=online
redirect_uri=urn:ietf:wg:oauth:2.0:oob
display=page
client_id=XXXXXXXXX.apps.googleusercontent.com
I am puzzled here. Some folks suggested changing the e-mail address in the consent screen (which I did ... but was unsuccessful). Again, my simple goal is to be able to pull one report from tis clients through the AdWords API (which I will expand once I get there). Any help would be appreciated. Cheers.
After some work, I was able to successfully navigate through this issue. Here are the detailed steps that I took to get to the point where I could successfully pull data through the API. In my situation, I manage an AdWords MCC with multiple accounts. Thus, I went back to the beginning of many of the help manuals and did the following:
Create a new project called AdWords-API-XXXX.
In the credentials screen on the console, I created a new "Client ID for native application". This allowed me to generate my CLIENT_ID and the CLIENT_SECRET that I needed. Critically, it also generated a re-direct URI which was the source of my problem.
I took both of these values, added them to the main script, and ran the generate_refresh_token.py script. This allowed me to generate a working refresh token. I had to be signed into my AdWords account MCC, in order to make sure that OAuth2 provided me the ability to access all potential AdWord clientsinside my MCC. I got an authentication screen generated by URL for this process which asked me to confirm that permission was being granted for AdWords access.
Following this, I created a new googleads.yaml script and placed this in my c:\gsutil directory. This is the code in most Python programs where the program looks for the file googleads.yaml:
adwords_client = adwords.AdWordsClient.LoadFromStorage()
Once this was done, I was able to successfully run the script from my command line to generate the final output. The script was:
python download_criteria_report.py
Note of course that I have changed my path variable previously in order to run Python 2.7 from the command line. This script was run inside the directory of the download_criteria_report.py file. This script ran successfully and enabled me to pull data from the AdWords API for one of my test clients.
The next challenge will be working with the returned output from the API and putting it into a format that I can quickly use for analysis & storage.