1

I have to subscribe to cometD Salesforce channel and hence building cometD client in python. I am using the below python library.

https://github.com/dkmadigan/python-bayeux-client

And below is the handshake response I am getting

{'Host': ['xxxxx.my.salesforce.com/cometd/42.0/'], 'Content-Type': ['application/x-www-form-urlencoded'], 'Authorization': ['admin@123Pi6s9Y2QVergfergregpqqY']} message={"channel":"/meta/handshake","id":"1",
            "supportedConnectionTypes":["callback-polling", "long-polling"],
            "version":"1.0","minimumVersion":"1.0"} Headers({'host': ['xxxxx.my.salesforce.com/cometd/42.0/'], 'content-type': ['application/x-www-form-urlencoded'], 'authorization': ['admin@123Pi6s9Y2QVergfergregpqqY']}) {u'successful': False, u'advice': {u'reconnect': u'none'}, u'ext': {u'replay': True, u'sfdc': {u'failureReason': u'401::Request requires authentication'}, u'payload.format': True}, u'error': u'403::Handshake denied', u'id': u'1', u'channel': u'/meta/handshake'}

And I am getting 401::Request requires authentication.

In the Authorization key, I have concatenated password and Access token i.e. admin@123Pi6s9Y2QVergfergregpqqY where admin@123 is the password I use to login to Salesforce.

I have been banging my head since 2 days but not able to figure out why handshake is failing. Any suggestions?

Gagan
  • 1,775
  • 5
  • 31
  • 59

1 Answers1

2

I believe that the authorization key is incorrect. It is not your password that is expected but an OAuth access token or session id that you receive after you log into salesforce. See the different OAuth flows, if you are testing you can use the username password flow.

The following method u can use to get the session id when needed

import requests
import json

LOGIN_INSTANCE_URL = 'https://test.salesforce.com/services/oauth2/token'
LOGIN_USER_NAME = 'username_here'
CLIENT_ID = 'connected app consumer key'
CLIENT_SECRET = 'connected app consumer secret'
PASSWORD = 'password token'

def connect(authUrl, clientId, secret, username, password):
    headers = {
            }        
    postBody = { 
                'grant_type': 'password',
                'client_id': clientId,
                'client_secret':secret,
                'username': username,
                'password': password
            }
    try:
        response = requests.post(authUrl, data = postBody, headers = headers)
        #response.raise_for_status()
        if (response.status_code == 200):
            authResponse = response.json()
            return authResponse['access_token']
        else: #if not 200 see what the problem was
            print response.text  
    except requests.exceptions.RequestException as e:  
        print e

print(connect(LOGIN_INSTANCE_URL, CLIENT_ID, CLIENT_SECRET, LOGIN_USER_NAME, PASSWORD))

This is just sample code that should work, but you need to create a connected app first. for stand alone app without user intervention JWT flow is better.

Gareth Jordan
  • 968
  • 1
  • 6
  • 10
  • Yes i actually appended security token with the password i use. Isnt it the case? I also have used only the access token but it still giving the same output. Essentially, {'Authorization': 'Pi6s9Y2QVergfergregpqqY'} – Gagan May 29 '18 at 23:21
  • Look at the docs for an example. The access token is not something you initially have. You get it as part of the response to a successful authentication. You can use your password and security token to authenticate using the username password flow, I'll update my answer with an example when I get to a computer. The authorization header value would be "Bearer long_access_token" – Gareth Jordan May 30 '18 at 00:55
  • So I am using the security token which I got when i reset it by going to the setup at the Salesforce. And then I was concatenating it with the Password. Looks like I was doing wrong then. Waiting for you to get your computer. I am burned in this task :(. – Gagan May 30 '18 at 01:01
  • I am able to retrieve the data with the help of session_id but that is short lived since it expires after some time. I am trying to implement long_access_token as you told me. – Gagan May 30 '18 at 07:26
  • Finally it worked. Just only one thing. The password you given in the POST request should be the concatenation of Password+Security token which was got from Reset security token link. Thanks @Gareth. – Gagan May 30 '18 at 15:08
  • 1
    yes that's why i put password token but i should have been more explicit on which token but i figured that u would know since u were initially trying that – Gareth Jordan May 30 '18 at 15:18
  • Hi Gareth, Is there any possibility of expiring this token in 24hours? Strangely it expires after 24 odd hours and I have to regenerate it every morning. :( – Gagan Jun 08 '18 at 01:01
  • 1
    Your token will expire if not used, so you can use a different oauth flow which provides a refresh token and get a new access token via the refresh token or update your code to re-authenticate if an invalid session error is received – Gareth Jordan Jun 08 '18 at 14:06
  • Yes that was exactly the case. I did not use it for some days. Thanks Gareth. – Gagan Jun 08 '18 at 23:48