litl / rauth

A Python library for OAuth 1.0/a, 2.0, and Ofly.
http://readthedocs.org/docs/rauth/en/latest/
MIT License
1.61k stars 175 forks source link

Getting oauth_problem=signature_invalid from Flickr when trying to upload #183

Open cmatta opened 8 years ago

cmatta commented 8 years ago

Hello, I'm trying to upload an image to flickr and receiving a signature_invalid error.

This code should reproduce:

def get_flickr_session():
    # returns flickr session
    flickr = OAuth1Service(
        name='flickr',
        consumer_key=FLICKR_API_KEY,
        consumer_secret=FLICKR_API_SECRET,
        request_token_url="https://www.flickr.com/services/oauth/request_token",
        access_token_url="https://www.flickr.com/services/oauth/access_token",
        authorize_url="https://www.flickr.com/services/oauth/authorize",
        base_url="https://api.flickr.com/services"
    )

    auth_params = {
        "perms": "delete"
    }

    request_token, request_token_secret = flickr.get_request_token(
                                            params={'oauth_callback': 'oob'})
    authorize_url = flickr.get_authorize_url(request_token, **auth_params)
    print 'Visit this URL in your browser: ' + authorize_url
    pin = raw_input('Enter PIN from browser: ')

    return flickr.get_auth_session(request_token,
                                   request_token_secret,
                                   method='POST',
                                   data={'oauth_verifier': pin})

def upload_to_flickr(session, url, title):
    post_url = """https://up.flickr.com/services/upload/"""

    photo_location = download_file(url)

    headers = {
        'Content-Type': 'application/xml'
    }

    data = {
        "title": title,
        "photo": open(photo_location, 'rb').read(),
        "is_public": 0
    }

    return session.post(post_url, data=data)

session = get_flickr_session()
p = upload_to_flickr(session, "http://i.imgur.com/K8v9RgV.jpg", "test photo")

The response I get is 401 and the response text says oauth_problem=signature_invalid.

I see this is related to the closed issue #109, if this should go in that closed thread I'll move it.

maxcountryman commented 8 years ago

Thanks for reporting this, it seems like the signature is not being built up correctly. Were you able to look through #109? Did that help at all?

andytrawick commented 8 years ago

Getting an signature_invalid error when working with SmugMug and using a query string in the request.

Session requests work well with SmugMug API (api.smugmug.com) except when a query is added. Both examples work when used in a browser window with proper authorization.

This example works: https://api.smugmug.com/api/v2/node/GS0g9!children

This example fails: https://api.smugmug.com/api/v2/node/GS0g9!children?start=11&count=10

The string built within session is https://api.smugmug.com/api/v2/node/GS0g9!children&count=10?oauth_consumer_key=...?oauth_nonce=...?oath_signature_method=...?oauth_timestamp=...?oauth_token=...?oauth_version=...?start=11

Note the first part of the query string "?start=11" is moved to the end of the Uri yet "&count=10" is left in place.

The failed example is created when calling session.get("https://api.smugmug.com/api/v2/node/GS0g9!children?start=11&count=10",headers={'Accept': 'application/json'})

The same call without the query string "?start=11&count=10" works.

Using python3 (3.4.1) with rauth 0.7.2 Using OAuth1Session to create the session.

maxcountryman commented 8 years ago

Sounds like a bug in the query string encoding.

andytrawick commented 8 years ago

Switched from rauth to requests_oauthlib and works well now. No changes to query string necessary.

alpritt commented 2 years ago

This is a problem when the query string is included in a GET request via the 'url' parameter, rather than added as separate 'params'.

this will work: session.request('GET', 'https://example.com', params={'key': 'value'}, header_auth=True) this will produce an invalid signature: session.request('GET', 'https://example.com?key=value', header_auth=True)

What happens is the base string for the oauth signature strips out the query string and completely discards it. What needs to happen is for the query string to be stripped out and then included in the base string in the same way as if they were provided as a dict to 'params'. I think the way to do this is OAuth1Session.request normalises the above 2 example calls.

Reference Appendix A.5.1. Generating Signature Base String at https://oauth.net/core/1.0a/#anchor13