I am trying to use OAuth2 to get an authorization token using Python to a REST API. I am successful doing so using CURL but not with python. I am using the examples provided at the following docs:
https://requests-oauthlib.readthedocs.org/en/latest/oauth2_workflow.html
The following is my code:
#!/usr/bin/python
import requests
import requests_oauthlib
from requests_oauthlib import OAuth2Session
from oauthlib.oauth2 import BackendApplicationClient
client_id = 'AAAAAA'
client_secret = 'BBBBBB'
client = BackendApplicationClient(client_id=client_id)
oauth = OAuth2Session(client=client)
token = oauth.fetch_token(token_url='https://example.com/as/token.oauth2', client_id=client_id, client_secret=client_secret)
print token
I am getting the following error:
oauthlib.oauth2.rfc6749.errors.InvalidClientError: (invalid_client) client_id value doesn't match HTTP Basic username value
This is a very basic API that only needs client_id and client_credentials to get an authorization token.
All information would be greatly appreciated.
The documentation specifies the following items:
client_id = r'your_client_id'
client_secret = r'your_client_secret'
redirect_uri = 'https://your.callback/uri'
By client key do you perhaps mean client key?
token = oauth.fetch_token(token_url='https://example.com/as/token.oauth2', client_id=client_id, client_secret=client_secret)
Try changing it to the above and give it a spin. using r'' for raw input instead and the token given.
I have found myself in a similar circumstance.
I am writing a Django app.
I was getting unauthorized_client and invalid_client exceptions.
In my case the post request in "Exchange the code" ("step 3" in the OAuth2 protocol) wasn't being formulated correctly.
Through much searching and trial and error I found it is possible to essentially customise the request. You can do this by specifying the optional arguments of auth, header and/or body.
from requests_oauthlib import OAuth2Session
from oauthlib.oauth2 import WebApplicationClient, BackendApplicationClient
from requests.auth import HTTPBasicAuth
client_id = CLIENT_ID
client_secret = CLIENT_SECRET
authorization_base_url = AUTHORIZE_URI
token_url = TOKEN_URI
redirect_uri = REDIRECT_URI
auth = HTTPBasicAuth(client_id, client_secret)
scope = SCOPE
# Create the Authorization URI
# Not included here but store the state in a safe place for later
the_first_session = OAuth2Session(client_id=client_id, redirect_uri=redirect_uri, scope=scope)
authorization_url, state = the_first_session.authorization_url(authorization_base_url)
# Browse to the Authorization URI
# Login and Auth with the OAuth provider
# Now to respond to the callback
the_second_session = OAuth2Session(client_id, state=state)
body = 'grant_type=authorization_code&code=%s&redirect_uri=%s&scope=%s' % (request.GET.get('code'), redirect_uri, scope)
token = the_second_session.fetch_token(token_url, code=request.GET.get('code'), auth=auth, body=body)
Related
I'm trying to register a Twitter webhook on an API I create on AWS API Gateway. I was able to set up the CRC portion which provides the appropriate response through a browser however I'm unable to make post requests to the same endpoint. I've been following multiple guides on this including this and this
The code is below that is giving a 403 response:
from urllib.parse import quote_plus
from requests_oauthlib import OAuth1Session
import json
import tweepy
import urllib
CONSUMER_KEY = 'xxxxxxxxxxxxx'
CONSUMER_SECRET = 'xxxxxxxxxxxxx'
ACCESS_TOKEN = 'xxxxxxxxxxxxx'
ACCESS_SECRET = 'xxxxxxxxxxxxx'
twitter = OAuth1Session(CONSUMER_KEY,
client_secret=CONSUMER_SECRET,
resource_owner_key=ACCESS_TOKEN,
resource_owner_secret=ACCESS_SECRET)
webhook_endpoint = urllib.parse.quote_plus("https://#######.execute-api.us-east-2.amazonaws.com/dev/webhook")
url = 'https://api.twitter.com/1.1/account_activity/all/:env_name/'
def register_webhook(url,twitter,webhook_endpoint):
url+=f'webhooks.json?url={webhook_endpoint}'
response = twitter.post(url)
print(response)
def subscribe_to_user_activity(url,twitter):
url+=f'subscriptions.json'
response = twitter.post(url)
print(response)
if __name__ == '__main__':
register_webhook(url,twitter,webhook_endpoint)
subscribe_to_user_activity(url,twitter)```
A couple of things I checked:
I can verify that the account is approved for account activity API, I created and counter checked the dev environment label, Keys were regenerated twice, Testing on Postman as advised here is giving a 200 forbidden response and doesn't work
In postman, I selected Oauth1.0 as the auth type and fill in Consumer Key, Consumer Secret, Access Token, Token Secret values, and provided the URL endpoint in the body. Is the POST request being sent to https://api.twitter.com/1.1/account_activity/all/:my_env_name/webhooks.json?
On the AWS side, the POST method was created on the resource with all default values
Any idea where I could be going wrong? Or a foolproof method of registering a Twitter webhook with AWS API gateway as the listener?
I am writing some code to move files over to OneDrive (enterprise account). My app is authenticated in Azure AD and should have the correct accesses (Files.ReadWrite.All in MS Graph, Sites.ReadWrite.All in Office365 SPO and User.Read in Azure AD).
The code to receive the app token works fine:
import msal
client_id = 'dc185bb*************6bcda94'
authority_host_uri = 'https://login.microsoftonline.com'
discovery_uri = 'https://api.office.com/discovery/'
client_secret = 'VsY7vV**************ToiA0='
tenant = '4a6*********************65079'
authority_uri = authority_host_uri + '/' + tenant
scopes=['https://graph.microsoft.com/.default']
app = msal.ConfidentialClientApplication(
client_id=client_id, authority=authority_uri,
client_credential=client_secret)
result = app.acquire_token_for_client(scopes=scopes)
print(result)
However, when I try to use this token with the OneDrive SDK library it seems like I am not able pass it through:
def __init__(self, http_provider, client_id=None, scopes=None, access_token=None, session_type=None, loop=None,
auth_server_url=None, auth_token_url=None):
"""Initialize the authentication provider for authenticating
requests sent to OneDrive
Args:
http_provider (:class:`HttpProviderBase<onedrivesdk.http_provider_base>`):
The HTTP provider to use for all auth requests
client_id (str): Defaults to None, the client id for your
application
scopes (list of str): Defaults to None, the scopes
that are required for your application
access_token (str): Defaults to None. Not used in this implementation.
The above is from the auth_provider.py part of the onedrivesdk, and clearly states the access_token is not used in the implementation.
Is there another way around this? Or other libraries to use?
You could try to use this Authentication of OneDrive for Business.
import onedrivesdk
from onedrivesdk.helpers import GetAuthCodeServer
from onedrivesdk.helpers.resource_discovery import ResourceDiscoveryRequest
redirect_uri = 'http://localhost:8080'
client_id = your_client_id
client_secret = your_client_secret
discovery_uri = 'https://api.office.com/discovery/'
auth_server_url='https://login.microsoftonline.com/common/oauth2/authorize'
auth_token_url='https://login.microsoftonline.com/common/oauth2/token'
http = onedrivesdk.HttpProvider()
auth = onedrivesdk.AuthProvider(http,
client_id,
auth_server_url=auth_server_url,
auth_token_url=auth_token_url)
auth_url = auth.get_auth_url(redirect_uri)
code = GetAuthCodeServer.get_auth_code(auth_url, redirect_uri)
auth.authenticate(code, redirect_uri, client_secret, resource=discovery_uri)
# If you have access to more than one service, you'll need to decide
# which ServiceInfo to use instead of just using the first one, as below.
service_info = ResourceDiscoveryRequest().get_service_info(auth.access_token)[0]
auth.redeem_refresh_token(service_info.service_resource_id)
client = onedrivesdk.OneDriveClient(service_info.service_resource_id + '/_api/v2.0/', auth, http)
Upload an Item:
returned_item = client.item(drive='me', id='root').children['newfile.txt'].upload('./path_to_file.txt')
For more examples, you can refer to this link.
I am trying to find a way to authenticate and authorize a client to access APIGEE. I can't seem to get it to function. I am using Python Requests-OAuthlib. Here is my code:
from requests_oauthlib import OAuth2Session
client_id = r'my_client_id'
client_secret = r'my_client_secret'
redirect_uri = 'https://api.usergrid.com/org/app'
oauth = OAuth2Session(client_id, redirect_uri=redirect_uri)
authorization_url, state = oauth.authorization_url('https://api.usergrid.com/org/app/token', grant_type='client_credentials')
redirect_response = raw_input(authorization_url)
token = oauth.fetch_token('https://api.usergrid.com/org/app/token', client_secret=client_secret, authorization_response=redirect_response)
url = "https://api.usergrid.com/org/app/my_collection"
r = oauth.get(url)
I get an error: "Please supply either code or authorization_code parameters."
Any ideas on what I am doing wrong? I am using the APIGEE docs found here: http://apigee.com/docs/app-services/content/authenticating-users-and-application-clients
Thank you in advance.
Your client is sending response_type=code in the authorization request. That is why the server is not performing client credential Oauth.
This could be a default behavior of your python client. In that case you might want to use a simple http client to keep things under control.
I've been following the guide for Twitter's 3-legged oauth setup:
https://dev.twitter.com/docs/auth/implementing-sign-twitter
Step 1: Obtaining a request token
For their authentication, step 1 requires making a post request containing the base64 encoded public and secret key.
key = "CONSUMER_KEY"
secret = "CONSUMER_SECRET"
auth = base64.encodestring("%s:%s" % (key, secret)).replace("\n", "")
data = {}
data["grant_type"] = "client_credentials"
headers = {}
headers["Authorization"] = "Basic " + auth
headers["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-8"
headers["Accept-Encoding"] = "gzip"
response = requests.post("https://api.twitter.com/oauth2/token",
headers=headers, data=data)
This first request returns a valid response code 200 along with an access token. The response looks like this:
{u'access_token': u'AAAAAAAAAAAAAAAAAAAAAHHHHH... ...vncbi', u'token_type': u'bearer'}
Step 2: Redirecting the user
This is where the problem is occurring. According to the docs, the user then just needs to be redirected to the authorization url formatted like this:
https://api.twitter.com/oauth/authenticate?oauth_token=AAAAAAAAAAAAAAAAAAAAAHHHHH... ...vncbi
However when I get to this page I get an error message:
Is there something I missed? The access_token is being generated without an issue. I'm not sure if this message is showing up because I set something up incorrectly earlier in the process. I'm also not sure how to check if the oauth token has expired.
Actually, you have been following https://dev.twitter.com/docs/api/1.1/post/oauth2/token which is quite different, e.g. only used for public resources and not private like status updates. For the three step one checkout https://gist.github.com/ib-lundgren/4487236 or better yet http://twython.readthedocs.org/en/latest/
If you only want to access public resources like user timelines you can do so via the code below.
# OBS: If you want to look at per user details and make status updates
# you want the OAuth1 version. This is only for publicly available
# resources such as user timelines.
from requests_oauthlib import OAuth2Session
from oauthlib.oauth2 import BackendApplicationClient
# Credentials you get from registering a new application
client_id = '<the id you get from github>'
client_secret = '<the secret you get from github>'
# TODO remove
client_id = 'VVq5UniipB5nXFAqtTA'
client_secret = 'PlaHnaSDbeY4eYkv8XiqxS1nzGWyKoq5WYSNjdeaw'
client_id = 'I1Xi7fOeYnA9jabyvGUaZxY20'
client_secret = 'k5PZpINooRpjAfQccGwLUr2ZMEtRJtoX8cKaooHjKewWupxRBG'
token_url = 'https://api.twitter.com/oauth2/token'
client = BackendApplicationClient(client_id)
twitter = OAuth2Session(client_id, client=client)
headers = {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
}
twitter.fetch_token(token_url, headers=headers, auth=(client_id, client_secret))
# Only public resources available to this application-only clients.
r = twitter.get('https://api.twitter.com/1.1/statuses/user_timeline.json?count=100&screen_name=twitterapi')
print r.content
Make sure you use the github version of the libraries
pip install git+https://github.com/idan/oauthlib.git
pip install git+https://github.com/requests/requests-oauthlib.git
At the moment i am needing to get a "success code" each time i want to run my .py app. to access my googdrive files which is a pain.
I saw Ali Afshars great vid on https://developers.google.com/drive/search-parameters where he uses:
from auth import http to streamline this process.
Not sure what this function should contain... Can you point me in the right direction, so that i can set up my .py to do this automatically ...or at least only once.
many thanks
Dav-o
EDIT relevant current snip of code follows:
import logging
logging.basicConfig()
import httplib2
import pprint
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
from oauth2client.client import *
from apiclient import errors
CLIENT_ID = "864350......ps.googleusercontent.com"
CLIENT_SECRET = "sw0yb.....-zR6XWzEgM"
OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive'
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oo...ooo' # Redirect URI for installed apps
flow = OAuth2WebServerFlow(CLIENT_ID, CLIENT_SECRET, OAUTH_SCOPE, REDIRECT_URI)
authorize_url = flow.step1_get_authorize_url()
print 'Go to the following link in your browser: ' + authorize_url
code = raw_input('Enter verification code: ').strip()
credentials = flow.step2_exchange(code)
http = httplib2.Http()
http = credentials.authorize(http)
drive_service = build('drive', 'v2', http=http)
What he probably does in auth is:
import httplib2
from oauth2client.client import OAuth2Credentials
http = httplib2.Http()
credentials = OAuth2Credentials(access_token, client_id, client_secret, refresh_token, None, '', '')
credentials.authorize(http)
You can wrap this code in a module/method and use the authenticate your requests. For multiple user scenarios, preserve access and refresh tokens (most likely in a db) and init credentials object with the stored tokens.