I am going through Evernote OAuth documentation. Was not able to get the temp token. It was resolved after receiving help here. Now, struck at the last step of this flow while receiving Access token. Could you someone let me know what could be the potential issue here?
Its following the similar below to the first one to retrieve the access token. Not sure if there is anything I miss.
import time
import base64
import random
import uuid
import urllib
import collections
import urllib.parse
import hmac
import hashlib
import binascii
import requests
def escape(s):
return urllib.parse.quote(s, safe='~')
def get_nonce():
return uuid.uuid4().hex
def stringify_parameters(parameters):
output = ''
ordered_parameters = {}
ordered_parameters =collections.OrderedDict(sorted(parameters.items()))
counter = 1
for k, v in ordered_parameters.items():
output += escape(str(k)) + '=' + escape(str(v))
if counter < len(ordered_parameters):
output += '&'
counter += 1
return output
oauth_parameters={
'oauth_timestamp': str(int(time.time())),
'oauth_signature_method': "HMAC-SHA1",
'oauth_version': "1.0",
'oauth_nonce': get_nonce(),
'oauth_consumer_key': 'xxxxx',
'oauth_callback':'http://localhost'
}
string_parameters=stringify_parameters(oauth_parameters)
secret='3************f'
### below portion of the code will return temp_token
key = (escape(secret)+'&').encode()
message = ('GET&' + escape('https://sandbox.evernote.com/oauth') + '&' + escape(string_parameters)).encode()
signature = hmac.new(key, message, hashlib.sha1).digest()
oauth_parameters['oauth_signature'] = base64.b64encode(signature).decode()
print(stringify_parameters(oauth_parameters))
res = requests.get('https://sandbox.evernote.com/oauth?' + stringify_parameters(oauth_parameters))
print(res.text)
####
##login to the url below based on the temp_token from above
##https://sandbox.evernote.com/OAuth.action?oauth_token=xxxxx.1652F9812D6.687474703A2F2F6C6F63616C686F7374.3A695C3760E6EFB92B3AB6033222E9D7
## after successful authorization from user, page is redirected along with 'oauth_verifier' value
##http://localhost/?oauth_token=xxxxx.1652F9812D6.687474703A2F2F6C6F63616C686F7374.3A695C3760E6EFB92B3AB6033222E9D7&oauth_verifier=1808C99D6868D17A89871E9290B334D6&sandbox_lnb=false
###error part - below doesn't work while retrieving the access token.
oauth_parameters={
'oauth_consumer_key': 'xxxxx',
'oauth_token': 'xxxxx.1652F9812D6.687474703A2F2F6C6F63616C686F7374.3A695C3760E6EFB92B3AB6033222E9D7',
'oauth_verifier':'1808C99D6868D17A89871E9290B334D6',
'oauth_nonce': get_nonce(),
'oauth_signature_method':'HMAC-SHA1',
'oauth_timestamp': str(int(time.time())),
'oauth_version': '1.0'
}
string_parameters=stringify_parameters(oauth_parameters)
key = (escape(secret)+'&').encode()
message = ('GET&' + escape('https://sandbox.evernote.com/oauth') + '&' + escape(string_parameters)).encode()
signature = hmac.new(key, message, hashlib.sha1).digest()
oauth_parameters['oauth_signature'] =
base64.b64encode(signature).decode()
res = requests.get('https://sandbox.evernote.com/oauth?' +
stringify_parameters(oauth_parameters))
print(res.text)
The only thing I can think of without knowing what the error message is (if there is any), is whether the oauth_verifier is copied over correctly. Everything else looks like it should work fine.
Related
How do I implement the below python/Java/PHP code in NodeJs?
ReferenceLink
Python Code (for reference):
import hashlib
import hmac
import base64
#app.route('/notify_url/', methods=["POST"])
def notify_url_process():
postData = {
"orderId" : request.form['orderId'],
"orderAmount" : request.form['orderAmount'],
"referenceId" : request.form['referenceId'],
"txStatus" : request.form['txStatus'],
"paymentMode" : request.form['paymentMode'],
"txMsg" : request.form['txMsg'],
"txTime" : request.form['txTime'],
}
signatureData = postData["orderId"] + postData["orderAmount"] + postData["referenceId"] + postData["txStatus"] + postData["paymentMode"] + postData["txMsg"] + postData["txTime"]
message = bytes(signatureData).encode('utf-8')
#get secret key from your config
secret = bytes(secretKey).encode('utf-8')
signature = base64.b64encode(hmac.new(secret,
message,digestmod=hashlib.sha256).digest())
So far, I was able to come up with the below code. However, the generated and received signatures do not match.
var hmac = crypto.createHmac('sha256', "appSecret"); //Key hidden for posting here
hmac.update(request.body.orderId + request.body.orderAmount+request.body.referenceId+request.body.txStatus+request.body.paymentMode+request.body.txMsg+request.body.txTime);
let generatedSignature = hmac.digest('hex');
let isSignatureValid = generatedSignature == request.body.cashfreeSignature;
console.log(isSignatureValid);
Have you tried comparing the base64 encoding as opposed to the hex value?
Instead of
let generatedSignature = hmac.digest('hex');
use
let generatedSignature = hmac.digest('base64');
[This is my code]
import requests
# after post code>
# ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SmxlSEFpT2pFMU9UUTJOalU1TmpBc0lrMXZaR1ZzSWpwN0lrTm9ZWEpoWTNSbGNuTlFaWEpFWVhraU9qVXdNREF3TENKVmMyVnlTV1FpT2pNMk16SXNJbFZ1YVhGMVpVbGtJam9pTnpObE5UVTNPR1l0WW1FMk5TMDBaVGt3TFRoallXVXRZMlEzWWpWaVlUZ3hORGhsSW4xOS5YRjFoZDltQ2hGRkpKel96UXZ5TFNJcXhTZFpucklWeXppZ1R6NWJCVHBV
URL_AUTH = 'https://developers.lingvolive.com/api/v1.1/authenticate'
URL_TRANSLATE = 'https://developers.lingvolive.com/api/v1/Minicard'
KEY = 'NzNlNTU3OGYtYmE2NS00ZTkwLThjYWUtY2Q3YjViYTgxNDhlOjc4NDM0MDRmMjNmODRlMTc5MzJlNTRiNThhMGM4MGQy' # key before post
headers_auth = {"Authorization": "Basic" + KEY}
auth = requests.post(URL_AUTH, headers=headers_auth)
print(auth)
This is Postman
KEY - Authorization
VALUE - Basic NzNlNTU3OGYtYmE2NS00ZTkwLThjYWUtY2Q3YjViYTgxNDhlOjc4NDM0MDRmMjNmODRlMTc5MzJlNTRiNThhMGM4MGQy
When I write auth.text, there is no output in the console
import requests
# after post code>
# ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SmxlSEFpT2pFMU9UUTJOalU1TmpBc0lrMXZaR1ZzSWpwN0lrTm9ZWEpoWTNSbGNuTlFaWEpFWVhraU9qVXdNREF3TENKVmMyVnlTV1FpT2pNMk16SXNJbFZ1YVhGMVpVbGtJam9pTnpObE5UVTNPR1l0WW1FMk5TMDBaVGt3TFRoallXVXRZMlEzWWpWaVlUZ3hORGhsSW4xOS5YRjFoZDltQ2hGRkpKel96UXZ5TFNJcXhTZFpucklWeXppZ1R6NWJCVHBV
URL_AUTH = 'https://developers.lingvolive.com/api/v1.1/authenticate'
URL_TRANSLATE = 'https://developers.lingvolive.com/api/v1/Minicard'
KEY = 'NzNlNTU3OGYtYmE2NS00ZTkwLThjYWUtY2Q3YjViYTgxNDhlOjc4NDM0MDRmMjNmODRlMTc5MzJlNTRiNThhMGM4MGQy' # key before post
headers_auth = {"Authorization": "Basic" + KEY}
auth = requests.post(URL_AUTH, headers=headers_auth)
print(auth.text)
Request: https://i.stack.imgur.com/rSPhO.png
Postman: https://i.stack.imgur.com/z2fLL.png
After running the program gives Error 401. I have triple checked all the information. Do you know how to solve this issue?
I think you need a space between "Basic" and the key, try
"Basic " + KEY
You should print the whole information in the response, in order to know more details about the error, hence I would add print(auth.text).
I've been trying to get this to work for hours now. None of the solutions on other questions are working.
What I'm trying to do is get my list of orders on Amazon. To do this, I am making a call to Amazon MWS. However, this is the error message I am getting:
<?xml version="1.0"?>
<ErrorResponse xmlns="https://mws.amazonservices.com/Orders/2013-09-01">
<Error>
<Type>Sender</Type>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message>
</Error>
<RequestID>03686743-15a6-4207-b0b7-316d1e4e5c8f</RequestID>
</ErrorResponse>
To find out what was wrong, I went onto Amazon MWS Scratchpad and used the same values, even the timestamp (I think you have 15 minutes until it expires), and compared the signatures. They were the same. However, my program still got the same error while the scratchpad worked perfectly.
Here is all the code:
import sys, os, base64, datetime, hashlib, hmac, urllib
from time import gmtime, strftime
from requests import request
import xml.etree.ElementTree as ET
def get_timestamp():
"""Return correctly formatted timestamp"""
return strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())
def calc_signature():
"""Calculate signature to send with request"""
sig_data = method + '\n' + domain.replace('https://', '').lower() + '\n' + URI + '\n' + request_description
hmac_obj = hmac.new(str(SECRET_KEY), sig_data, hashlib.sha256)
return urllib.quote(base64.b64encode(hmac_obj.digest()), safe='-_.~')
SECRET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
AWS_ACCESS_KEY = 'xxxxxxxxxxxxxxxxxxx'
SELLER_ID = 'xxxxxxxxxxxxxxxxxxxxxxx'
MARKETPLACE_ID = 'xxxxxxxxxxxxxxx'
Action = 'ListOrders'
SignatureMethod = 'HmacSHA256'
SignatureVersion = '2'
Timestamp = get_timestamp()
Version = '2013-09-01'
CreatedAfter = '2014-08-26T23:00:57Z' # TODO -1 day
URI = '/Orders/2013-09-01'
domain = 'https://mws.amazonservices.co.uk'
method = 'POST'
payload = {'AWSAccessKeyId': AWS_ACCESS_KEY,
'Action': Action,
'SellerId': SELLER_ID,
'SignatureVersion': SignatureVersion,
'Timestamp': Timestamp,
'Version': Version,
'SignatureMethod': SignatureMethod,
'CreatedAfter': '2014-08-26T23:00:00Z',
'MarketplaceId.Id.1': MARKETPLACE_ID
}
request_description = '&'.join(['%s=%s' % (k, urllib.quote(payload[k], safe='-_.~').encode('utf-8')) for k in sorted(payload)])
sig = calc_signature()
url = '%s%s?%s&Signature=%s' % (domain, URI, request_description, urllib.quote(sig))
headers = {'Host': 'amazonwebservices.co.uk', 'Content-Type': 'text/xml', 'x-amazon-user-agent': 'python-requests/1.2.0 (Language=Python)'}
response = request(method, url, headers=headers)
print response.content
Here's a print of sig_data in calc_signature():
POST
mws.amazonservices.co.uk
/Orders/2013-09-01
AWSAccessKeyId=xxxxxxxxxxxxx&Action=ListOrders&CreatedAfter=2014-08-26T23%3A00%3A00Z&MarketplaceId.Id.1=xxxxxxxxxxxxx&SellerId=xxxxxxxxxxxxxxx&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2014-08-28T15%3A50%3A34Z&Version=2013-09-01
Here's a print of url:
https://mws.amazonservices.co.uk/Orders/2013-09-01?AWSAccessKeyId=xxxxxxxxxxxx&Action=ListOrders&CreatedAfter=2014-08-26T23%3A00%3A00Z&MarketplaceId.Id.1=xxxxxxxxxxxx&SellerId=xxxxxxxxxxxxx&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2014-08-28T15%3A50%3A34Z&Version=2013-09-01&Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
I am completely out of ideas at this point. I have triple checked that my secret key, access key, seller ID and marketplace ID are correct.
Any help would be massively, massively appreciated!
I know this is a few months late but I had the exact same issue despite knowing my signature was correct and found out it was in fact the POST execution that was the problem and not the signature. If Amazon can't understand your params, it will throw an HTTP 403 error and tell you your signature is wrong even though it's not. I can't tell you why it works this way but try skipping the requests library and doing the following using urllib.request after building your url instead which worked for me:
#using python 3.4
import urllib.request
#... your code from before...
headers = {'Host': 'mws.amazonservices.com', 'Content-Type': 'text/xml', 'x-amazon-user-agent': 'SomeApp/1.1 (Language=Python)'}
req = urllib.request.Request(method=method,url=url,headers=headers)
response = urllib.request.urlopen(req)
the_page = response.read()
print(the_page)
#As seen here: https://docs.python.org/3/howto/urllib2.html#data
If that doesn't do it, take a second look at how you encoded everything and maybe dabble with urllib.parse.
Happy Amazoning!
Inside your calc_signature function, your safe parameter isn't allowing + and / which are allowed in the base64 output character set. As a result, it is percent-encoding them, and then those percents get further perecnt-encoded as %25s in the query string.
I made some additional changes, so here's all the code:
import sys, os, base64, datetime, hashlib, hmac, urllib
from time import gmtime, strftime
from requests import request
import xml.etree.ElementTree as ET
def get_timestamp():
"""Return correctly formatted timestamp"""
return strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())
def calc_signature(method, domain, URI, request_description, key):
"""Calculate signature to send with request"""
sig_data = method + '\n' + \
domain.lower() + '\n' + \
URI + '\n' + \
request_description
hmac_obj = hmac.new(key, sig_data, hashlib.sha256)
digest = hmac_obj.digest()
return urllib.quote(base64.b64encode(digest), safe='-_+=/.~')
SECRET_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
AWS_ACCESS_KEY = 'XXXXXXXXXXXXXX'
SELLER_ID = 'XXXXXXXXXXXXX'
MARKETPLACE_ID = 'XXXXXXXXXXXX'
Action = 'ListOrders'
SignatureMethod = 'HmacSHA256'
SignatureVersion = '2'
Timestamp = get_timestamp()
Version = '2013-09-01'
CreatedAfter = '2013-08-26T23:00:57Z'
URI = '/Orders/2013-09-01'
domain = 'mws.amazonservices.com'
proto = 'https://'
method = 'POST'
payload = {
'AWSAccessKeyId': AWS_ACCESS_KEY,
'Action': Action,
'SellerId': SELLER_ID,
'SignatureVersion': SignatureVersion,
'Timestamp': Timestamp,
'Version': Version,
'SignatureMethod': SignatureMethod,
'CreatedAfter': CreatedAfter,
'MarketplaceId.Id.1': MARKETPLACE_ID
}
request_description = '&'.join(['%s=%s' % (k, urllib.quote(payload[k], safe='-_.~').encode('utf-8')) for k in sorted(payload)])
sig = calc_signature(method, domain, URI, request_description, SECRET_KEY)
url = '%s%s?%s&Signature=%s' % \
(proto+domain, URI, request_description, urllib.quote(sig))
headers = {
'Host': domain,
'Content-Type': 'text/xml',
'x-amazon-user-agent': 'python-requests/1.2.0 (Language=Python)'
}
response = request(method, url, headers=headers)
print response.content
i'm trying to access twitter using the api
i created an app and checked "Allow this application to be used to Sign in with Twitter", then i followed these steps:
https://dev.twitter.com/docs/api/1/post/oauth/request_token
https://dev.twitter.com/docs/auth/authorizing-request
https://dev.twitter.com/docs/auth/creating-signature
but i'm getting
urllib2.HTTPError: HTTP Error 401: Unauthorized
so i must have done something wrong or missed something
can somebody spot my mistake?
import urllib2
import time
import urllib
import hashlib
import hmac
import base64
def escape(s):
return urllib.quote(s, safe='~')
consumer_key = 'yBsHl3G6MqXx9JpnoLoGbA'
consumer_secret = 'JBk5oUDLSuNAXxdBHrDmoUFxemw7IJ1a2yWPmCydX7w'
http_method = 'POST'
base_url = 'https://api.twitter.com/oauth/request_token'
oauth_token_secret = ''
data={'oauth_callback':'http://localhost.de:8000/accounts/callback/twitter'}
header = {
'oauth_consumer_key': consumer_key,
'oauth_timestamp': str(int(time.time())),
'oauth_nonce': hashlib.md5(str(time.clock())).hexdigest(),
'oauth_version': '1.0',
'oauth_signature_method': 'HMAC-SHA1'
}
header.update(data)
paramstr = ''
for k in sorted(header):
paramstr+=escape(k)+'='+escape(header[k])+'&'
paramstr = paramstr[:-1]
print paramstr
sig_base_str = http_method.upper()+'&'+escape(base_url)+'&'+escape(paramstr)
print sig_base_str
key = escape(consumer_secret)+'&'+escape(oauth_token_secret)
signature = base64.b64encode(hmac.new(key, sig_base_str, hashlib.sha1).digest())
header['oauth_signature'] = signature
header_str = 'OAuth '
for k in sorted(header):
header_str+=escape(k)+'="'+escape(header[k])+'", '
header_str = header_str[:-2]
print header_str
req=urllib2.Request(base_url, data=urllib.urlencode(data))
req.add_header('Authorization', header_str)
print urllib2.urlopen(req).read()
i know there are libs for doing this, but i would like to write my own code for testing purposes
i solved it myself. the twitter docs are not 100% correct.
for example here
https://dev.twitter.com/docs/api/1/post/oauth/request_token
they say that the authorization header should look like this
OAuth oauth_nonce="K7ny27JTpKVsTgdyLdDfmQQWVLERj2zAK5BslRsqyw", oauth_callback="http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1300228849", oauth_consumer_key="OqEqJeafRSF11jBMStrZz", oauth_signature="Pc%2BMLdv028fxCErFyi8KXFM%2BddU%3D", oauth_version="1.0"
but this is wrong, you should not add oauth_callback="http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback" to the authorization header
I'm having an awfully hard time with Yahoo's authentication/authorization. I've enabled BOSS in my account, set up a payment method, and now I'm trying to run a search using some python code:
import urllib2
import oauth2 as oauth
import time
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
def oauth_request(url, params, method="GET"):
params['oauth_version'] = "1.0",
params['oauth_nonce'] = oauth.generate_nonce(),
params['oauth_timestamp'] = int(time.time())
consumer = oauth.Consumer(key=OAUTH_CONSUMER_KEY,
secret=OAUTH_CONSUMER_SECRET)
params['oauth_consumer_key'] = consumer.key
req = oauth.Request(method=method, url=url, parameters=params)
req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, None)
return req
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web"
req = oauth_request(url, params={"q": "cats dogs"})
req_url = req.to_url()
print req_url
result = urllib2.urlopen(req_url)
I keep getting a urllib2.HTTPError: HTTP Error 401: Unauthorized exception. I can't figure out whether there's something wrong with my key, or the method of signing, or if I'm somehow tampering with my data after signing, or what the deal is. Anyone have suggestions?
I made some small changes to make your example work. See code for comments.
import urllib2
import oauth2 as oauth
import time
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
def oauth_request(url, params, method="GET"):
# Removed trailing commas here - they make a difference.
params['oauth_version'] = "1.0" #,
params['oauth_nonce'] = oauth.generate_nonce() #,
params['oauth_timestamp'] = int(time.time())
consumer = oauth.Consumer(key=OAUTH_CONSUMER_KEY,
secret=OAUTH_CONSUMER_SECRET)
params['oauth_consumer_key'] = consumer.key
req = oauth.Request(method=method, url=url, parameters=params)
req.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer, None)
return req
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web"
req = oauth_request(url, params={"q": "cats dogs"})
# This one is a bit nasty. Apparently the BOSS API does not like
# "+" in its URLs so you have to replace "%20" manually.
# Not sure if the API should be expected to accept either.
# Not sure why to_url does not just return %20 instead...
# Also, oauth2.Request seems to store parameters as unicode and forget
# to encode to utf8 prior to percentage encoding them in its to_url
# method. However, it's handled correctly for generating signatures.
# to_url fails when query parameters contain non-ASCII characters. To
# work around, manually utf8 encode the request parameters.
req['q'] = req['q'].encode('utf8')
req_url = req.to_url().replace('+', '%20')
print req_url
result = urllib2.urlopen(req_url)
Here is a Python code snippet that works for me against Yahoo! BOSS:
import httplib2
import oauth2
import time
OAUTH_CONSUMER_KEY = "Blah"
OAUTH_CONSUMER_SECRET = "Blah"
if __name__ == "__main__":
url = "http://yboss.yahooapis.com/ysearch/web?q=cats%20dogs"
consumer = oauth2.Consumer(key=OAUTH_CONSUMER_KEY,secret=OAUTH_CONSUMER_SECRET)
params = {
'oauth_version': '1.0',
'oauth_nonce': oauth2.generate_nonce(),
'oauth_timestamp': int(time.time()),
}
oauth_request = oauth2.Request(method='GET', url=url, parameters=params)
oauth_request.sign_request(oauth2.SignatureMethod_HMAC_SHA1(), consumer, None)
oauth_header=oauth_request.to_header(realm='yahooapis.com')
# Get search results
http = httplib2.Http()
resp, content = http.request(url, 'GET', headers=oauth_header)
print resp
print content
Im using an Authenticate Header to submit the OAuth signature.
So I decided to ditch Python and try Perl, and it Just Worked. Here's a minimal code sample:
use strict;
use Net::OAuth;
use LWP::UserAgent;
my $CC_KEY = "blahblahblah";
my $CC_SECRET = "blah";
my $url = 'http://yboss.yahooapis.com/ysearch/web';
print make_request($url, {q => "cat dog", format => "xml", count => 5});
sub make_request {
my ($url, $args) = #_;
my $request = Net::OAuth->request("request token")
->new(
consumer_key => $CC_KEY,
consumer_secret => $CC_SECRET,
request_url => $url,
request_method => 'GET',
signature_method => 'HMAC-SHA1',
timestamp => time,
nonce => int(rand 10**6),
callback => 'oob',
extra_params => $args,
protocol_version => Net::OAuth::PROTOCOL_VERSION_1_0A,
);
$request->sign;
my $res = LWP::UserAgent->new(env_proxy=>1)->get($request->to_url);
return $res->content if $res->is_success;
die $res->status_line;
}
Here's another solution, this time back in python-land. This was put together by Tom De Smedt, author of the Pattern web-mining kit.
I'll communicate with the author of python-oauth2 to see if it can be fixed.
OAUTH_CONSUMER_KEY = "blahblahblah"
OAUTH_CONSUMER_SECRET = "blah"
import urllib
import hmac
import time
import random
import base64
try:
from hashlib import sha1
from hashlib import md5
except:
import sha as sha1
import md5; md5=md5.new
def hmac_sha1(key, text):
return hmac.new(key, text, sha1).digest()
def oauth_nonce(length=40):
h = "".join([str(random.randint(0, 9)) for i in range(length)])
h = md5(str(time.time()) + h).hexdigest()
return h
def oauth_timestamp():
return str(int(time.time()))
def oauth_encode(s):
return urllib.quote(s, "~")
def oauth_signature(url, data={}, method="get", secret="", token=""):
# Signature base string: http://tools.ietf.org/html/rfc5849#section-3.4.1
base = oauth_encode(method.upper()) + "&"
base += oauth_encode(url.rstrip("?")) + "&"
base += oauth_encode("&".join(["%s=%s" % (k, v) for k, v in sorted(data.items())]))
# HMAC-SHA1 signature algorithm: http://tools.ietf.org/html/rfc5849#section-3.4.2
signature = hmac_sha1(oauth_encode(secret) + "&" + token, base)
signature = base64.b64encode(signature)
return signature
q = "cat"
url = "http://yboss.yahooapis.com/ysearch/" + "web" # web | images | news
data = {
"q": q,
"start": 0,
"count": 50, # 35 for images
"format": "xml",
"oauth_version": "1.0",
"oauth_nonce" : oauth_nonce(),
"oauth_timestamp" : oauth_timestamp(),
"oauth_consumer_key" : OAUTH_CONSUMER_KEY,
"oauth_signature_method" : "HMAC-SHA1",
}
data["oauth_signature"] = oauth_signature(url, data, secret=OAUTH_CONSUMER_SECRET)
complete_url = url + "?" + urllib.urlencode(data)
response = urllib.urlopen(complete_url)
print response.read()
Here is sample code to access Yahoo! BOSS API v2 using with python-oauth as oauth liberary.
OAUTH_CONSUMER_KEY = "<oauth consumer key>"
OAUTH_CONSUMER_SECRET = "<oauth consumer secret>"
URL = "http://yboss.yahooapis.com/ysearch/web"
import urllib
import oauth.oauth as oauth
data = {
"q": "yahoo boss search",
"start":0,
"count":2,
"format":"json"
}
consumer = oauth.OAuthConsumer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET)
signature_method_plaintext = oauth.OAuthSignatureMethod_PLAINTEXT()
signature_method_hmac_sha1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
oauth_request = oauth.OAuthRequest.from_consumer_and_token(consumer, token=None, http_method='GET', http_url=URL, parameters=data)
oauth_request.sign_request(signature_method_hmac_sha1, consumer, "")
complete_url = oauth_request.to_url()
response = urllib.urlopen(complete_url)
print "REQUEST URL => %s" % complete_url
print ""
print "RESPONSE =>"
print response.read()
I stepped into the urllib2.open code using the debugger, and found that the response has this header:
WWW-Authenticate: OAuth oauth_problem="version_rejected", realm="yahooapis.com"
So I guess I'm having some kind of version mismatch of OAuth.