GithubHelp home page GithubHelp logo

requests / requests-oauthlib Goto Github PK

View Code? Open in Web Editor NEW
1.7K 53.0 421.0 572 KB

OAuthlib support for Python-Requests!

Home Page: https://requests-oauthlib.readthedocs.org/

License: ISC License

Python 100.00%
python python-requests oauth2-client oauth-client

requests-oauthlib's Introduction

Requests-OAuthlib build-status coverage-status Documentation Status

This project provides first-class OAuth library support for Requests.

The OAuth 1 workflow

OAuth 1 can seem overly complicated and it sure has its quirks. Luckily, requests_oauthlib hides most of these and let you focus at the task at hand.

Accessing protected resources using requests_oauthlib is as simple as:

>>> from requests_oauthlib import OAuth1Session
>>> twitter = OAuth1Session('client_key',
                            client_secret='client_secret',
                            resource_owner_key='resource_owner_key',
                            resource_owner_secret='resource_owner_secret')
>>> url = 'https://api.twitter.com/1/account/settings.json'
>>> r = twitter.get(url)

Before accessing resources you will need to obtain a few credentials from your provider (e.g. Twitter) and authorization from the user for whom you wish to retrieve resources for. You can read all about this in the full OAuth 1 workflow guide on RTD.

The OAuth 2 workflow

OAuth 2 is generally simpler than OAuth 1 but comes in more flavours. The most common being the Authorization Code Grant, also known as the WebApplication flow.

Fetching a protected resource after obtaining an access token can be extremely simple. However, before accessing resources you will need to obtain a few credentials from your provider (e.g. Google) and authorization from the user for whom you wish to retrieve resources for. You can read all about this in the full OAuth 2 workflow guide on RTD.

Installation

To install requests and requests_oauthlib you can use pip:

pip install requests requests-oauthlib

requests-oauthlib's People

Contributors

akira-dev avatar al-the-x avatar bloodywing avatar chaosct avatar dasevilla avatar dosisod avatar dsanader avatar filosottile avatar hellerve avatar hugovk avatar ib-lundgren avatar iliakur avatar jdufresne avatar jonathanhuot avatar jtroussard avatar kianmeng avatar lukasa avatar madhavij avatar mart-e avatar maxint avatar mm avatar mouhtasi avatar nateprewitt avatar poswald avatar shazow avatar sigmavirus24 avatar singingwolfboy avatar sunfulong avatar violuke avatar voiduin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

requests-oauthlib's Issues

README is misleading

The README example has "from requests_authlib" when it should be "requests_oauthlib"

Also, the link from requests to here could be a lot clearer :-)

Oauth2 Question

Is there already work in supporting Oauth2? If not, I think I may tackle it as I need it for PRAW. My question is, should support be added as part of this package, or a separate requests-oauth2lib package?

There already exists a simple package sanction that could probably be adapted to work with requests. That package is under the MIT license, so I think the code can be "borrowed" assuming the copyright notice is also copied. Thoughts?

BackendApplicationClient can't be used since it's not using parse_request_body_response correctly

session.fetch_token('https://foo.bar.com:8001/access_token/', client_id=client_id, client_secret=client_secret)
Traceback (most recent call last):
File "", line 1, in
File "/home/omer/.virtualenvs/deployment/local/lib/python2.7/site-packages/requests_oauthlib/oauth2_session.py", line 160, in fetch_token
self._client.parse_request_body_response(r.text, scope=self.scope)
File "/home/omer/.virtualenvs/deployment/local/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/clients/backend_application.py", line 156, in parse_request_body_response
self.token = parse_token_response(body, scope=scope)
File "/home/omer/.virtualenvs/deployment/local/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 297, in parse_token_response
validate_token_parameters(params, scope)
File "/home/omer/.virtualenvs/deployment/local/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 310, in validate_token_parameters
raise MissingTokenTypeError()
oauthlib.oauth2.rfc6749.errors.MissingTokenTypeError

facebook compliance fix raises "ValueError: Not a valid urlencoded string" when receiving an error

Facebook returns an access token in a urlencoded format, but on error, it returns a JSON encoded error message.

The facebook compliance fix attempts to urldecode the response body without any attempt to handle non-urlencoded data, or raise a sensible warning.

There are a few options to solve this:

We could check for errors before the compliance fixes are run. This might save us from code duplication, but it seems like the compliance fixes ought to be the first thing to touch the response.

We could also leave it up to the compliance fixes to handle weird conditions like this. In the facebook case, I would wrap the urldecode bit in a try, and simply return the unaltered response in the exception block.

I think the second solution is the better one. I'll submit a pull request to do just that.

Content-Type overridden whenever extract_params returns anything except None or []

oauthlib.common.extract_params returns a somewhat nonsensical list (but a value python considers true nonetheless) for most JSON values, and the code in OAuth1.call doesn't check if we've set a Content-Type before overriding it, so JSON-bodied posts have their Content-Type overridden, causing them to fail with most JSON-based REST APIs.

Duplicate Content-Length header bug on post requests

