Amazon advertising API get authorization code via script - amazon

I'm trying to fetch a report from Amazon advertising using python script and I can't find a way to get the authorization code. All amazon documentation refer to websites and none for automatic scripts.
Any idea how can I implement it?
Thanks.

What you need:
a registered application on developers.amazon.com
client_id and client_secret for this app
consent to access an Amazon Advertising Account (this is done via 'Login with Amazon')
As a result of the consent process you get a refresh token.
With the client_id, the client_secret and the refresh token you can build a python script to receive an access token - and with the access token you can access the Amazon Advertising API.
Resources:
https://advertising.amazon.com/API/docs/en-us/setting-up/account-setup
https://advertising.amazon.com/API/docs/en-us/get-started/overview
EDIT:
I recommend to use a tool like Postman or SoapUI for easy testing of auth and api requests...

I had the same problem and using tector's comment I built a simple function that uses the Refresh Token (which never expires) to generate the Authorization Code, which is valid for 60 minutes:
import requests
import json
host = 'https://api.amazon.com/auth/o2/token'
body = {
"grant_type": "refresh_token",
'client_id': YOUR CLIENT ID,
'refresh_token': YOUR REFRESH TOKEN,
'client_secret': YOUR CLIENT SECRET
}
headers = {"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"}
def authenticator():
r = requests.post(host, body,
headers=headers)
r.raise_for_status()
r = r.json()
with open('FILENAME.json', 'w') as f:
json.dump(r, f)

Related

google.auth.exceptions.RefreshError: Invalid Client

I am working on a project to let a client authorize their google ads account, and then use those authorized credentials to download data on their behalf. I have a webapp that successfully Authorizes the app to do things on the clients behalf. This generates an access code that I then trade for two credentials, an access token and a refresh token. This refresh token then gets passed to a database, where a separate app attempts to query the googleAds API.
It is my understanding that the Google Oauth engine only needs the refresh token.
I am trying to authorize by use of load_from_dict() or load_from_env() methods of the GoogleAdsClient class. Both yield the same error: google.auth.exceptions.RefreshError: ('invalid_client: Unauthorized', {'error': 'invalid_client', 'error_description': 'Unauthorized'})
I have verified the developer_token, client_id, and client_secret are all accurate to what is in the API console. I have also verified the refresh_token is being passed correctly to the credential dict.
I am really at a loss on where to go from here. I have read many stack overflow threads with similar titles, and yet I am still stuck at the same place.
Here are some relevant links.
Google Ads API configuration
Google Identity and Server side web apps
Google's example of an API call
Relevant code
class GoogleAds:
def __init__(self):
self.scope = ['https://www.googleapis.com/auth/adwords']
self.client_id = os.getenv('GOOGLE_ADS_CLIENT_ID')
self.client_secret = os.getenv('GOOGLE_ADS_CLIENT_SECRET')
self.developer_token = os.getenv('GOOGLE_ADS_DEVELOPER_TOKEN')
self.refresh_token = os.getenv('GOOGLE_ADS_REFRESH_TOKEN')
def authorize(self):
credentials = {
"developer_token": self.developer_token,
"refresh_token": self.refresh_token,
"client_id": self.client_id,
"client_secret": self.client_secret,
"use_proto_plus":"True",
"grant_type": "refresh_token",
}
print(credentials)
googleads_client = GoogleAdsClient.load_from_dict(credentials)
service = googleads_client.get_service("GoogleAdsService")
request = googleads_client.get_type("SearchGoogleAdsRequest")
return service, request
'error': 'invalid_client', 'error_description': 'Unauthorized' Can be a very hard error to debug. It can mean a number of things.
Currently it Implies to me that the user has not authorized this client.
First ensure that the refresh token has not expired. Second ensure that the client id and client secrete used to create the refresh token are the same one that you are using to request a new access token.
oauth2#expiration
I ended up refreshing the Client_Secret in the google API client and that seemed to have gotten me through.
Q: It is outside the scope of this question, but is it possible to get that value from the authorization step?
A: You can get the customer IDs you have access to with the client.get_service("CustomerService") method. There is also a way to get account hierarchy. I will probably be using (Frankensteining) that to move forward

Google (YouTube) Auth API

