simple-salesforce icon indicating copy to clipboard operation
simple-salesforce copied to clipboard

Support for Oauth token requests

Open alexan32 opened this issue 5 years ago • 2 comments

Hey guys, I've just started using simple sales force, and it's been a pretty great tool to work with so far.

Right now I'm working on getting salesforce to work with oauth, and unfortunately the documentation is pretty vague on that point.

From what I understand from reading issue #107, simple-salesforce does not directly support token oauth requests. I had to use a separate python module to get the oauth access token, which I then use to set the session_id variable.

#107 is a pretty old issue, so I was wondering if you have since added or plan to add a way to retrieve the access token from the salesforce module itself. For me it would be a great quality of life improvement.

alexan32 avatar May 05 '20 14:05 alexan32

Want to add that this is the only reason that I cannot use simple-salesforce for my integration. For external reasons, I can't use a username/password to authenticate. Oauth works well but it isn't easy to get.

In the meantime - this comment supplies code that should help.

https://github.com/simple-salesforce/simple-salesforce/pull/128#issuecomment-548453633

adam133 avatar Jun 03 '20 15:06 adam133

Hello, my workd around is to OAuth 2.0 JWT. You can have more info on setting it up Salesforce OAuth2 JWT I pretty much do something as follow

  1. I have JWTOauth class
class JWTOAuth(object):

    base_url = 'https://login.salesforce.com'
    token_url = 'https://login.salesforce.com/services/oauth2/token'
    algorithm = 'RS256'

    def __init__(self, claims, private_key):
        self.claims = claims
        self.private_key = private_key

    @property
    def nonce(self):
        alphabet = string.ascii_letters + string.digits
        return '_' + ''.join(random.SystemRandom().choice(alphabet) for i in range(20))

    @property
    def assertion(self):
        self.claims['jit'] = self.nonce
        self.claims['exp'] = int(time.time()) + 300
        return jwt.encode(self.claims, self.private_key, algorithm=self.algorithm)

    def get_token(self):
        data = {
            'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
            'assertion': self.assertion.decode('utf-8')
        }
        resp = requests.post(self.token_url, data=data)
        return resp
  1. A simple salesfore wrapper
class SFWrapper(object):

    def __init__(self, claims, private_key):
        self.claims = claims
        self.private_key = private_key
        self.access_token = None
        self.session = None

    def get_access_token(self, *args, **kwargs):
        oauth = JWTOAuth(self.claims, self.private_key)
        resp = oauth.get_token()
        self.oauth = oauth
        if 'access_token' not in resp.json():
            raise ValueError(resp.json())
        self.access_token = resp.json()
        return self.access_token

    def authenticate(self):
        token = self.access_token
        self.session = Salesforce(instance_url=token['instance_url'], session_id=token['access_token'])
        return self.session

    def get_session(self):
        self.get_access_token()
        return self.authenticate()
  1. I can now use simple_salesforce as follow:
>>> sf = SFWrapper(claims, private_key)
>>> sf.get_session()
>>> sf.session.query('SELECT id, name FROM Account')

I mainly use it for Bulk Load though. Hope it helped

josuebrunel avatar Sep 24 '20 04:09 josuebrunel