Python Requests Login to Login With Amazon to get Access Token for Amazon Advertising API - oauth-2.0

I am trying to use python requests to receive my access token for the Amazon Advertising API. The procedure is outlined here: https://advertising.amazon.com/API/docs/v2/guides/authorization Here is what I tried
CLIENT_ID = MyClientID
CLIENT_SECRET = MySecret
RETURN_URL = 'https://myreturn.com/my.php'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.61 Safari/537.36',
}
with requests.Session() as s:
s.headers = headers
r = s.get('https://www.amazon.com/ap/oa?client_id={}&scope=cpc_advertising:campaign_management&error=access_denied&response_type=code&redirect_uri={}'.format(CLIENT_ID,RETURN_URL),headers=headers)
soup = BeautifulSoup(html)
data = {}
form = soup.find('form', {'name': 'signIn'})
for field in form.find_all('input'):
try:
data[field['name']] = field['value']
except:
pass
data[u'email'] = MY_EMAIL
data[u'password'] = MY_PASS
b = s.post('https://www.amazon.com/ap/oa?client_id={}&scope=cpc_advertising:campaign_management&response_type=code&redirect_uri={}',data=data,allow_redirects=True,headers=headers)
i get an error_description=User+not+authenticated&error=access_denied error, what am I doing wrong here?

You DON'T NEED Username and Password in your Python Script to authenticate!
What you need is CLIENT_ID, SCOPE and REDIRECT_URI and three requests:
Get authorization code:
GET https://www.amazon.com/ap/oa?client_id={{CLIENT_ID}}&scope={{SCOPE}}&response_type=code&redirect_uri={{REDIRECT_URI}}
This will open the 'Login with Amazon' Consent Page, where you (or your customer) log into your Amazon Seller Central account and grant access to the Console APP with API access rights.
Request tokens
POST https://api.amazon.com/auth/o2/token
with headers:
Content-Type:application/x-www-form-urlencoded
with body data:
grant_type:authorization_code
code:{{AUTH_CODE}} <----- returned from step 1
client_id:{{CLIENT_ID}}
client_secret:{{CLIENT_SECRET}}
redirect_uri:{{REDIRECT_URI}}
Get/Refresh access token (every time it is outdated):
POST https://api.amazon.com/auth/o2/token
with headers:
Content-Type:application/x-www-form-urlencoded
charset:UTF-8
with body data:
grant_type:refresh_token
refresh_token:{{REFRESH_TOKEN}} <------ returned from step 2
client_id:{{CLIENT_ID}}
client_secret:{{CLIENT_SECRET}}
With the CLIENT_ID and (fresh) access token you can now request every service from the API. For excample listCampaigns:
GET https://advertising-api.amazon.com/v2/sp/campaigns
Headers:
Content-Type:application/json
Amazon-Advertising-API-ClientId:{{CLIENT_ID}}
Amazon-Advertising-API-Scope:{{PROFILE_ID}}
Authorization:Bearer {{ACCESS_TOKEN}} <----- returned from step 3

Related

Open URL using Groovy receives status 403

I am trying to read the contents of a web page using a Groovy script. The page contains the readings from one of my temperature sensors that I want to save regularly. I have tried the simplest variant:
def url = "https://measurements.mobile-alerts.eu/Home/MeasurementDetails?deviceid=021B5594EAB5&vendorid=60122a8b-b343-49cb-918b-ad2cdd6dff16&appbundle=eu.mobile_alerts.mobilealerts&fromepoch=1674432000&toepoch=1674518400&from=23.01.2023%2000:00&to=24.01.2023%2000:00&command=refresh"
def res = url.toURL().getText()
println( res)
The result is:
Caught: java.io.IOException: Server returned HTTP response code: 403 for URL: (my url)
In any browser, this URL works without problems.
I would be very grateful for any tips on how to solve this problem.
HTTP code 403 means that a client is forbidden from accessing a valid URL. In other words, the server knows that you are not making a request via a web browser. To bypass this restriction, you need to specify a User-Agent in the request header.
For example:
def url = 'https://measurements.mobile-alerts.eu/Home/MeasurementDetails?deviceid=021B5594EAB5&vendorid=60122a8b-b343-49cb-918b-ad2cdd6dff16&appbundle=eu.mobile_alerts.mobilealerts&fromepoch=1674432000&toepoch=1674518400&from=23.01.2023%2000:00&to=24.01.2023%2000:00&command=refresh'
def res = url.toURL().getText(requestProperties:
['User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0'])
println res
You can switch to other valid user-agent values.

How to get the complete URL by making a google search with BS4 and Requests