I'm trying to use the Google Auth Python library to perform OAuth2 into my own YouTube account, so I can gather metrics of my own subscriptions. The code, however, isn't working.
I have setup a service account, and that process created a "Compatible OAuth2" client, and I exported the JSON key file from that. I have also setup an API key, which is also enabled to do all the things (yes, I know, the sec-eng soul inside you is dying) ...
Here is the code:
# Python 3.10.0
from google.oauth2 import service_account
import requests
import json
import os
# Start an OAuth session
service_account_info = json.load(open(f'{os.path.dirname(__file__)}/.config/service_account.json'))
credentials = service_account.Credentials.from_service_account_info(service_account_info)
# API Key
with open(f'{os.path.dirname(__file__)}/.config/.apikey') as f:
API_KEY = f.read()
HEADERS = {'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': f'Bearer {credentials}'}
# Construct the URL
URL = 'https://www.googleapis.com/youtube/v3/subscriptions'
# Parameters
PARAMS = {'part':'id', 'maxResults':'250', 'order':'alphabetical', 'mine':'true', 'key': API_KEY}
# Make the request
request = requests.get(URL, headers=HEADERS, params=PARAMS)
response = request.json()
# Print the response
print(json.dumps(response, indent=4))
But I'm getting this error:
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [
{
"message": "Invalid Credentials",
"domain": "global",
"reason": "authError",
"location": "Authorization",
"locationType": "header"
}
],
"status": "UNAUTHENTICATED"
}
}
I'm fairly confident that the problem is in how I'm handling the credentials but I don't know how that is supposed to go.
I appreciate your input and help.
All I'm trying to do is list my own YouTube Channel Subscriptions.
Thanks!
The YouTube data api does not support service account authentication to standard YouTube accounts. hense the OAuth 2 access token in the error message.
Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential.
rumor
I have heard that it does work with google workspace domain YouTube accounts because then you can configure the domain wide delegation. I have not tried
Other options
You can use standard oauth2 and authorize your application once. Store the refresh token and then your application can then just use the refresh token to request a new access token as needed. Just remember to set your application in production or your refresh token will expire after seven days and you will need to authorize the application again.

Can I use OAuth 2.0 Service-to-service access token to access Skype for Business Online Resources?

My question is about Skype for Business Online. I'm able to connect with ucwa sdk samples and get the current status of the user. In the sample the user is required to authenticate, but I need a solution that runs in the background.
I want to get the presence of an SfB online user without going through the login screen.
I followed this link: Service-to-service access token request
Can I use the OAuth 2.0 service-to-service method to get SfB Online resources?
If not, Are there other method(s) to do this?
I'm able to retrieve an acces token from the code below, but unable to connect with SfB as I don't know what do next.
def get_access_token(resource):
params = {
'grant_type': 'client_credentials',
'client_id': clientId,
'client_secret': secret,
'resource': resource
}
url = '{0}{1}'.format(authority, '/%s/oauth2/token' % tenant)
response = requests.post(url, params)
if response.status_code == 200:
jsonObject = json.loads(response.content.decode('utf-8'))
print(jsonObject)
return jsonObject['access_token']
else:
print(response.content)

MS Graph API: invalid authentication token

I'm trying to use the Microsoft Graph API to query an Outlook/O365 mailbox for messages. I registered my app in the Azure portal and received the necessary information to query the API. The app has the Mail.Read permission. (I don't have access to the Azure portal, I was told it was set up this way.) When I get my token from the OAuth endpoint, however, it doesn't work in any subsequent calls. I'm using Python's requests module for testing right now.
Why is this call failing? It seems like I'm passing all of the correct information but I'm clearly missing something.
I'm getting the token by performing a POST on:
https://login.microsoftonline.com/my.domain/oauth2/token
I pass the necessary parameters:
data = {'grant_type': 'client_credentials', 'client_id': CLIENTID, 'client_secret': SECRET, 'resource': APPURI}
and I get a response like this:
{
'resource': 'APPURI',
'expires_in': '3599',
'ext_expires_in': '3600',
'access_token': 'TOKENHERE',
'expires_on': '1466179206',
'not_before': '1466175306',
'token_type': 'Bearer'
}
I try to use that token, however, and it doesn't work for anything I call. I'm passing it as a header:
h = {'Authorization': 'Bearer ' + TOKEN}
I'm calling this URL:
url = 'https://graph.microsoft.com/v1.0/users/my.email.address#example.com/messages'
Specifically, I use this:
r = requests.get(url, headers=h)
The response is a 401:
{
'error': {
'innerError': {
'date': '2016-06-17T15:06:30',
'request-id': '[I assume this should be removed for privacy]'
},
'code': 'InvalidAuthenticationToken',
'message': 'Access token validation failure.'
}
}
in your login request, the resource parameter should be https://graph.microsoft.com
It seems to be the case, that tokens issued from the v1 endpoint aren't valid for atleast some requests with MS Graph API.
Instead try to get the token form the v2 endpoint by calling https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token.
In case you are working with oidc discovery documents, you'll find the one for v2 at https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration
I think you will need to register app from here "https://apps.dev.microsoft.com" instead of from Azure Portal.
Unless you are an using Client Credentials, you cannot access the messages another account's mailbox. Make sure that my.email.address#example.com is the same account you are authenticated with and that this address is also the userPrincipalName for the account.
You can also use a simplified URI for requesting your messages and bypassing determining the account's userPrincipalName by using /me. In this case the GET request would be https://graph.microsoft.com/v1.0/me/messages
It's worth noting that even if MS's Azure documentation does not specify the need for listing the resource, I could never get to work without listing the resource.
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols-oauth-client-creds.
There is a supplementary document specifiy to two-legged Auth for MS Graph that actually uses the 'resource' in the example.
https://developer.microsoft.com/en-us/graph/docs/authorization/app_only
Happy hunting!