Python 3. Unable to make Post requests with versions later than 0.3.0.
0.3.1 introduced a TypeError that's been fixed. 0.3.2 and 0.3.2 produce a Duplicate Content-Length header bug on post requests. Get requests work properly.

I made the following modifications to core.py on 0.3.3 to make it work:

Replaced return string.decode('utf-8') with return string on line 17
Removed decoding='utf-8' from line 32
Removed decoding=decoding from line 41

Facebook Oauth2

I'm trying to get Facebook Oauth2 login working correctly, and I hit something interesting. I keep getting the following traceback:

  File "/opt/webapp/clusterlogin/lib/python2.7/site-packages/pyramid/router.py", line 161, in handle_request
    response = view_callable(context, request)
  File "/opt/webapp/clusterlogin/lib/python2.7/site-packages/pyramid/config/views.py", line 375, in viewresult_to_response
    result = view(context, request)
  File "/opt/webapp/clusterlogin/lib/python2.7/site-packages/pyramid/config/views.py", line 491, in _requestonly_view
    response = view(request)
  File "/opt/webapp/clusterlogin/src/clusterlogin/views/facebook_auth.py", line 40, in facebook_login
    client_secret=settings['facebook.client_secret'])
  File "/opt/webapp/clusterlogin/lib/python2.7/site-packages/requests_oauthlib/oauth2_session.py", line 125, in fetch_token
    self._client.parse_request_body_response(r.content, scope=self.scope)
  File "/opt/webapp/clusterlogin/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/clients/web_application.py", line 271, in parse_request_body_response
    self.token = parse_token_response(body, scope=scope)
  File "/opt/webapp/clusterlogin/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 292, in parse_token_response
    params = json.loads(body)
  File "/opt/python-2.7.3/lib/python2.7/json/__init__.py", line 326, in loads
    return _default_decoder.decode(s)
  File "/opt/python-2.7.3/lib/python2.7/json/decoder.py", line 366, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/opt/python-2.7.3/lib/python2.7/json/decoder.py", line 384, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

What seems to be happening is that the request to gain an access_token is succeeding, but is responding with the following string in the response body: 'access_token=#####&expires=#####'. requests-oauthlib expects a JSON response, so it isn't able to parse the string returned. Is this a bug, or am I doing something incorrect?

Incompatibility with oauthlib > 0.4.2

