difficulty getting oauth 2 token file with yagmail - python

I am trying to use the python package yagmail to send emails but am having a tough time getting authorization to work.
My issue is getting an Oauth 2 token, but there is a disconnect with yagmail, as specified in a github thread. As stated in this post, https://github.com/kootenpv/yagmail/issues/143, it appears that google does not supply the credential file in the correct format. But I tried a bunch of things and each has its own problem.
When I set up a Client ID in the Google API console, download the
json as credentials.json and let the system create the token.json,
things work to a point: I am brought through google to "pick an
account, do you want to continue" and token is created. I am able to
print labels for the gmail account. But when I issue
yag.send(to='xxx#gmail.com', subject='Testing Yagmail',
contents='Hurray, it worked!'), I get an error "TypeError:
refresh_authorization() got an unexpected keyword argument 'token'."
When I look at the token file, it does contain the key 'token' which
it should not per this github post https://github.com/kootenpv/yagmail/issues/143#issuecomment-527115298][2].
If I go into the token and edit it to reflect the the expected
contents as identified in the above link by removing keys that are
not specified and prefixing the names with 'google_', I get an error
"ValueError: Authorized user info was not in the expected format,
missing fields refresh_token, client_id, client_secret." It doesn't
seem to like the 'google_' prefix.
editing the token file as above without the 'google_' prefix seems to
get further producing a different error "An error occurred:
<HttpError 403 when requesting
https://gmail.googleapis.com/gmail/v1/users/me/labels?alt=json
returned "Request had insufficient authentication scopes"
I am stuck. Relatively new to Oauth2, but it seems others are able to use yagmail. Is there a trick I am missing? I originally posted on Github because I found that other related post, but it seems SO is more geared toward Q&A. Is there a relation betweeen Github and SO? Difference?
Thanks for any assistance,
Brian

I finally found a solution and the answer was hidden in plain sight.
First the Oauth authorization needed to be set up as outlined in this post (which is excellent): Sending email via Gmail & Python
As stated, when yagmail is run the first time the authorization process gives instructions, the final stating to "Navigate to the following URL to auth:" and asks "Enter the localhost URL you were redirected to:"
The problem is the browser window shows what appears to be an error message, a sad face with a message "This site can’t be reached, localhost refused to connect, reload", etc. I never thought this was expected behavior. The url is the one being navigated to in the error screen.
Simply stating the error should be expected, and the url needs to be copied and pasted in the post above would help a lot.

Related

Google authentication no longer working using Desktop app credentials (Google OAuth:2.0 Error 400: invalid_request)

Previously, this bit of python code worked:
from google.cloud import bigquery
from google_auth_oauthlib import flow
appflow = flow.InstalledAppFlow.from_client_secrets_file(
"credentials.json", scopes=["https://www.googleapis.com/auth/bigquery"])
appflow.run_console()
However, I now get an Error 400: invalid_request message when it directs me to new browser. The details of the error are:
Error 400: invalid_request
The out-of-band (OOB) flow has been blocked in order to keep users secure. Follow the Out-of-Band (OOB) flow migration guide linked in the developer docs below to migrate your app to an alternative method.
Request details: redirect_uri=urn:ietf:wg:oauth:2.0:oob
I know that Google has updated some of its policies in this space in recent months, but I've tried a lot of different things and it won't work (most that result in a uri_mismatch error).
As the credentials are for a Desktop App, I can't add specific URIs in the console like I would for others e.g. Web app. However, I can see in the JSON the redirect uri is set to "http://localhost"
I've tried manually updating the redirect uri (e.g. by adding '8080') in the json file, as outlined at the very bottom of this page. See also this and this article from Google but am getting the same invalid_request error.
This stack overflow answer gives a hacky suggestion, although it didn't work for me.
How do I 'update' my auth method to get it to work now? Ideally the browser pop-up should give me an authentication code that I can manually copy back into the python notebook.

Control API: Service unavailable (503)

