salesforcecometdbayeux

Salesforce cometD: 401::Request requires authentication


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?


Solution

  • 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.