So, I was making a program that will search google and fetch all the results for a given keyword. I wanted to get all the URLs and print them out to the screen, and I decided to use BS4 for this and this is how I did it:
r = requests.get(f'https://www.google.com/search?q={dork}&start={page}',headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:54.0) Gecko/20100101 Firefox/54.0'})
soup = BeautifulSoup(r.text, "html.parser")
urls = soup.find_all('div', attrs={'class': 'BNeawe UPmit AP7Wnd'})
for url in urls:
url = url.split('<div class="BNeawe UPmit AP7Wnd">')[1].split('</div>')[0]
url = url.replace(' › ','/')
print(f'{Fore.GREEN}{url}{Fore.WHITE}')
open(f'results/{timeLol}/urls.txt', "a")
But, it did not return the complete URL instead, if the URL was big it returned ... after some of the URL, is there any way at all to get the complete URL even if it is not using BS4 and Requests.
Any search query example would be appreciated.
While you don't provide query example, you can try to use bs4 css selectors (css selectors reference):
for result in soup.select('.tF2Cxc'):
link = result.select_one('.yuRUbf a')['href']
# https://spicysouthernkitchen.com/best-way-to-cook-corn-on-the-cob/
# other URLs below...
Code and example in the online IDE that scrapes more:
import requests, lxml
from bs4 import BeautifulSoup
headers = {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3538.102 Safari/537.36 Edge/18.19582"
}
params = {'q': 'how to cook best corn on the cob'}
html = requests.get('https://www.google.com/search', headers=headers, params=params)
soup = BeautifulSoup(html.text, 'lxml')
# container with all needed data
for result in soup.select('.tF2Cxc'):
link = result.select_one('.yuRUbf a')['href']
print(link)
---------
'''
https://spicysouthernkitchen.com/best-way-to-cook-corn-on-the-cob/
https://www.allrecipes.com/recipe/222352/jamies-sweet-and-easy-corn-on-the-cob/
https://www.delish.com/cooking/a22487458/corn-on-the-cob/
https://www.thekitchn.com/best-method-cook-corn-skills-showdown-23045869
https://natashaskitchen.com/15-minute-corn-on-the-cob/
https://www.thegunnysack.com/how-long-to-boil-corn-on-the-cob/
https://www.epicurious.com/recipes/food/views/basic-method-for-cooking-corn-on-the-cob-40047
https://houseofnasheats.com/the-best-boiled-corn-on-the-cob/
https://www.tasteofhome.com/article/perfect-corn-on-the-cob/
'''
Alternatively, you can do the same thing using Google Search Results API from SerpApi, but without thinking about how to parse stuff since it's already done for the end user. All that needs to be done is just to iterate over structured JSON string.
It's a paid API with a free plan.
Code to integrate:
from serpapi import GoogleSearch
import os
params = {
"api_key": os.getenv("API_KEY"),
"engine": "google",
"q": "how to cook best corn on the cob",
"hl": "en",
}
search = GoogleSearch(params)
results = search.get_dict()
for result in results['organic_results']:
link = result['link']
print(link)
----------
'''
https://spicysouthernkitchen.com/best-way-to-cook-corn-on-the-cob/
https://www.allrecipes.com/recipe/222352/jamies-sweet-and-easy-corn-on-the-cob/
https://www.delish.com/cooking/a22487458/corn-on-the-cob/
https://www.thekitchn.com/best-method-cook-corn-skills-showdown-23045869
https://natashaskitchen.com/15-minute-corn-on-the-cob/
https://www.thegunnysack.com/how-long-to-boil-corn-on-the-cob/
https://www.epicurious.com/recipes/food/views/basic-method-for-cooking-corn-on-the-cob-40047
https://houseofnasheats.com/the-best-boiled-corn-on-the-cob/
https://www.tasteofhome.com/article/perfect-corn-on-the-cob/
'''
Disclaimer, I work for SerpApi.

Initiate SingleSignOn by Saml2PostBinding

