1

After looking at several articles online, StackOverflow, and the Yelp Google Group, I've been unable to figure out the problem to an Invalid Signature error being produced from my Yelp API request.

Here is the exact error:

{'error': {'text': 'Signature was invalid', 'description': 'Invalid signature. Expected signature base string: [some text here with keys]}}

And the code I've written to go along with it:

import rauth
import time

def get_results():

    #Obtain these from Yelp's manage access page
    consumer_key = ''
    consumer_secret = ''
    token = ''
    token_secret = ''

    session = rauth.OAuth1Session(
            consumer_key = consumer_key
            ,consumer_secret = consumer_secret
            ,access_token = token
            ,access_token_secret = token_secret)

    request = session.get("http://api.yelp.com/v2/search?location=Boston&term=food")

    #Transforms the JSON API response into a Python dictionary
    data = request.json()
    print(data)
    session.close()

    return data

if __name__=="__main__":
    print(get_results())

So what exactly is causing this error? I've done some modifications prior to this attempt, and the previous attempts I made I got similar errors; except one time I only got a "Invalid Signature" error, with no "Expect signature base string" message

freddiev4
  • 2,501
  • 2
  • 26
  • 46

2 Answers2

3

There are more steps to authentication as per the docs

Making a Request

Each request must contain the following OAuth protocol parameters:

OAuth Parameter Value
oauth_consumer_key  Your OAuth consumer key (from Manage API Access).
oauth_token The access token obtained (from Manage API Access).
oauth_signature_method  hmac-sha1
oauth_signature The generated request signature, signed with the oauth_token_secret obtained (from Manage API Access).
oauth_timestamp Timestamp for the request in seconds since the Unix epoch.
oauth_nonce A unique string randomly generated per request.

These parameters may be passed in the HTTP (Authorization) header as URL query keys or in the POST data. Generating the OAuth signature is done by applying the HMAC-SHA1 with the oauth_token_secret. You may view your OAuth consumer key at Manage API Access. OAuth libraries are available to generate these requests.

You are not passing oauth_timestamp which is required or applying the HMAC-SHA1 so you get an Invalid Signature error, it is clearly outlined in the docs above what you need to send.

There is also an actual python yelp api you could use but to make a request you can use the example below based on the request function from the example code: to make a request using oauth2 and requests:

import requests
import oauth2

def request(url, url_params=None):
    consumer_key = ""
    consumer_secret = ""
    token = ""
    token_secret =""
    url_params = url_params or {}
    consumer = oauth2.Consumer(consumer_key, consumer_secret)
    oauth_request = oauth2.Request(method="GET", url=url, parameters=url_params)

    oauth_request.update(
        {
            'oauth_nonce': oauth2.generate_nonce(),
            'oauth_timestamp': oauth2.generate_timestamp(),
            'oauth_token': token,
            'oauth_consumer_key': consumer_key
        }
    )
    token = oauth2.Token(token, token_secret)
    oauth_request.sign_request(oauth2.SignatureMethod_HMAC_SHA1(), consumer, token)
    signed_url = oauth_request.to_url()

    print(u'Querying {0} ...'.format(url))

    return requests.get(signed_url).json()

Which using your url outputs a whole load of json, the start of which is:

Querying http://api.yelp.com/v2/search?location=Boston&term=food ...
{'region': {'center': {'longitude': -71.05460875, 'latitude': 42.35028894954365}, 'span': {'latitude_delta': 0.0325510910039668, 'longitude_delta': 0.04668455000000904}}, 'total': 8351, 'businesses': [{'name': "Giacomo's Ristorante", 'url': 'http://www.yelp.com/biz/giacomos-ristorante-boston', 'mobile_url': 'http://m.yelp.com/biz/giacomos-ristorante-boston', 'rating_img_url_large': 'http://s3-media2.fl.yelpcdn.com/assets/2/www/img/ccf2b76faa2c/ico/stars/v1/stars_large_4.png', 'phone': 
...............................................................
...............................................................

I am not sure if the api supports python 3 but the code above was tested with python3 and python2 and it works fine, to install oauth2 you can simple pip install oauth2 and the same with requests if you don't have it installed.

Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • 1
    Great answer, very detailed. – dotcomly Oct 21 '15 at 21:56
  • @FreddieV4, no prob, glad it helped. – Padraic Cunningham Oct 22 '15 at 17:45
  • I'm getting no response calling the method above? I ran the same url you used like this: `params = dict(location='Boston', term='food',) request('http://api.yelp.com/v2/search?', url_params=params)` – Michael Smith Dec 11 '15 at 20:20
  • Hi, yes I have. I literally just copied and pasted your code, filled in the 4 keys, then added logic to call the request function you created. Maybe it has to do with the version of python I'm running? – Michael Smith Dec 11 '15 at 20:27
  • Oops! There was a typo with one of my keys & the url was wrong- but the latter didn't seem to matter. This worked: `params = dict(location='Boston', term='food',) rjson =request('http://api.yelp.com/v2/search/?', url_params=params) print rjson ` – Michael Smith Dec 11 '15 at 23:22
0

Another common issue is that the servers time is out of sync. On linux, one can run

sudo ntpdate -s time.nist.gov
Jonathan Hendler
  • 1,239
  • 1
  • 17
  • 23