requests-oauthlib
requests-oauthlib copied to clipboard
Mobile Application Flow Example
This part is still missing documentation https://requests-oauthlib.readthedocs.org/en/latest/oauth2_workflow.html#mobile-application-flow
Does anybody have an example on hand? I'll write the docs, but would be nice to have some working code to start from. Is this tested?
I think @ib-lundgren is in the best place to answer this.
@Miserlou Happy to hear you want to write docs :)
I've scribbled together an untested example based on the Google OAuth 2 example but for the UserAgent flow. Let me know what errors you run into and I'll investigate...
# Credentials you get from registering a new application
client_id = '<the id you get from google>.apps.googleusercontent.com'
redirect_uri = 'https://your.registered/callback'
# OAuth endpoints given in the Google API documentation
authorization_base_url = "https://accounts.google.com/o/oauth2/auth"
scope = [
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile"
]
from oauthlib.oauth2 import MobileClient
client = MobileClient(client_id)
from requests_oauthlib import OAuth2Session
google = OAuth2Session(client_id, client=client, scope=scope, redirect_uri=redirect_uri)
# Redirect user to Google for authorization
authorization_url, state = google.authorization_url(authorization_base_url,
# offline for refresh token
# force to always make user click authorize
access_type="offline", approval_prompt="force")
print 'Please go here and authorize,', authorization_url
# Get the authorization verifier code from the callback url
redirect_response = raw_input('Paste the full redirect URL here:')
# Fetch the access token
google.token_from_fragment(redirect_response)
# Fetch a protected resource, i.e. user profile
r = google.get('https://www.googleapis.com/oauth2/v1/userinfo')
print r.content
Oh, and in the docs it is worth noting that python web apps want should not use this OAuth flow but it is perfect for desktop apps controlling a browser.
Okay cool! I actually like writing docs.. what's the point of writing a library if you don't tell people how to use it?
So we're using django-oauth-toolkit to associate clients with accounts on our web application. Because it's for mobile clients, there is no need for any callback or redirect APIs - there is no user interaction at all. The user has the client_id and a secret, it just needs to get an access token.
My purpose here is to write a python client with requests-oauthlib which can test an API configured in such a way.
So far, the only way I've found that is to do this:
response = requests.post(BASE_URL + ACCESS_TOKEN_PATH, {'grant_type': 'client_credentials', 'client_id': CLIENT_ID, 'client_secret': CLIENT_SECRET})
token = response.json() # {u'access_token': u'QMa1rtXXXXXXXXXXXXXXd', u'token_type': u'Bearer', u'expires_in': 36000, u'scope': u'read write'}
client = MobileApplicationClient(CLIENT_ID)
session = OAuth2Session(CLIENT_ID, client=client, token=token)
print session.get(API_URL + 'hello/') # <Response [200]>
Is there any way for requests-oauthlib to do the first part so I don't have to make the call directly with requests.post?
Yes. Try this code
client = oauthlib.oauth2.BackendApplicationClient(CLIENT_ID)
session = requests_oauthlib.OAuth2Session(CLIENT_ID, client=client)
token = session.fetch_token("https://your.token/endpoint", client_id=CLIENT_ID, client_secret=CLIENT_SECRET)
# store token if you fancy
session.get(API_URL + 'hello/')
It might be worth adding an alias for this way/flow along the lines of "SingleUserClient" (or "NonInteractiveSingleUserClient") as that is the second use case for this flow and possibly even more common.
Note that CLIENT_ID is supplied three times but only the last one matters as the first two are for consistency with other flows but unused. Whereas the last one forces client_id and client_secret to be included in the request (since this is not mandated in the oauth 2 spec its not always done). By using BackendApplicationClient the grant_type will be set for you.
Also note that the type of client only matters when obtaining the token. Once you have the token you can just use default.
# sometime later
token = load_token_from_db(CLIENT_ID)
session = OAuth2Session(CLIENT_ID, token=token)
print session.get(API_URL + 'hello/')
I've tried the code with the Github API but I must be doing something wrong:
import requests_oauthlib
from oauthlib.oauth2 import BackendApplicationClient
client_id = "my_client_id"
client_secret = "my_client_secret"
token_url = 'https://github.com/login/oauth/access_token'
client = BackendApplicationClient(client_id)
session = requests_oauthlib.OAuth2Session(client_id, client=client)
token = session.fetch_token(token_url, client_id=client_id, client_secret=client_secret)
# store token if you fancy
session.get('https://api.github.com/user')
I get a response from github: "error=bad_verification_code&error_description=The+code+passed+is+incorrect+or+expired.&error_uri=http%3A%2F%2Fdeveloper.github.com%2Fv3%2Foauth%2F%23bad-verification-code"
Then, I get an error: "oauthlib.oauth2.rfc6749.errors.MissingTokenError"
I've double and triple-checked my client_id and client_secret keys
I tried the above code (changing the client_id, secret, token url, etc) against my flask-oauthlib server and get an error: {"error": "invalid_client"}. The client_id and secret is valid and are in my database (and work when I do a web authorization flow).
EDIT: @lepture solved this issue with the flask-oauthlib server but still can't access github api above
Sorry for the late reply. Great that it works with flask-oauthlib now.
For GitHub, I am not certain they actually support the client credentials grant that you are trying to use. I think they only support the authorization code one. However, you can use their API with your token using basic auth which is quite similar https://developer.github.com/v3/oauth/#non-web-application-flow .