[SalesForce] Generate JWToken from salesforce using Consumer Secret

I am trying to connect to an API and based on their requirement, JWToken is required to make a call and the JWToken must be signed using the provided consumer secret.

Now, they have a sample code in python that works well. I just want to know how to make it work with salesforce.

Here's the python code: (i've replaced the consumer id,secret,token and endpoints with random values.)

import jwt
import _datetime
import requests

app_consumer_id = "000"
app_consumer_secret = "000"
app_access_token = "0000"
base_url = "https://baseurl.com"
end_point = "/API/endpoint/version/client/"
httpMethod = "GET"

# obtain the uri for the endpoint I'm going to query for
uri = base_url + end_point

# set up the jwt token claims dictionary
claims = {
    "iss": "http://mydomain.com.au",
    "aud": "https://audience.com",
    "nbf": _datetime.datetime.utcnow(),
    "exp": _datetime.datetime.utcnow() + _datetime.timedelta(seconds=60),
    "consumerId": app_consumer_id,
    "accessToken": app_access_token,
    "url": uri,
    "httpMethod": httpMethod
}

# create the base64 encoded JWtoken string as byte code
encoded_jwt_byte = jwt.encode(claims, app_consumer_secret, algorithm='HS256')

# convert the byte code to a string
jwt_str = str(encoded_jwt_byte, 'utf-8')

# create signing headers
headers = {'Authorization': 'JwToken' + ' ' + jwt_str, 'content-type': 'application/json'}

# send the request and obtain the result
response = requests.get(uri, verify=True, headers=headers, timeout=45)

# print the returned json to my console
print(response.json())

Best Answer

It's pretty similar with Salesforce, but your sample code has the parameters incorrect for the platform. See OAuth 2.0 JWT Bearer Token Flow from the Salesforce documentation for more details. Rather than using the JWT for authorization on REST requests, you'll exchange it for an access token, which you'll then include with a Bearer authorization header (if you're constructing your REST requests manually).

I use JWT in Python in one of my projects and have a Gist available showing how to use it with simple_salesforce. It's short, so I'll include the entirety here:

import jwt
import requests
import datetime
from simple_salesforce import Salesforce
from simple_salesforce.exceptions import SalesforceAuthenticationFailed

def jwt_login(consumer_id, username, private_key, sandbox=False):
    endpoint = 'https://test.salesforce.com' if sandbox is True else 'https://login.salesforce.com'
    jwt_payload = jwt.encode(
        { 
            'exp': datetime.datetime.utcnow() + datetime.timedelta(seconds=30),
            'iss': consumer_id,
            'aud': endpoint,
            'sub': username
        },
        private_key,
        algorithm='RS256'
    )

    result = requests.post(
        endpoint + '/services/oauth2/token',
        data={
            'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
            'assertion': jwt_payload
        }
    )
    body = result.json()

    if result.status_code != 200:
        raise SalesforceAuthenticationFailed(body['error'], body['error_description'])
    
    return Salesforce(instance_url=body['instance_url'], session_id=body['access_token'])

Call jwt_login() with the consumer Id, username, JWT signing key, and a Boolean for sandbox or production and you'll get back a simple_salesforce.Salesforce instance. If you aren't using that library and just want the access token, you could return body['access_token'] instead and modify the error handling.

N.b. as written this requires Python 3.6 for the time handling.