pythonoauth-2.0basecamp

How can I automate authentication to basecamp 3 api (preferably in python)?


This is my first foray into OAuth, so please be patient with me if I'm way off base, or going in an entirely wrong direction.

I want to write a script to pull information from basecamp 3, format it, and send it in an email. I already do this with basecamp 2 and it works fine. But basecamp 3 does not allow simple authentication. This is just a script that runs via cron once per week.

Most of the OAuth examples I've found require getting an authorization url, going to it in a browser, granting authorization, etc in order to get an access token. Please tell me there is an automated way! I can't let this become a manual process.

I tried the Backend Application Flow with requests-oauthlib (found here: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#backend-application-flow)

I have tried their example pretty much straight up without luck:

from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session

ktclient_id = r'my-client-id'
ktclient_secret = r'my-client-secret'
ktredirect_uri = r'http://www.company.com/whatever'

client = BackendApplicationClient(client_id=ktclient_id)
oauth = OAuth2Session(client=client)

token = oauth.fetch_token(token_url=r'https://launchpad.37signals.com/authorization/token',
                        client_id=ktclient_id,
                        client_secret=ktclient_secret)

Here is the error that I get:

Traceback (most recent call last):
  File "./get-token.py", line 20, in <module>
    client_secret=ktclient_secret)
  File "/home/mwilson/.local/lib/python2.7/site-packages/requests_oauthlib/oauth2_session.py", line 244, in fetch_token
    self._client.parse_request_body_response(r.text, scope=self.scope)
  File "/home/mwilson/.local/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 409, in parse_request_body_response
    self.token = parse_token_response(body, scope=scope)
  File "/home/mwilson/.local/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 376, in parse_token_response
    validate_token_parameters(params)
  File "/home/mwilson/.local/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 386, in validate_token_parameters
    raise MissingTokenError(description="Missing access token parameter.")
oauthlib.oauth2.rfc6749.errors.MissingTokenError: (missing_token) Missing access token parameter.

I've tried specifying the redirect_uri in the line

oauth = OAuth2Session(client=client, redirect_uri=ktredirect_uri)

And I get the same result. Anyone ever have any luck with this? What other parameter does basecamp 3 require?


Solution

  • Basecamp 3 supports Oauth2 authentication with a web server only,

    You need to follow the following steps:

    1. Make a request to basecamp with your client id and client secret and get an access code
    2. Trade the access code you received for an access token, refresh token and expiry time

    You could proceed with a flask or django app for the same.

    1. You need to register your app at https://launchpad.37signals.com/integrations

    2. For django you could specify the redirect url as localhost:8000/view_name

    3. The access token you get after following the steps could be used to make any request through the api. Usually the access token lasts for about a week or more until you overuse it.

    Example for a django app: views.py:

    def authorize_basecamp(request) :
        return HttpResponseRedirect("https://launchpad.37signals.com/authorization/new?type=web_server&client_id=<your client id>&redirect_uri=<your redirect url>")
    

    above would be to redirect the client to the basecamp authentication site where he will log in and authorize your web app through basecamp

    Suppose the url specified as redirect is : http://localhost:8000/app_name/get_token/ then the view for getting the access token will be :

    def get_token (request) :
        print  (request)
        URL = "https://launchpad.37signals.com/authorization/token"
        # your API key here 
        client_id ="<your_id>"
        client_secret = "<your secret>"
        ver_code = request.GET.get('code')
        redirect_uri = "http://localhost:8000/app_name/get_token/"
    
        data = {'type':'web_server', 'client_id':client_id, 'client_secret':client_secret, 'redirect_uri':redirect_uri,'code':ver_code } 
    
        # sending post request and saving response as response object
        print (ver_code, URL) 
        r = requests.post(url = URL, data = data)
        print (r)
        dic = r.json()
        access_token = dic['access_token']
        refresh_token = dic['refresh_token']
    
        headers = {
            'Authorization': 'Bearer '+access_token,
            'User-Agent': '<your agent_name>',
        }
    
        response = requests.get('https://launchpad.37signals.com/authorization.json', headers=headers)
    
        dic2 = response.json()
    
        expires_at = dic2['expires_at']
        lis_api_urls = []
    
        for j in dic2['accounts']: 
            lis_api_urls.append(j['href'])
    
        api_base_url = lis_api_urls[0]
    
        
        return HttpResponse("Access Token : %s Refresh Token : %s ".format(access_token,refresh_token))