Oauth lib client constructor changed, token is now named access_token, so requests_oauthlib is now incompatible with recent version of authlib (there are maybe other incompatibilites, I did'nt search for more and just installed version 0.4.2)

Google OAuth 2 Tutorial raises MissingCodeError

The code provided in the Google OAuth 2 tutorial (https://requests-oauthlib.readthedocs.org/en/latest/examples/google.html) gives an exception:

raise MissingCodeError("Missing code parameter in response.")
oauthlib.oauth2.rfc6749.errors.MissingCodeError: Missing code parameter in response.

The problem is not in the web application client that I created with the Google API console, because I wrote another piece of code doing the same thing but using the Python library google-api-python-client and it works.

Any idea?

OAuth2Session refresh token default arguments

While the spec only defines grant_type and refresh_token other parameters like client_id and client_secret are often used (Google, WindowsLive).

We should investigate what the major providers use and see if we can come up with a good way to provide these by default as a smart alternative to auto_refresh_kwargs or whether it would be better to subclass OAuth2Session with provider specific versions such as GoogleWebApplication.

The "Using OAuth1Session" Twitter example doesn't actually work

The Auth1Session example code mentioned on the requests-oauthlib documentation page doesn't actually work.

The twitter response page just shows a number that you're supposed to give back to the client, rather than a URL with oauth_token and verifier specified in the params. The code then fails with this stack trace:

Traceback (most recent call last):
  File "oauth_example.py", line 37, in <module>
    oauth_tokens = oauth.fetch_access_token(access_token_url)
  File "/Users/nhooey/git/github/vine/vineweb/.venv/lib/python2.7/site-packages/requests_oauthlib/oauth1_session.py",
line 228, in fetch_access_token
    token = self._fetch_token(url)
  File "/Users/nhooey/git/github/vine/vineweb/.venv/lib/python2.7/site-packages/requests_oauthlib/oauth1_session.py",
line 264, in _fetch_token
    token = dict(urldecode(self.post(url).text))
  File "/Users/nhooey/git/github/vine/vineweb/.venv/lib/python2.7/site-packages/oauthlib/common.py", line 137, in urld
ecode
    raise ValueError('Not a valid urlencoded string.')
ValueError: Not a valid urlencoded string.

Because the response from Twitter is this:

<?xml version="1.0" encoding="UTF-8"?>
<hash>
  <error>Required oauth_verifier parameter not provided</error>
  <request>/oauth/access_token</request>
</hash>

The Using OAuth1 auth helper example from that page works fine with Twitter, though.

Sort out the documentation

We've finally got some stuff up on ReadTheDocs, but it's not great. This issue is an umbrella tracking issue, so I can tick stuff off as we go. Here are some things we need to do: feel free to suggest more in the comments.

  • Sort out the README (partly in #46).
  • Sort out Intersphinx (see #47).
  • Remove lengthy worked examples from the API docs.
  • Put lengthy worked examples somewhere else (see #46).
  • Improve clarity of API docs.
  • Improve landing page.
  • Tutorials. Lots of tutorials. A whole tutorials section (see #49).

Don't piggyback on oauthlib's log scope

This happens here and possibly other places:

from oauthlib.common import log

...
log.debug(...)

This is bad because all the logs show up as coming from oauthlib, whereas some happen actually in oauthlib and some in requests_oauthlib. Differentiating them would be useful for debugging where things are happening.

I suggest using...

import logging

log = logging.getLogger(__name__)

...
log.debug(...)

This will also allow the user to turn off oauthlib logs but keep requests_oauthlib logs, and vice versa.

Mentions of "URI" should be "URL"

The acronym uri is used all over the place in code and documentation, where it should be url. Also url is used in a bunch of places too, where it is already correct.

This is a semantic nitpick, and probably not worth breaking backwards compatibility over. But worth keeping in mind in case you ever end up doing a big refactor and see an opportunity to clean this up. :)

Feel free to close this bug if it doesn't make sense to pursue at this time.

Update minimum oauthlib version in setup.py

Bump the minimum version of oauthlib in setup.py install_requires to 0.4.2.

The following tests fail with oauthlib 0.4.0:

running test
running egg_info
writing requirements to requests_oauthlib.egg-info/requires.txt
writing requests_oauthlib.egg-info/PKG-INFO
writing top-level names to requests_oauthlib.egg-info/top_level.txt
writing dependency_links to requests_oauthlib.egg-info/dependency_links.txt
reading manifest file 'requests_oauthlib.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
writing manifest file 'requests_oauthlib.egg-info/SOURCES.txt'
running build_ext
test_authorization_url (tests.test_oauth1_session.OAuth1SessionTest) ... ok
test_binary_upload (tests.test_oauth1_session.OAuth1SessionTest) ... ERROR
test_fetch_access_token (tests.test_oauth1_session.OAuth1SessionTest) ... ERROR
test_fetch_request_token (tests.test_oauth1_session.OAuth1SessionTest) ... ERROR
test_nonascii (tests.test_oauth1_session.OAuth1SessionTest) ... ERROR
test_parse_response_url (tests.test_oauth1_session.OAuth1SessionTest) ... ok
test_signature_methods (tests.test_oauth1_session.OAuth1SessionTest) ... ERROR
test_signature_types (tests.test_oauth1_session.OAuth1SessionTest) ... ERROR
testCanPostBinaryData (tests.test_core.OAuth1Test) ... ERROR
testFormEncoded (tests.test_core.OAuth1Test)
OAuth1 assumes form encoded if content type is not specified. ... ERROR
testNonFormEncoded (tests.test_core.OAuth1Test)
OAuth signature only depend on body if it is form encoded. ... ERROR
test_url_is_native_str (tests.test_core.OAuth1Test) ... ERROR
test_add_nonexisting_token (tests.test_oauth2_auth.OAuth2AuthTest) ... ok
test_add_token_to_body (tests.test_oauth2_auth.OAuth2AuthTest) ... ok
test_add_token_to_headers (tests.test_oauth2_auth.OAuth2AuthTest) ... ok
test_add_token_to_url (tests.test_oauth2_auth.OAuth2AuthTest) ... ok
test_add_token (tests.test_oauth2_session.OAuth2SessionTest) ... ok
test_authorization_url (tests.test_oauth2_session.OAuth2SessionTest) ... ok
test_fetch_token (tests.test_oauth2_session.OAuth2SessionTest) ... ok
test_refresh_token_request (tests.test_oauth2_session.OAuth2SessionTest) ... ok
test_token_from_fragment (tests.test_oauth2_session.OAuth2SessionTest) ... ok

======================================================================
ERROR: test_binary_upload (tests.test_oauth1_session.OAuth1SessionTest)
  File "/usr/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/models.py", line 226, in prepare
    p.prepare_auth(self.auth, self.url)
  File "/usr/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/models.py", line 428, in prepare_auth
    r = auth(self)
  File "/mnt/home/user/repos/freebsd/ports/www/py-requests-oauthlib/work/requests-requests-oauthlib-0b1fe5c/requests_oauthlib/core.py", line 61, in __call__
    unicode(r.url), unicode(r.method), r.body or '', r.headers)
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/oauth1/rfc5849/__init__.py", line 225, in sign
    encoding=self.encoding)
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 332, in __init__
    self.headers = CaseInsensitiveDict(encode(headers or {}))
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 328, in <lambda>
    encode = lambda x: to_unicode(x, encoding) if encoding else x
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 276, in to_unicode
    return dict(((to_unicode(k, encoding), to_unicode(v, encoding)) for k, v in data))
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 276, in <genexpr>
    return dict(((to_unicode(k, encoding), to_unicode(v, encoding)) for k, v in data))
ValueError: too many values to unpack

======================================================================
ERROR: testNonFormEncoded (tests.test_core.OAuth1Test)
OAuth signature only depend on body if it is form encoded.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/mock-1.0.1-py2.7.egg/mock.py", line 1201, in patched
    return func(*args, **keywargs)
  File "/mnt/home/user/repos/freebsd/ports/www/py-requests-oauthlib/work/requests-requests-oauthlib-0b1fe5c/tests/test_core.py", line 67, in testNonFormEncoded
    a = r.prepare()
  File "/usr/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/models.py", line 226, in prepare
    p.prepare_auth(self.auth, self.url)
  File "/usr/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/models.py", line 428, in prepare_auth
    r = auth(self)
  File "/mnt/home/user/repos/freebsd/ports/www/py-requests-oauthlib/work/requests-requests-oauthlib-0b1fe5c/requests_oauthlib/core.py", line 65, in __call__
    unicode(r.url), unicode(r.method), None, r.headers)
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/oauth1/rfc5849/__init__.py", line 225, in sign
    encoding=self.encoding)
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 332, in __init__
    self.headers = CaseInsensitiveDict(encode(headers or {}))
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 328, in <lambda>
    encode = lambda x: to_unicode(x, encoding) if encoding else x
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 276, in to_unicode
    return dict(((to_unicode(k, encoding), to_unicode(v, encoding)) for k, v in data))
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 276, in <genexpr>
    return dict(((to_unicode(k, encoding), to_unicode(v, encoding)) for k, v in data))
ValueError: too many values to unpack

======================================================================
ERROR: test_url_is_native_str (tests.test_core.OAuth1Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/mock-1.0.1-py2.7.egg/mock.py", line 1201, in patched
    return func(*args, **keywargs)
  File "/mnt/home/user/repos/freebsd/ports/www/py-requests-oauthlib/work/requests-requests-oauthlib-0b1fe5c/tests/test_core.py", line 108, in test_url_is_native_str
    r = requests.get('http://httpbin.org/get', auth=oauth)
  File "/usr/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/api.py", line 55, in get
    return request('get', url, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/sessions.py", line 324, in request
    prep = req.prepare()
  File "/usr/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/models.py", line 226, in prepare
    p.prepare_auth(self.auth, self.url)
  File "/usr/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/models.py", line 428, in prepare_auth
    r = auth(self)
  File "/mnt/home/user/repos/freebsd/ports/www/py-requests-oauthlib/work/requests-requests-oauthlib-0b1fe5c/requests_oauthlib/core.py", line 65, in __call__
    unicode(r.url), unicode(r.method), None, r.headers)
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/oauth1/rfc5849/__init__.py", line 225, in sign
    encoding=self.encoding)
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 332, in __init__
    self.headers = CaseInsensitiveDict(encode(headers or {}))
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 328, in <lambda>
    encode = lambda x: to_unicode(x, encoding) if encoding else x
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 276, in to_unicode
    return dict(((to_unicode(k, encoding), to_unicode(v, encoding)) for k, v in data))
  File "/usr/local/lib/python2.7/site-packages/oauthlib-0.4.0-py2.7.egg/oauthlib/common.py", line 276, in <genexpr>
    return dict(((to_unicode(k, encoding), to_unicode(v, encoding)) for k, v in data))
ValueError: too many values to unpack

----------------------------------------------------------------------
Ran 21 tests in 0.046s

FAILED (errors=10)

OAuth2Session.fetch_token() ignores state

In the callback view like Web App Example of OAuth 2 web application flow, I instantiated OAuth2Session with state parameter and called fetch_token() method but fetch_token() does not use the given state value.

So an arbitrary state parameter bypasses OAuth2Session's CSRF protection:

github = OAuth2Session(client_id, state='wrong state')
github.fetch_token(
    token_url, client_secret=client_secret,
    authorization_response=request.url)  # does not raise MismatchingStateError

OAuthSession2 ignores `state` param

We are using state param to follow the relation between our app and authentication requests. Think of them, as some uuid values.

It is fine by Google (link):
state - any string - Indicates any state which may be useful to your application upon receipt of the response. The Google Authorization Server roundtrips this parameter, so your application receives the same value it sent. Possible uses include redirecting the user to the correct resource in your site, nonces, and cross-site-request-forgery mitigations.

However, OAuthSession2.authorization_url ignores the value being passed to the constructor, and replaces with a self-generated one (line 102).

def authorization_url(self, url, **kwargs):
    state = self.new_state()
    return self._client.prepare_request_uri(url,
            redirect_uri=self.redirect_uri,
            scope=self.scope,
            state=state,
            **kwargs), state

Allow insecure communication for development

OAuth2 requires a secure communication channel, i.e. HTTPS, and the library refuses connections on HTTPS. This is inconvenient when developing OAuth2-based applications. Setting up HTTPS locally is quite some work, especially with clients that verify the certificate chain.

Would you accept a pull request that adds an option to disable the HTTPS check?

Or alternatively, is there another way for requests-oauthlib to address this issue that I could implement?

tests fail due to pycrypto dependency

I tried running the tests and got a failure in tests.test_oauth1_session.OAuth1SessionTest.test_signature_methods. Basically the test is using the rsa functionality of oauthlib, which isn't installed by default. I've listed my steps to reproduce below.

Here are some ways I can think of to rectify the situation. If you pick which one you like, or suggest another, I'll make the fix and submit a pull request.

  1. change the "oauthlib>=0.4.2" requirement to "oauthlib[rsa]>=0.4.2", which installs the rsa optional component and thus pycrypto. the potential problem is that this might require some python development libraries to be installed. not sure on that one.
  2. make the one failing test optional, and it only runs if pycrypto is installed (or if oauthlib[rsa] is installed).
  3. make pycrypto a requirement for testing, but not installation.

My OS is Ubuntu 13.04 and for this test I used python 2.7. virtualenv version is 1.9.1

Reproduce steps:

  • Check out source code
  • (create new virtualenv: virtualenv env --no-site-packages
  • activate virtualenv
  • python setup.py install
  • at this point the following packages are installed: oauthlib, requests, requests_oauthlib
  • install test dependencies: pip install nose mock
  • run tests: nosetests tests. I get the stack trace below.

I have confirmed that option (1) makes the tests pass.

Stack trace:

(env)frank@frank-leoben-ubuntu:~/boxes/requests-oauthlib-notmine$ nosetests tests
..........E..........
======================================================================
ERROR: test_signature_methods (tests.test_oauth1_session.OAuth1SessionTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/frank/boxes/requests-oauthlib-notmine/env/local/lib/python2.7/site-packages/mock.py", line 1201, in patched
    return func(*args, **keywargs)
  File "/home/frank/boxes/requests-oauthlib-notmine/tests/test_oauth1_session.py", line 100, in test_signature_methods
    auth.post('https://i.b')
  File "/home/frank/boxes/requests-oauthlib-notmine/env/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/sessions.py", line 377, in post
    return self.request('POST', url, data=data, **kwargs)
  File "/home/frank/boxes/requests-oauthlib-notmine/env/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/sessions.py", line 324, in request
    prep = req.prepare()
  File "/home/frank/boxes/requests-oauthlib-notmine/env/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/models.py", line 226, in prepare
    p.prepare_auth(self.auth, self.url)
  File "/home/frank/boxes/requests-oauthlib-notmine/env/local/lib/python2.7/site-packages/requests-1.2.3-py2.7.egg/requests/models.py", line 428, in prepare_auth
    r = auth(self)
  File "/home/frank/boxes/requests-oauthlib-notmine/requests_oauthlib/core.py", line 65, in __call__
    unicode(r.url), unicode(r.method), None, r.headers)
  File "build/bdist.linux-x86_64/egg/oauthlib/oauth1/rfc5849/__init__.py", line 281, in sign
    request.oauth_params.append(('oauth_signature', self.get_oauth_signature(request)))
  File "build/bdist.linux-x86_64/egg/oauthlib/oauth1/rfc5849/__init__.py", line 135, in get_oauth_signature
    sig = signature.sign_rsa_sha1(base_string, self.rsa_key)
  File "build/bdist.linux-x86_64/egg/oauthlib/oauth1/rfc5849/signature.py", line 479, in sign_rsa_sha1
    from Crypto.PublicKey import RSA
ImportError: No module named Crypto.PublicKey
-------------------- >> begin captured logging << --------------------
oauthlib: DEBUG: Collected params: [(u'oauth_version', u'1.0'), (u'oauth_consumer_key', u'foo'), (u'oauth_signature_method', u'HMAC-SHA1'), (u'oauth_nonce', u'abc'), (u'oauth_timestamp', u'123')]
oauthlib: DEBUG: Normalized params: oauth_consumer_key=foo&oauth_nonce=abc&oauth_signature_method=HMAC-SHA1&oauth_timestamp=123&oauth_version=1.0
oauthlib: DEBUG: Normalized URI: https://i.b/
oauthlib: DEBUG: Base signing string: POST&https%3A%2F%2Fi.b%2F&oauth_consumer_key%3Dfoo%26oauth_nonce%3Dabc%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D123%26oauth_version%3D1.0
oauthlib: DEBUG: Signature: h2sRqLArjhlc5p3FTkuNogVHlKE=
oauthlib: DEBUG: Encoding URI, headers and body to utf-8.
oauthlib: DEBUG: Encoding URI, headers and body to utf-8.
oauthlib: DEBUG: Collected params: [(u'oauth_version', u'1.0'), (u'oauth_consumer_key', u'foo'), (u'oauth_signature_method', u'RSA-SHA1'), (u'oauth_nonce', u'abc'), (u'oauth_timestamp', u'123')]
oauthlib: DEBUG: Normalized params: oauth_consumer_key=foo&oauth_nonce=abc&oauth_signature_method=RSA-SHA1&oauth_timestamp=123&oauth_version=1.0
oauthlib: DEBUG: Normalized URI: https://i.b/
oauthlib: DEBUG: Base signing string: POST&https%3A%2F%2Fi.b%2F&oauth_consumer_key%3Dfoo%26oauth_nonce%3Dabc%26oauth_signature_method%3DRSA-SHA1%26oauth_timestamp%3D123%26oauth_version%3D1.0
--------------------- >> end captured logging << ---------------------

----------------------------------------------------------------------
Ran 21 tests in 0.640s

FAILED (errors=1)

setup.py not using find_packages()

When I attempt to add the requests-oauthlib github repo to my requirements.txt, I receive this error:

ImportError: No module named compliance_fixes

This can simply be fixed by using setuptools.find_packages() to located all of the included packages. Going to submit a pull request for this.

ImportError: No module named oauthlib.common

Hello im using requests-oauthlib in windows 7 and i installed the module from pip. I get this error every time i'm using it to call the Oauth1 class.

from requests_oauthlib import OAuth1
File "C:\Python27\lib\site-packages\requests_oauthlib\__init__.py", line 1, in <module> from .core import OAuth1
File "C:\Python27\lib\site-packages\requests_oauthlib\core.py", line 3, in <module> from oauthlib.common import extract_params
ImportError: No module named oauthlib.common

Can you help me figure out why i get this error ?

Thank you for your help.

Cleanup file names.

It seems to me we should rename core.py to oauth1_auth.py to match the naming scheme of the rest of the files in the library.

Trouble to make the Oauth2 Web App example working

Hello,

I've got the following error when I try the snippet of code

oauthlib.oauth2.rfc6749.errors.InsecureTransportError
I got the redirection but returning to the callback throws this exception.

The exception is triggered by the line :
token = github.fetch_token(token_url, client_secret=client_secret, authorization_response=request.url)

Since I'm new to requests-oauth, I don't know if the blunder is coming from me or not. But I almost copy/paste the code and replaced all that have to be replaced.

Can anyone confirm the example is working ?

Can't get requests-oauthlib to interact correctly with flask-oauthlib

I raised this issue with flask-oauthlib but maybe this is more appropriate here? I've been having an issue trying to fetch a token on a flask-oauthlib server. The complete details are here (along with logging info for the client and the server):

http://stackoverflow.com/questions/21888461/flask-oauthlib-server-doesnt-play-well-with-requests-oauthlib-client

Since I have not gotten a response or even acknowledgement I'm wondering if I posted it in the right place and thought it might be more appropriate to post here. I'm completely out of ideas and have been trying to resolve this for quite some days now.

Sphinx docs setup

Would be great to have a docs directory setup. One with path set properly for syntax highlighting =)

Bonus would be to create a few .rst files in there that uses autodoc to generate docs from existing source files.

multipart/form-data causing exception to be thrown in core.py

In the file: core.py, the following line of code causes a TypeError Exception to be thrown when you are trying to send a multipart data post request.

The error message that I'm seeing is: TypeError: Type str doesn't support the buffer API

Here's the problematic line of code in core.py:

is_form_encoded = (CONTENT_TYPE_FORM_URLENCODED in headers.get('Content-Type', ''))

Use-case: When sending a POST request (with the Requests API) using the "files" parameter like so:

response = requests.request(method='POST', url=api_url, auth=self.oauth, params=params, files=file_payload)

When this call makes its way down to core.py, Python3.3 is not happy. Why? It appears the "in" operator in the above statement (in core.py) performs a problematic comparison. r.headers.get('Content-Type', '') returns a byte-stream instead of a string when multipart data is being sent from the Requests API. CONTENT_TYPE_FORM_URLENCODED, however, is a 'str' type. This comparison causes a TypeError exception to be thrown.

Here's a hack I implemented to get around this problem:

    #-----------------------------------------------------------------------
    #
    # SketchUp modified code starts here.
    content_type = r.headers.get('Content-Type', '')
    try:
        if (CONTENT_TYPE_FORM_URLENCODED in content_type):
            is_form_encoded = True
        else:
            is_form_encoded = False
    except Exception as e:
        # print("OAuth BUG: comparing 'byte stream' with 'str' type when "
        #       "a multipart request header is encountered.")
        is_form_encoded = False
    #
    # SketchUp modified code ends here.
    #-----------------------------------------------------------------------

    #-----------------------------------------------------------------------
    # This is the OAuth block of code that SketchUp has commented out:
    #
    # is_form_encoded = (CONTENT_TYPE_FORM_URLENCODED in
    #         r.headers.get('Content-Type', ''))
    #
    #-----------------------------------------------------------------------

I think you should be aware of this issue as it caused me some serious pain. My "fix" is just a hack and I'm sure there's a better way to solve this problem.

~Gabriel

Examples

Examples are sorely needed for this new library - Twitter and Facebook being the most obvious ones, but it'd be nice to see it demo'd as a provider as well. Python-oauth2 has some decent examples, for instance: https://github.com/simplegeo/python-oauth2

No request body with certain 3rd party libs.

I'm using django-allauth with linkedin, and line 52 of the core.py (if is_form_encoded...) throws an exception "Request object has no attribute body". Strangely, this does not occur with direct calls to the linkedin API. Nonetheless, would you mind a short-circuit hasattr(r, 'body') in the if statement to prevent this? Thanks!

Warn if using an old version of requests

One of the few issues I see people run into is that they are using an old version of requests, pre 1.0 that is but might now also include the odd pre 2.0.

It might be helpful if we raised a Warning telling users to upgrade their version of requests. I am not sure how/where to best do this. @Lukasa thoughts?

The most obvious place which would address most of the pre 1.0 issues is in OAuth 1 where we expect a PreparedRequest and instead get a Request. However with the encoding changes in 2.0 the places/cases impacted will be much more subtle. Although still most likely in OAuth 1.

core.py#L51

if requests.__version__ < '2.0.0':
    raise Warning('You are using requests version %s, which is older than requests-oauthlib expects, please upgrade to 2.0.0 or later." % requests.__version__)

OAuth1Session needs to re-sign redirected requests so that allow_redirect can function.

Currently this is impossible to solve directly from this library as requests itself is at fault, as it does not provide facilities in the SessionRedirectMixin.resolve_redirects to call prepare_auth on the local PreparedRequest object to recalculate the OAuth signatures. This can probably be called after the prepare_cookies call.

Edit: can probably be done by overriding the send method so that it calls prepare_auth again, but that's hideous.

Survey potentially risky use of Response.content

In OAuth{1,2}Session Response.content (byte-like string) might be used in a way that can cause problems, especially in py3, and should be replaced with Response.text (unicode string). See #42 for how this was problematic with json parsing.

Tests should be added to make sure regressions are not introduced as well.

AttributeError: 'PreparedRequest' object has no attribute 'data'

@Lukasa asked me to raise this error in this repo as well:

Hey guys, just wanted to bring this issue forward. With requests 1.0.0
So the error came from when I went to test Twython with the new requests release.

And because it bothered me, I removed self from all variables that used self like self.callback_url
Also, I striped the code out of the actual function get_authentication_tokens (so that's why you'll see ref to that function in the traceback)

import requests
from requests_oauthlib import OAuth1

app_key = u'SUPERDUPERSECRETKEY'
app_secret = u'SUPERDUPERSECRETSECRET'

callback_url = 'http://example.com'
headers = {'User-Agent': 'Twython v2.5.5'}
auth = OAuth1(app_key, app_secret,
                               signature_type='auth_header')

request_args['oauth_callback'] = callback_url
response = requests.get('https://api.twitter.com/oauth/request_token', params=request_args, headers=headers, auth=auth)

if response.status_code != 200:
    raise TwythonAuthError("Seems something couldn't be verified with your OAuth junk. Error: %s, Message: %s" % (response.status_code, response.content))

request_tokens = dict(parse_qsl(response.content))
if not request_tokens:
    raise TwythonError('Unable to decode request tokens.')

oauth_callback_confirmed = request_tokens.get('oauth_callback_confirmed') == 'true'

auth_url_params = {
    'oauth_token': request_tokens['oauth_token'],
}

# Use old-style callback argument if server didn't accept new-style
if callback_url and not oauth_callback_confirmed:
    auth_url_params['oauth_callback'] = callback_url

request_tokens['auth_url'] = 'https://api.twitter.com/oauth/authenticate?' + urllib.urlencode(auth_url_params)

return request_tokens

Anyways, when I try to run this code I get the error:

Traceback (most recent call last):
  File "twython.py", line 585, in <module>
    auth_props = t.get_authentication_tokens()
  File "twython.py", line 271, in get_authentication_tokens
    response = requests.get('https://api.twitter.com/oauth/request_token', params=request_args, headers=headers, auth=self.auth)
  File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests/api.py", line 49, in get
    return request('get', url, **kwargs)
  File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests/api.py", line 38, in request
    return session.request(method=method, url=url, **kwargs)
  File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests/sessions.py", line 253, in request
    prep = req.prepare()
  File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests/models.py", line 200, in prepare
    p.prepare_auth(self.auth)
  File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests/models.py", line 336, in prepare_auth
    r = auth(self)
  File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests_oauthlib/core.py", line 41, in __call__
    decoded_body = extract_params(r.data)
AttributeError: 'PreparedRequest' object has no attribute 'data'

oauth_nonce, oauth_timestamp, oauth_version

I started using requests-oauthlib a few days ago. I came to the point where I need to use oauth_nonce, oauth_timestamp and oauth_version in the program that I am using to learn REST. I reviewed the code and went over the tutorial but I didn't find any of the above-mentioned parameters. I am new to REST and I may have missed or didn't fully understand the library, therefore I wanted to ask if you have support for oauth_nonce, oauth_timestamp and oauth_version.

Thanks in advance.

**Please** release a new version on PyPI.

5570360 fixed a giant bug that some people have run into: with revisions before 5570360 (including v0.3.2) it's simply impossible to fetch access token from Twitter, Tumblr, and possibly any other site using the code below (that's basically a simplified example from the docs).

from requests_oauthlib import OAuth1Session

CLIENT_KEY = 'blah'
CLIENT_SECRET = 'blah'
REQUEST_TOKEN_URL = 'https://api.twitter.com/oauth/request_token'
BASE_AUTHORIZATION_URL = 'https://api.twitter.com/oauth/authorize'
ACCESS_TOKEN_URL = 'https://api.twitter.com/oauth/access_token'

if __name__ == '__main__':
    oauth = OAuth1Session(client_key=CLIENT_KEY,
                          client_secret=CLIENT_SECRET)

    oauth.fetch_request_token(REQUEST_TOKEN_URL)
    print oauth.authorization_url(BASE_AUTHORIZATION_URL)
    redirect_response = raw_input('Redirect response: ')
    oauth.parse_authorization_response(redirect_response)
    print oauth.fetch_access_token(ACCESS_TOKEN_URL)

On previous revisions it will fail with this:

Traceback (most recent call last):
  File "a.py", line 20, in <module>
    print oauth.fetch_access_token(ACCESS_TOKEN_URL)
  File "/tmp/requests-oauthlib/requests_oauthlib/oauth1_session.py", line 221, in fetch_access_token
    token = self._fetch_token(url)
  File "/tmp/requests-oauthlib/requests_oauthlib/oauth1_session.py", line 257, in _fetch_token
    self._populate_attributes(token)
  File "/tmp/requests-oauthlib/requests_oauthlib/oauth1_session.py", line 249, in _populate_attributes
    raise ValueError('Response does not contain a token. %s', token)
ValueError: (u'Response does not contain a token. %s', {})

I've already said it in a comment under the commit – this is a big issue. It breaks the OAuth 1 functionality completely, assuming you use OAuth1Session to obtain the tokens.

I think a lot of users of requests_oauthlib would lead much happier lives if a version that includes this fix would be available on PyPI.

OAuth2Session ignores self.state when generation an authorization url

OAuth2Session always calls self.new_state() in authorization_url even if the user specified a state in the constructor. I think that should be changed.

As a side note I think the state and state_generator arguments should be mutually exclusive to prevent errors on the user side.

client_id and client_secret in docs should be raw string

I recently tried requests-oauthlib with django-oauth-toolkit following the webapplication flow tutorial.

If the provider use '' char in client_id and client_secret strings that will be interpreted as an escape sequence and you'll obtain an InvalidClientId error when you try to exchange the token.
For instance if the client_id XQcKemTaz}^1GW6C@_;@KHDh@yo\4Br\jv/,;5\1:

