I wrote a small app to clean out errors in Google's Search Console (formally Google Webmaster Tools) using Oauth to connect accounts. This was running fine for the past two weeks, however, today I have noticed the the following error:
Error
Traceback (most recent call last):
File "/home/graingerkid/search_console_auto/scripts/error_count.py", line 97, in <module>
get_error_stats()
File "/home/graingerkid/search_console_auto/scripts/error_count.py", line 19, in get_error_stats
access_token = get_refreshed_tokens(refresh_token)
File "/home/graingerkid/search_console_auto/scripts/refresh_token.py", line 25, in get_refreshed_tokens
access_token = keys['access_token']
KeyError: 'access_token'
After investigating and trying to debug my code I realised I was not getting an access_token when requesting one with the refresh_token, here is the output:
Output
{
"error" : "invalid_grant"
}
Here is the function I wrote to grab the access_tokens (I've changed sensitive info):
Code
#-*- coding:utf-8 -*-
import json
import httplib2
import urllib
import pprint
def get_refreshed_tokens(refresh_token):
GOOGLE_CLIENT_ID = '98997543650-f0tn93u86vmts4j2m987654359shue6gu9g.apps.googleusercontent.com'
GOOGLE_CLIENT_SECRET = 'TFGZVLVG7VtnnrbNDTYFNBRgbfdFuENkBY'
h = httplib2.Http(".cache")
url = 'https://accounts.google.com/o/oauth2/token'
body = {
'client_secret': GOOGLE_CLIENT_SECRET,
'grant_type': 'refresh_token',
'refresh_token': refresh_token,
'client_id': GOOGLE_CLIENT_ID
}
headers = {'Content-type': 'application/x-www-form-urlencoded', 'cache-control': 'no-cache'}
response, content = h.request(url, 'POST', headers=headers, body=urllib.urlencode(body))
print content
keys = json.loads(content)
try:
access_token = keys['access_token']
except Exception as e:
pass
access_token = None
return access_token
get_refreshed_tokens('1/lWS6Fu3Hz5dMBPk9huVu6mt5yrnj5hrunhMEf7vs_UdibrBactUREZofsF9C7PrpE-j')
When requesting access to a users account I use the following:
google = oauth.remote_app('google',
base_url='https://www.google.com/accounts/',
authorize_url='https://accounts.google.com/o/oauth2/auth',
request_token_url=None,
request_token_params={'scope': 'https://www.googleapis.com/auth/webmasters https://www.googleapis.com/auth/userinfo.email',
'response_type': 'code',
'access_type':'offline',
'approval_prompt':'force'},
access_token_url='https://accounts.google.com/o/oauth2/token',
access_token_method='POST',
access_token_params={'grant_type': 'authorization_code'},
consumer_key=GOOGLE_CLIENT_ID,
consumer_secret=GOOGLE_CLIENT_SECRET)
Bearing in mind this worked fine for several weeks, I'm struggling to understand what's gone wrong, and searches on SO have not yielded answers.
Can anyone help with this?
(the accounts connected to these are mine, I have checked their access and the API access in Google API console is still intact, nothing has changed.)
Related
I am attempting to authenticate with Microsoft Defender for Endpoint's API service by following this learn article:
https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/run-advanced-query-sample-python?view=o365-worldwide#get-token
I typically use the "request" library for REST calls, so I didn't follow the above code snippet exactly. When running my version of the above code:
import json
import requests
MDE_CLIENT_ID = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX'
MDE_CLIENT_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
TENANT_ID = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX'
AUTHORITY = 'https://login.microsoftonline.com/'
MDE_URI = 'https://api.securitycenter.microsoft.com'
class RESTError(Exception):
def __init__(self, status_code, message):
self.status_code = status_code
self.message = str(self.status_code) + ' ' + json.dumps(message)
super().__init__(self.message)
def authenticate_mde():
headers = {
'content-type': 'application/x-www-form-urlencoded'
}
body = {
'resource': MDE_URI,
'client_id': MDE_CLIENT_ID,
'client_secret': MDE_CLIENT_SECRET,
'grant_type': 'client_credentials'
}
response = requests.post(AUTHORITY + TENANT_ID + '/oauth2/token', data = json.dumps(body), headers = headers)
if (response.status_code < 200 or response.status_code > 299):
raise RESTError(response.status_code, response.json())
return response.json()['access_token']
def main():
token = authenticate_mde()
print(token)
if (__name__ == '__main__'):
main()
When I run this code I receive a 400 error back from the authentication service complaining about a missing body parameter 'grant_type'. However, as you can see in the code, I clearly have that included in the same fashion as the code snippet from MSFT.
Traceback (most recent call last):
File "C:\Users\24724\Documents\code\python\scripts\mde-executor.py", line 42, in <module>
main()
File "C:\Users\24724\Documents\code\python\scripts\mde-executor.py", line 38, in main
token = authenticate_mde()
File "C:\Users\24724\Documents\code\python\scripts\mde-executor.py", line 32, in authenticate_mde
raise RESTError(response.status_code, response.json())
__main__.RESTError: 400 {"error": "invalid_request", "error_description": "AADSTS900144: The request body must contain the following parameter: 'grant_type'.\r\nTrace ID: e4d0d06e-aae6-4b6d-80e2-2b3997f74302\r\nCorrelation ID: 5788089d-f94e-4e9a-8667-d6e36c183af8\r\nTimestamp: 2023-01-06 17:00:23Z", "error_codes": [900144], "timestamp": "2023-01-06 17:00:23Z", "trace_id": "e4d0d06e-aae6-4b6d-80e2-2b3997f74302", "correlation_id": "5788089d-f94e-4e9a-8667-d6e36c183af8", "error_uri": "https://login.microsoftonline.com/error?code=900144"}
I also tried copying MSFT's code snippet exactly and inserting my own global var info but receive the same error. I have tried moving the body to url parameters, headers, splitting it up between body, params, and headers. No luck. I have tried different content-types in the header as well and tried without any headers. None seems to work and I am stumped at this point.
I resolved the issue. Passing 'resource' into the body was apparently screwing it up, even though their python example here shows that:
import json
import urllib.request
import urllib.parse
tenantId = '00000000-0000-0000-0000-000000000000' # Paste your own tenant ID here
appId = '11111111-1111-1111-1111-111111111111' # Paste your own app ID here
appSecret = '22222222-2222-2222-2222-222222222222' # Paste your own app secret here
url = "https://login.microsoftonline.com/%s/oauth2/token" % (tenantId)
resourceAppIdUri = 'https://api.securitycenter.microsoft.com'
body = {
'resource' : resourceAppIdUri,
'client_id' : appId,
'client_secret' : appSecret,
'grant_type' : 'client_credentials'
}
data = urllib.parse.urlencode(body).encode("utf-8")
req = urllib.request.Request(url, data)
response = urllib.request.urlopen(req)
jsonResponse = json.loads(response.read())
aadToken = jsonResponse["access_token"]
https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/run-advanced-query-sample-python?view=o365-worldwide#get-token
Following the example they give for cURL here and using the 'scope' parameter instead fixed it.
curl -i -X POST -H "Content-Type:application/x-www-form-urlencoded" -d "grant_type=client_credentials" -d "client_id=%CLIENT_ID%" -d "scope=https://securitycenter.onmicrosoft.com/windowsatpservice/.default" -d "client_secret=%CLIENT_SECRET%" "https://login.microsoftonline.com/%TENANT_ID%/oauth2/v2.0/token" -k
https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/exposed-apis-create-app-webapp?view=o365-worldwide#use-curl
So far this is my code
import requests, json
API_ENDPOINT = 'https://discord.com/api/v8'
CLIENT_ID = '82'
CLIENT_SECRET = 'db'
REDIRECT_URI = 'https://google.com'
def refresh_token(refresh_token):
data = {
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'grant_type': 'refresh_token',
'refresh_token': refresh_token
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers)
r.raise_for_status()
return r.json()
js = json.loads(open("token.json", "r").read())
for i in js:
js[i] = refresh_token(js[i]["refresh_token"])
open("token.txt", "w").write(json.dumps(js))
Every time I run it, I get a 400 error
Traceback (most recent call last):
js[i] = refresh_token(js[i]["refresh_token"])
File "c:\Users\c\Downloads\discord-oauth2-example-master\discord-oauth2-example-master\refresh.py", line 18, in refresh_token
r.raise_for_status()
File "C:\Users\c\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\requests\models.py", line 943, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://discord.com/api/v8/oauth2/token
The code is taken directly from the discord website, so i have no idea what is going wrong. My original token grants are working but not this. Any ideas?
Thanks
I think you should provide the scope key in the data object itself. The scope is the key that you initially set when you created the access_token;
Example of scope key that is separated by whitespace:
identify email guilds
If you check the discord-oauth2 library, it requires us to pass the "scope" key into the data object
https://www.npmjs.com/package/discord-oauth2
I am writing a command line script accessing LinkedIN API via Library but having issues with it. Here is my code:
from linkedin import linkedin
import requests
RETURN_URL = "http://localhost"
authentication = linkedin.LinkedInAuthentication(CLIENT_ID, CLIENT_SECRET, RETURN_URL,
linkedin.PERMISSIONS.enums.values())
print(authentication.authorization_url)
get_code = authentication.authorization_url
application = linkedin.LinkedInApplication(authentication)
authentication.authorization_code = 'AQQfHou58eyVEJmbabHk1njdl-AY0bqfDjkZeosAn6DR-DiTnH7raJoDcign2U3w5w1YieYU4cjfTz3Ab-wa7cm3KwwctjzU-SoAWchjj_odArFM7q1W1CCU_15Q7gLDRrZoMCo5ivXnkisR5gYfGS0V2E_jsQ&state=74abc361c20313f5bc87d43f42f88b53#!'
# authentication.get_access_token()
data = {
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'grant_type': 'authorization_code',
'redirect_uri': RETURN_URL,
'code': 'AQTqmP0g4PWGJpNnSysqvH4TCXTusoWsjbx1f3R7TPazYP4pCB81a4FrRJRUNjeJzH5yoN2XTrIT4YO-mu2VBQkhL12kwJZ09Xm_WHh97nyok0tqKHh8k54c3dCc075hrsJ8KYw02X-2XSMD-TkxQWKrUXPsMw&state=82d8d2bbbc80ba485812d2fe500cf3e9#!'
}
url = 'https://www.linkedin.com/uas/oauth2/accessToken'
r = requests.post(url, data=data)
print(r.text)
The error I get:
https://www.linkedin.com/uas/oauth2/authorization?client_id=862ztaa9740mst&redirect_uri=http%3A//localhost&scope=rw_company_admin%20r_emailaddress%20r_basicprofile%20w_share&response_type=code&state=d8e7aaefdbd32211fb7d342b238a84dc
{"error_description":"missing required parameters, includes an invalid parameter value, parameter more than once. : Unable to retrieve access token : appId or redirect uri does not match authorization code or authorization code expired","error":"invalid_request"}
Also, how to get code part dynamically?
I am trying to request an authorization code as documented here.
I am using Python requests package to do this and have the following example code:
import requests
auth_endpoint = 'https://login.microsoftonline.com/%s/oauth2/authorize?api-version=1.0' % TENANT_ID
payload = {
'client_id': CLIENT_ID,
'response_type': 'code',
'resource': APP_ID_URI,
'redirect_uri': REPLY_URL
}
response = requests.get(url=auth_endpoint, data=payload)
However, when I run the code above, I get back HTML in the body and not the response I'm expecting. It seems like the HTML code is for a login page.
When I take the formatted endpoint URI and plug it into a browser, I am able to get the auth code from the redirect URI. But, is there a way to get this from the body of the response while still using the requests package?
Please use session class of requests module to implement your requirement. Please refer to the following code sample:
import requests
s = requests.Session()
USERNAME = '<username_email>'
PASSWORD = '<userpassword>'
s.auth = (USERNAME, PASSWORD)
TENANT_ID = '<tenant_id>'
# Authorize URL
authorize_url = 'https://login.microsoftonline.com/%s/oauth2/authorize' % TENANT_ID
# Token endpoint.
token_url = 'https://login.microsoftonline.com/%s/oauth2/token' % TENANT_ID
payload = { 'response_type': 'code',
'client_id': '<tenant_id>',
'redirect_uri': 'http://localhost',
'authority' :'authority'
}
response = s.get(authorize_url, params=payload ,allow_redirects=True)
print response
print response.url
Any further concern, please feel free to let me know.
I am trying to Share a Post on Linkedin on user's behalf.
I took the user through authentication process to generate oauth2 token. I have the token but now i am stuck how to use it. All the help i found on the internet was regarding Oauth not Oauth2. I am trying to send the request but i am getting HTTP Error 401: Unauthorized. Below is my code...
import urllib2, cookielib
cookie_jar = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie_jar))
urllib2.install_opener(opener)
xml_request = ..... XML
headers={'Content-Type': 'application/xml'}
url = "http://api.linkedin.com/v1/people/~/shares/?oauth2_access_token=XXXX"
req = urllib2.Request(url, data=xml_request, headers = headers)
rsp = opener.open(req)
content = rsp.read()
I have checked and the token is valid i am getting Network Updates using the same token... I have searched and searched but still no help on Oauth2. All the Linkedin Clients i have seen in using Oauth not Oauth2..
Please help me out on how to send this request.
If anyone know any api or client which uses oauth2 please let me know..
Thanks in advance for your help
I wrote below code to Share Content on linkedin using OAuth 2.0
import requests
import json
def make_request(method, url, token ,data=None, params=None, headers=None, timeout=60):
headers = {'x-li-format': 'json', 'Content-Type': 'application/json'}
params = {}
kw = dict(data=data, params=params, headers=headers, timeout=timeout)
params.update({'oauth2_access_token': token})
return requests.request(method.upper(), url, **kw)
def submit_share(comment, title, description, submitted_url, submitted_image_url, token):
post = {
'comment': comment,
'content': {
'title': title,
'submitted-url': submitted_url,
'submitted-image-url': submitted_image_url,
'description': description
},
'visibility': {
'code': 'anyone'
}
}
url = 'https://api.linkedin.com/v1/people/~/shares'
try:
response = make_request('POST', url, token,data=json.dumps(post))
response = response.json()
return response
except Exception:
return False
I hope this code helps anyone.
Regards