Good morning,
I want to query households (my first query and generally first experience with the Sonos API) and have authenticated successfully. I got an access token and query the Control API like this:
headers={"Content-Type" : "application/json",
"Authorization" : "Bearer " + token["access_token"]}
resp = re.get('http://api.ws.sonos.com/control/api/v1/househoulds', headers=headers)
It returns me a response with error code "503: Service unavailable":
Service Unavailable
Service Unavailable - Zero size object
The server is temporarily unable to service your request. Please try again
later.
Reference XXXXX
(I cut out the reference because I am not sure, if it contains credentials). I remember that when I intentionally changed my access token to a wrong one yesterday, I would get an error code back that I am not authorized. But now when I change it to a false one I still just get this same page back (503: Service unavailable).
Does anyone have the same problem? Might it be some security mechanism because I authorized many times in a short time or is the control API just currently down? I tried yesterday and today and don't see a blog post stating a downtime.
I see two issues with the code snippet you provided:
Issue 1: Your API URL has a typo. You used "househoulds" instead of
"households".
Issue 2: Your URL needs to use https://, not http://
If you fix those two issues and are indeed using a valid access token, your request should work.

ROPC flow: The request body must contain the following parameter: 'client_assertion' or 'client_secret'

I am testing MSAL and ROPC flow. When I run sample https://github.com/Azure-Samples/ms-identity-python-desktop I get error:
python username_password_sample.py parameters.json
invalid_client
AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.
I was having same problem while following MS documentation and used curl. Please check my other question where SO community helped me to solve problem. After adding application registration secret to curl request, I got valid token and I was able to fetch mails.
What is confusing me is fact that secret is not present in parameters.json file.
You missed the step No.6 from this link: https://github.com/Azure-Samples/ms-identity-python-desktop/tree/master/1-Call-MsGraph-WithUsernamePassword
If the application was set as Public Client, then the secret is not required.
For more details, you can read https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc#authorization-request for reference.

How to create a Wikipedia bot to add a new section to a talk page?