I am having an issue when using ITfoxtec for ASP.NET Core 3.0.
As context I am trying to establish a connection between a webapplication and a third-party login service. To encapsulate some of the possibilities beforehand, the third-party has access to our metadata-url and configured their services for our webapplication.
Desired user workflow:
User enters the webapplication;
User clicks a button which redirects the user to the login service;
User logs in on the service and redirects back to the given returnURL;
Afterwards the webapplication determines permission based on the provided sso-cookie.
Steps taken so far:
Added Saml2 section in appsettings.json containing our metadata.xml and issuer. The issuer name equals the given EntityID provided within the metadata.xml. It is made anonymous in the given context, like so:
"Saml2": {
"IdPMetadata": "wwwroot/SAML/Metadata.xml",
"Issuer": "myIssuerName",
"SignatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
"CertificateValidationMode": "ChainTrust",
"RevocationMode": "NoCheck",
"SigningCertificateFile": "\\licenses\\certificate.pfx",
"SigningCertificatePassword": "password1"
},
Added Saml2Configuration in startup.cs;
services
.Configure<Saml2Configuration>(Configuration.GetSection("Saml2"))
.Configure<Saml2Configuration>(configuration =>
{
configuration.SigningCertificate = CertificateUtil.Load(
$"{Environment.WebRootPath}{Configuration["Saml2:SigningCertificateFile"]}",
Configuration["Saml2:SigningCertificatePassword"]);
configuration.AllowedAudienceUris.Add(configuration.Issuer);
var entityDescriptor = new EntityDescriptor();
entityDescriptor.ReadIdPSsoDescriptorFromFile(Configuration["Saml2:IdpMetadata"]);
if (entityDescriptor.IdPSsoDescriptor == null) throw new Exception("Failed to read the metadata.");
configuration.SignAuthnRequest = true;
configuration.SingleSignOnDestination = entityDescriptor.IdPSsoDescriptor.SingleSignOnServices
.Where(ed => ed.Binding.ToString() == "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")
.First().Location;
configuration.SignatureValidationCertificates.AddRange(entityDescriptor.IdPSsoDescriptor.SigningCertificates);
});
Here comes the tricky part; By default the sso initiation does a request with a RedirectBinding which does therefore send a GET request towards the sso service. However, the service I am trying to approach expects a SAMLRequest as a POST request. So I have changed the code by initiating with PostBinding request and afterwards directly submit the form, like so:
public IActionResult Initiate([FromQuery(Name = "returnUrl")] string returnUrl = "")
{
var binding = new Saml2PostBinding();
binding.SetRelayStateQuery(new Dictionary<string, string> { { "ReturnUrl", returnUrl } });
binding.Bind(new Saml2AuthnRequest(_saml2configuration)
{
ForceAuthn = false,
IsPassive = false,
NameIdPolicy = new NameIdPolicy() { AllowCreate = true },
AssertionConsumerServiceUrl = new Uri("https://localhost:44366/api/Authentication/Process"),
});
return binding.ToActionResult();
}
Issue:
However, after sending the base64 encoded AuthnRequest as SAML Request, I am receiving a 403 Forbidden from the third-party login. At this stage I am not certain whether is the identity provider not being configured properly or my request lacking something. What am I doing wrong?
Below is the (anonymously made) request headers.
Assume that the SAMLRequest is provided in formdata as base64 encoded.
:authority: myEntityDescriptorName
:method: POST
:path: mySsoURL
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
accept-encoding: gzip, deflate, br
accept-language: nl-NL,nl;q=0.9,en-US;q=0.8,en;q=0.7
cache-control: no-cache
content-length: 3582
content-type: application/x-www-form-urlencoded
cookie: JSESSIONID=3D5FE88D55674C2F1E3646E6D8A0FFBE
origin: https://localhost:44366
pragma: no-cache
referer: https://localhost:44366/
sec-fetch-mode: navigate
sec-fetch-site: cross-site
sec-fetch-user: ?1
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36
It is correct to change the Authn Request to a Post binding if that is required.
Your application is a Service Provider (also called Relying Party) which needs to be configured at the Identity Provider with a unique Issuer name.
I think the problem is that the Issuer name you have configured ("Issuer": "myIssuerName") is incorrect. The issuer name should be your Service Providers issuer name, not the Identity Provider Issuer name from the metadata.xml.

hipchat oauth token internal server error

I follow hipchat site and try to get an add-on token
https://developer.atlassian.com/hipchat/guide/hipchat-rest-api/api-access-tokens?_ga=2.94621780.975509804.1497491262-871504840.1479901346#APIaccesstokens-Add-ongeneratedtokens
I have the following code:
import requests
secret = 'hipchat_secret'
headers = {'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic {}'.format(secret)}
url = 'https://api.hipchat.com/v2/oauth/token?grant_type=client_credentials&scope=send_notification+admin_room'
res = requests.post(url, headers=headers)
But it gives me a 500 Internal Server Error. What is wrong with my code?
The mistake was I used v1 token.
It works perfect when I switch to v2

OAuth2 Web API 2 authentication

I'm learning how to secure a test API that I'm building and I want to implement security where a user signs up and then he requests an API Key which he will use in his app to authenticate to my API.
I started to implement this: https://github.com/vchatterji/OAuth2ClientCredentialGrant and I got the first part working where a user can signup and then request and receive a ConsumerKey & ConsumerSecret which is saved in an Azure table.
My problem is that I'm not sure what Flow I'm using The documentation doesn't state to change anything in StartupAuth:
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
I'm trying to authenticate with Fiddler and have tried many different requests but my most common error is unsupported grant type.
Based on what I have here what kind of grant type should I use?
Above it says to authenticate at /Token but other docs say api/token, which is the correct one?
Any help with composing the auth request would be greatly appreciated.
I was having the same issue for not having the data sent in the body of the request... Like this:
POST http://localhost:60543/oauth/token HTTP/1.1
Host: localhost:60543
Connection: keep-alive
Content-Length: 54
Cache-Control: no-cache
Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36
Postman-Token: 85363928-a3d6-f9ad-c368-ab6019027a02
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en,fr;q=0.8,pt-PT;q=0.6,pt;q=0.4,en-US;q=0.2,es;q=0.2
username=peter&password=123456&grant_type=password
Make sure to set the content type in the header of the request.

Resources