Search code examples
pythonapioauth-2.0access-tokenstrava

How to access authentication by Strava API using Python?


I am starting a small python script (not an application) that can upload my *.fit activity files on Strava whenever they are created in a desired folder.

The main steps I plan to do are:

1. monitor *.fit file system modifications
2. access authentication to Strava to enable my program to upload files
   (This tool will be personal use only, thus I expect no need to authenticate every time uploading)
3. upload the file to my Strava account
4. automatically doing this fixed routine with the help of Windows Task Scheduler
   (For example, there will be 4-5 new riding activities generated in my computer folder, I expect this tool can automatically upload all of them once a week so that I do not need to manually complete the task.)

For step2, I really have no ideas how to implement even though reading through Strava Authentication Documentation and several source codes other peoples have developed (e.g. toravir's "rk2s (RunKeeper 2 Strava)" project on GitHub). I grabbed that some of the python modules like stravalib, swagger_client, request, json, etc. as well as concepts like OAuth2 may be related to step2 but I still can not put everything together...

Can any experienced give me some advice for the implementations of step2? or any related readings will be perfect!

Advice for other parts of this project will also be very welcomed and appreciated.

I thank you very much in advance:)


Solution

  • This is a code example on how you can access the Strava API, check out this gist or use the code below:

    import time
    import pickle
    from fastapi import FastAPI
    from fastapi.responses import RedirectResponse
    from stravalib.client import Client
    
    CLIENT_ID = 'GET FROM STRAVA API SITE'
    CLIENT_SECRET = 'GET FROM STRAVA API SITE'
    REDIRECT_URL = 'http://localhost:8000/authorized'
    
    app = FastAPI()
    client = Client()
    
    def save_object(obj, filename):
        with open(filename, 'wb') as output:  # Overwrites any existing file.
            pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
    
    def load_object(filename):
        with open(filename, 'rb') as input:
            loaded_object = pickle.load(input)
            return loaded_object
    
    
    def check_token():
        if time.time() > client.token_expires_at:
            refresh_response = client.refresh_access_token(client_id=CLIENT_ID, client_secret=CLIENT_SECRET, refresh_token=client.refresh_token)
            access_token = refresh_response['access_token']
            refresh_token = refresh_response['refresh_token']
            expires_at = refresh_response['expires_at']
            client.access_token = access_token
            client.refresh_token = refresh_token
            client.token_expires_at = expires_at
    
    @app.get("/")
    def read_root():
        authorize_url = client.authorization_url(client_id=CLIENT_ID, redirect_uri=REDIRECT_URL)
        return RedirectResponse(authorize_url)
    
    
    @app.get("/authorized/")
    def get_code(state=None, code=None, scope=None):
        token_response = client.exchange_code_for_token(client_id=CLIENT_ID, client_secret=CLIENT_SECRET, code=code)
        access_token = token_response['access_token']
        refresh_token = token_response['refresh_token']
        expires_at = token_response['expires_at']
        client.access_token = access_token
        client.refresh_token = refresh_token
        client.token_expires_at = expires_at
        save_object(client, 'client.pkl')
        return {"state": state, "code": code, "scope": scope}
    
    try:
        client = load_object('client.pkl')
        check_token()
        athlete = client.get_athlete()
        print("For {id}, I now have an access token {token}".format(id=athlete.id, token=client.access_token))
    
        # To upload an activity
        # client.upload_activity(activity_file, data_type, name=None, description=None, activity_type=None, private=None, external_id=None)
    except FileNotFoundError:
        print("No access token stored yet, visit http://localhost:8000/ to get it")
        print("After visiting that url, a pickle file is stored, run this file again to upload your activity")
    

    Download that file, install the requirements, and run it (assuming the filename is main):

    pip install stravalib
    pip install fastapi
    pip install uvicorn
    uvicorn main:app --reload