>>> client_id = 'XQcKemTaz}^1GW6C@_;@KHDh@yo\4Br\jv/,;5\1'
>>> print client_id
XQcKemTaz}^1GW6C@_;@KHDh@yoBr\jv/,;5

As you can see the input value and output value are different.
To avoid this behavior you can use raw python string syntax:

>>> client_id = r'XQcKemTaz}^1GW6C@_;@KHDh@yo\4Br\jv/,;5\1'
>>> print client_id
XQcKemTaz}^1GW6C@_;@KHDh@yo\4Br\jv/,;5\1

I can open a PR if you want

Cannot exclude a param from OAuth signature (flickr file upload)

Flickr API for file uploading (http://www.flickr.com/services/api/upload.api.html) uses a tricky approach: they require a single POST parameter photo and support some optional params.

The tricky part is that this photo parameter needs to be excluded from the OAuth signature, while all the other params (the optional ones) should be included in it (as explained under the link above).

Is it possible to exclude some parameters from including in the signature using requests-oauthlib?

ValueError: Only unicode objects are escapable.

Using requests 0.14.2 (tried 1.0.4 too and think I got the same thing) and Python 2.7.3. Getting this error when trying to make a request. Relevant part of stack trace:

  File "/Users/john/.virtualenvs/dashboard/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/__init__.py", line 215, in sign
    request.oauth_params.append(('oauth_signature', self.get_oauth_signature(request)))
  File "/Users/john/.virtualenvs/dashboard/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/__init__.py", line 67, in get_oauth_signature
    uri, headers, body = self._render(request)
  File "/Users/john/.virtualenvs/dashboard/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/__init__.py", line 137, in _render
    headers = parameters.prepare_headers(request.oauth_params, request.headers, realm=realm)
  File "/Users/john/.virtualenvs/dashboard/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/utils.py", line 32, in wrapper
    return target(params, *args, **kwargs)
  File "/Users/john/.virtualenvs/dashboard/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/parameters.py", line 58, in prepare_headers
    escaped_value = utils.escape(value)
  File "/Users/john/.virtualenvs/dashboard/lib/python2.7/site-packages/oauthlib/oauth1/rfc5849/utils.py", line 56, in escape
    raise ValueError('Only unicode objects are escapable.')
ValueError: Only unicode objects are escapable.

Cannot prevent signing of multipart file data

The documentation at https://oauthlib.readthedocs.org/en/latest/client.html says:

The OAuth 1 spec only covers signing of x-www-url-formencoded information. If you are sending some other kind of data in the body (say, multipart file uploads), these don’t count as a body for the purposes of signing. Don’t provide the body to Client.sign() if it isn’t x-www-url-formencoded data.

I can't see any way of doing this with requests-oauthlib - there doesn't seem to be a way of preventing it from signing the body when called like so:

r = requests.post(url, files=files, auth=oauth)

...or am I missing something?

Prepare 0.4.0 release

The current 0.3.0 release is pretty old and we've fixed a few bugs, as well as added a massive amount of functionality. I want to get this library into a shape where we can pass it to Kenneth all he has to do is tag it and go. @ib-lundgren, @sigmavirus24, is there anything we need to do?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.