How to serialize an OAuth1Session?

Viewed 341

I currently have a monolithic Python script which performs an OAuth authentication, returning an OAuth1Session, and then proceeds to perform some business logic using that OAuth1Session to gain authorization to a third-party service.

I need to split this up into two separate scripts, one which performs the OAuth authentication and will run on one machine, and the other which will run on a remote machine to perform the business logic authorized against the third-party service.

How can I serialize the OAuth1Session object so that the authenticated tokens can be handed off seamlessly from the authentication script on machine A to the processing script on machine B?

I tried the obvious:

print(json.dumps(session))

But I got this error:

TypeError: Object of type OAuth1Session is not JSON serializable

Is there a canonical solution for this simple requirement?

UPDATE

Here's the entire source code. Please note this is not my code, I downloaded it from the author and now I'm trying to modify it to work a bit differently.

"""This Python script provides examples on using the E*TRADE API endpoints"""
from __future__ import print_function
import webbrowser
import json
import logging
import configparser
import sys
import requests
from rauth import OAuth1Service

def oauth():
    """Allows user authorization for the sample application with OAuth 1"""
    etrade = OAuth1Service(
        name="etrade",
        consumer_key=config["DEFAULT"]["CONSUMER_KEY"],
        consumer_secret=config["DEFAULT"]["CONSUMER_SECRET"],
        request_token_url="https://api.etrade.com/oauth/request_token",
        access_token_url="https://api.etrade.com/oauth/access_token",
        authorize_url="https://us.etrade.com/e/t/etws/authorize?key={}&token={}",
        base_url="https://api.etrade.com")

    base_url = config["DEFAULT"]["PROD_BASE_URL"]

    # Step 1: Get OAuth 1 request token and secret
    request_token, request_token_secret = etrade.get_request_token(
        params={"oauth_callback": "oob", "format": "json"})

    # Step 2: Go through the authentication flow. Login to E*TRADE.
    # After you login, the page will provide a text code to enter.
    authorize_url = etrade.authorize_url.format(etrade.consumer_key, request_token)
    webbrowser.open(authorize_url)
    text_code = input("Please accept agreement and enter text code from browser: ")

    # Step 3: Exchange the authorized request token for an authenticated OAuth 1 session
    session = etrade.get_auth_session(request_token,
                                  request_token_secret,
                                  params={"oauth_verifier": text_code})

    return(session, base_url)


# loading configuration file
config = configparser.ConfigParser()
config.read(sys.argv[1])
(session, base_url) = oauth()

print(base_url)
print(json.dumps(session))

#original code
#market = Market(session, base_url)
#quotes = market.quotes(sys.argv[2])

Please note the last two commented-out lines. That is the original code: Immediate after the oauth is performed, the code invokes some business functionality. I want to break this up into two separate scripts running as isolated processes: Script 1 performs the oauth and persists the session, Script 2 reads the session from a file and performs the business functionality.

Unfortunately it fails at the last line, print(json.dumps(session)).

"XY Problem" Alert

My goal is to split up the script into two so that the business logic can run in a separate machine from the authentication code. I believe that the way to do this is to serialize the session object and then parse it back in the second script. Printing out the session using json.dumps() is an intermediate step, 'Y', in my journey to solving problem 'X'. If you can think of a better way to achieve the goal, that could be a valid answer.

1 Answers

From the comments available in the source code here: https://github.com/litl/rauth/blob/a6d887d7737cf21ec896a8104f25c2754c694011/rauth/session.py

You only need to serialize some attributes of your object to reinstantiate it:

    Line 103
    def __init__(self,
                     consumer_key,
                     consumer_secret,
                     access_token=None,
                     access_token_secret=None,
                     signature=None,
                     service=None):
     ...

Thus I would suggest serializing the following dict on the first machine:

info_to_serialize = {
    'consumer_key': session.consumer_key,
    'consumer_secret': session.consumer_secret,
    'access_token': session.access_token,
    'access_token_secret': session.access_token_secret
}
serialized_data = json.dumps(info_to_serialize)

And on the second machine reinstantiate your session like that:

from rauth.session import OAuth1Session

info_deserialized = json.loads(serialized_data)
session = OAuth1Session(**info_deserialized)

Hope this helped

Related