We need to implement a bot which posts new sections on Wikipedia Talk pages.
As a matter of efficiency, we prefer to use python HTTP POST requests using MediaWiki API rather than available MediaWiki libraries.
We have not requested for an approval for the bot, and we are just trying to implement a trial version to test the bot on our own Talk pages.
For this purpose, I went through the following steps:
1- As discussed at https://en.wikipedia.org/wiki/Wikipedia:Creating_a_bot:
Create an account for your bot. Click here when logged in to create the account, linking it to yours. (If you do not create the bot account while logged in, it is likely to be blocked as a possible sockpuppet or unauthorised bot until you verify ownership)
Create a user page for your bot. Your bot's edits must not be made under your own account. Your bot will need its own account with its own username and password.
So, I logged in to my own Wikipedia account, and created a new account (for the bot).
2- As discussed at "API:Login" page: (Sorry, because of having less than 10 reputation, I am not able to add more than 2 links)
Logging in through the API requires two requests. For the first request, I wrote the following code in python:
def logInRequestToWikipedia():
# Add required parameters to the request.
request = { 'action' : 'login' }
request['lgname'] = 'BotName'
request['lgpassword'] = '*************'
url = 'https://en.wikipedia.org/w/api.php'
headers = { 'content-type' : 'application/x-www-form-urlencoded' }
r = requests.post(url, data = json.dumps(request), headers=headers)
The response starts with an error as follows:
<error code="help" info="" xml:space="preserve">
And continues with the API documentation.
3- As discussed at "API:Edit_-_Create%26Edit_pages" page:
Note: In this example, all parameters are passed in a GET request just for the sake of simplicity. However, action=edit requires POST requests; GET requests will cause an error. Do not forget to set the Content-Type header of your request to application/x-www-form-urlencoded. The token that you received is terminated with +\, this needs to be urlencoded (so it will end with %2B%5C) before it is passed back.
I added each of the following parameters separately and both together in the request data and tried all three cases, but it returns the same response.
request['lgtoken'] = '%2B%5C'
request['Content-Type'] = 'application/x-www-form-urlencoded'
4- Also I tried each of the followings in my request data, but it returns the same response:
request['format'] = 'json'
request['format'] = 'xml'
5- Moreover I found the following instruction at "User-Agent_policy" page:
User agents (browsers or scripts) that do not send a User-Agent header may now encounter an error message like this:
Scripts should use an informative User-Agent string with contact information, or they may be IP-blocked without notice.
User agents that send a User-Agent header that is blacklisted (for example, any User-Agent string that begins with "lwp", whether it is informative or not) may encounter a less helpful error message (lie) like this:
Our servers are currently experiencing a technical problem. This is probably temporary and should be fixed soon. Please try again in a few minutes.
This change is most likely to affect scripts (bots) accessing Wikimedia websites such as Wikipedia automatically, via api.php or otherwise, and command line programs.[3] If you run a bot, please send a User-Agent header identifying the bot and supplying some way of contacting you, e.g.:
User-Agent: MyCoolTool/1.1 (http://example.com/MyCoolTool/; MyCoolTool#example.com) BasedOnSuperLib/1.4
Do not copy a browser's user agent for your bot, as bot-like behavior with a browser's user agent will be assumed malicious.[4] For more information, please refer to the MediaWiki API Documentation
That's why I also tried my script with the following parameter, but the error response did not change:
request['User-Agent'] = "MyCoolTool/1.1 (http://example.com/MyCoolTool/; MyCoolTool#example.com) BasedOnSuperLib/1.4"
Do you think the problem can be related to the fact that we have not requested for an approval for the bot yet? Because we are just trying to implement a trial version to test the bot on our own Talk pages, and apply for the approval after making sure everything will work.
I'm pretty sure the problem is this line:
request['lgtoken'] = '%2B%5C'
The Login API you linked to doesn't include an lgtoken on the initial login attempt; it's only sent on the second ("Confirm token") step, using the token value from the NeedToken response.
And +\ doesn't look like a valid token.
So it's not surprising that you're getting an error.
Meanwhile, when I test this with my Wikipedia account, I get an error if I include that line, and success if I don't, which validates my suspicion that this is the problem.

GData and OAuth in Python: Unable to convert request token to access token

I am trying to implement a button on a web-based dashboard that allows a user to export the current data to a Google Spreadsheet using OAuth and GData API. Currently, I can get the user to a login/grant access page, but if I add the line to convert the request token to an access token, I receive:
"RequestError: Unable to upgrade OAuth request token to access token: 400, parameter_absent
oauth_parameters_absent:oauth_token"
I am following the instructions for OAuth 2 on this page:
https://developers.google.com/gdata/docs/auth/oauth
and have read both PyDocs for the Google APIs and found no details on this issue:
http://gdata-python-client.googlecode.com/hg/pydocs/gdata.docs.client.html#DocsClient
(Won't let me post a this hyperlink but other Pydoc is same URL but replace the piece after pydocs/ with gdata.gauth.html#ClientLoginToken)
This is the code that works:
def createDocsClient(self, oauth_callback_url):
docsClient = gdata.docs.client.DocsClient(source='RiskOps-QualityDashboard')
request_token = docsClient.GetOAuthToken(SCOPES, oauth_callback_url, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)
domain = None
auth_url = request_token.generate_authorization_url(google_apps_domain=domain)
self.redirect(str(auth_url))
request_token = gdata.gauth.AuthorizeRequestToken(request_token, self.request.uri
With the above code, I get to a grant access page and if you click the grant access page, you get a 404 error because it doesn't know where to go after (as expected), but the page has the proper URL displayed listing an oauth_verifier and oauth_token. The "AuthorizeRequestToken" line is supposed to use that URL to authorize the token so up to this line, everything seems to work.
When I add the following line right after the code above, I get the "RequestError" I wrote about:
access_token = docsClient.GetAccessToken(request_token)
I've tried different combinations of nesting the calls within each other, using the AeSave and AeLoad (as the instructions mention might be needed but I'm not sure if my case calls for it) and many other random and unsuccessful ideas and nothing is really giving me a good idea of what I'm missing or doing wrong.
Would really appreciate and help or any ideas anyone has.(If you can't tell, I'm fairly inexperienced when it comes to real-world code (as opposed to academic code). Thanks so much.

Categories

Resources