Token based authentication with flask-security extension

I am currently looking for a way to secure a REST API using token based authentication. I am developing the API in Python using Flask and have discovered the flask-security extension which seems to have a lot of interesting features.
One of the features mentioned in the documentation is Token Authentication.
According to the documentation:
Token based authentication is enabled by retrieving the user auth
token by performing an HTTP POST with the authentication details as
JSON data against the authentication endpoint. A successful call to
this endpoint will return the user’s ID and their authentication
token. This token can be used in subsequent requests to protected
resources.
I am however still a bit confused on how to implement this feature using flask-security.
Some online research has led me to using things such as #auth_token_required but I am having some trouble to put everything together. The flask-security documentation itself is not very helpful.
For example, how can a user get an authentication token? what is the authentication endpoints?
It would be great if you could lead me in the right direction. Code examples would be awesome too :-)
Endpoint is /login, you post your credentials as json request body:
{'email':'john#smit.com', 'password':'1234'}
However for this to work you need to disable the csrf tokens in your flask app (thanks Mandar Vaze):
app.config['WTF_CSRF_ENABLED'] = False
Then you do each request with the token in the HTTP headers:
Authentication-Token:WyI1NTE1MjhmNDMxY2Q3NTEwOTQxY2ZhYTgiLCI2Yjc4NTA4MzBlYzM0Y2NhZTdjZjIxNzlmZjhiNTA5ZSJd.B_bF8g.t1oUMxHr_fQfRUAF4aLpn2zjja0
Or as query string:
http://localhost:5000/protected?auth_token=WyI1NTE1MjhmNDMxY2Q3NTEwOTQxY2ZhYTgiLCI2Yjc4NTA4MzBlYzM0Y2NhZTdjZjIxNzlmZjhiNTA5ZSJd.B_bF8g.t1oUMxHr_fQfRUAF4aLpn2zjja0
Client example in python 3:
import requests
import json
#do the login
r = requests.post('http://localhost:5000/login',
data=json.dumps({'email':'john#smit.com', 'password':'1234'}),
headers={'content-type': 'application/json'})
response = r.json()
print(response) #check response
token = response['response']['user']['authentication_token'] #set token value
#Now you can do authorised calls
r = requests.get('http://localhost:5000/protected',
headers={'Authentication-Token': token})
print(r.text)
Angular example snippet to obtain the token:
$http.post('/login', {"email": $scope.formdata.login,"password":$scope.formdata.password}).
success(function(results) {
$window.sessionStorage.token = results.response.user.authentication_token;
});
Angular example snippet to visit protected pages:
if ($window.sessionStorage.getItem('token')) {
config.headers['Authentication-Token'] = $window.sessionStorage.getItem('token');
}
I found Flask-Security's token-based not a good candidate for my project. I recommend using JWT token instead.
The problems with Flask-Security's token based authentication.
Need to disable CSRF globally, this is not good when you also have a traditional web application in which CSRF token is desirable
No easy way to renew the token ( without submitting password again )
Can not control the payload of the token, there's no API to put/get data to/from the token
That token, by design, only works with one Flask app. So if your frontend app needs to talk with multiple restful apis, this wont work well
Check out JWT (pyjwt or flask-jwt) token, it solves all the above problems and more.
Authentication endpoint is /login
Look at the code of flask-security here specifically views.py: _render_json()
login() calls _render_json which in turn calls get_auth_token() - and returns the auth token.
Problem (for me) is to get this to work.
For me request.json seems empty (hence this does not work)
{"email": "test#example.com", "password": "test123"}
Hopefully this helps you move forward a little.

Resources