1

I am trying to use the OAuth 2.0 JWT Bearer Token Flow to get my access token for future api requests using Python 3.7 but I am receiving the following error:

{"error":"unsupported_grant_type","error_description":"grant type not supported"}

Here is my code,

import requests
import base64
import datetime
import jks
import OpenSSL
import urllib
import math

iss = '3MVG9G9pzCUSkzZs8CmmhEFtWNL2CMUdfINoZ0jVZgIxmEHXLkj2DQASd4zvCJeGOML.fZje7.y5yMyU<last couple of characters removed'
aud = 'https://login.salesforce.com'
sub = 'user@gmail.com'
exp = str(math.floor(((datetime.datetime.now()+ datetime.timedelta(minutes = 5))-datetime.datetime(1970,1,1,0,0,0)).total_seconds()))

jwtHeader = str('{"alg":"RS256"}')
jwtClaims = str('{"iss":"' + iss + '","sub":"' + sub + '","aud":"' + aud + '","exp":"' + exp + '"}')

jwtRequest = str(base64.urlsafe_b64encode(jwtHeader.encode('utf-8')).decode('utf-8')) + '.' + str(base64.urlsafe_b64encode(jwtClaims.encode('utf-8')).decode('utf-8'))

"import java key store extracted from Salesforce"
ks = jks.KeyStore.load('XXXXX.jks', 'XXXXX')

"convert to OpenSSL private key format using ASN1 - also do this for the cert"
_ASN1 = OpenSSL.crypto.FILETYPE_ASN1
pkey = OpenSSL.crypto.load_privatekey(_ASN1, pk_entry.pkey)
cert = OpenSSL.crypto.load_certificate(
    OpenSSL.crypto.FILETYPE_PEM, 
    open('WMDataLake.crt').read()
)

"check private key conversion is correct"
OpenSSL.crypto.PKey.check(pkey)

"use private key to sign request"
oSSLsign = OpenSSL.crypto.sign(pkey, jwtRequest.encode('utf-8'), "RSA-SHA256")

"verify signature is correct"
OpenSSL.crypto.verify(cert, oSSLsign, jwtRequest.encode('utf-8'), "RSA-SHA256")

Signature = str(base64.urlsafe_b64encode(oSSLsign).decode('utf-8'))

signedJwtRequest = jwtRequest + '.' + Signature

grantype = str('urn:ietf:params:oauth:grant-type:jwt-bearer')

payload = 'grant_type=' + str(urllib.parse.quote(grantype))
payload += '&assertion=' + signedJwtRequest

r = requests.post("https://login.salesforce.com/services/oauth2/token", data=payload)
print(r.text)

This is my resulting payload:

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiIzTVZHOUc5cHpDVVNrelpzOENtbWhFRnRXTkwyQ01VZGZJTm9aMGpWWmdJeG1FSFhMa2oyRFFBU2Q0enZDSmVHT01MLmZaamU3Lnk1eU15VWJrRDNEIiwic3ViIjoic2VhbnF1aW5saXZhbjg4QGdtYWlsLmNvbSIsImF1ZCI6Imh0dHBzOi8vbG9naW4uc2FsZXNmb3JjZS5jb20iLCJleHAiOiIxNTYzMjc5OTY4In0=.b9oqWczSoGKiaB-fQijI0164ScgEb8tKPhWdUH_i7j0_1muGmjs9jn8J6V8wCIsKCjk7Po56ClMn56utYsJQ2axk1cmYUfJhFJZCOk3ozvEsD5VrqFpJZNZYFF4DGMIO4zUdG0lCq0jSC8Umbznoqp4VzrDS7k6S_7sEx6YCZCZIzx09JPZV-KBdbTNtbkXTwV36UHSQGXLpRnD6c47uWYaKxghnlLd4Nyzj5k2QBUf1CYdpu2JdRhHIO0_dBzEzDrbp1QpWRmypfVpd2VgDlOe1HXo2o__Nk6g0aPT5PyK2mqYH9fHmwWCmoYN55-l5_24KCrOjTrynPJ8UFSpYbg==

Is there something I am doing wrong when setting up the payload?

Many thanks for your help.

2

Root cause: you need to explicitly set the Content-Type:

 headers = {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
r = requests.post("https://login.salesforce.com/services/oauth2/token", data=payload,headers=headers)

While having your actual assertion did help me help you, you shouldn't do that in the future. Please rotate the keys ASAP.

Other issues:

  1. Your header should include the token type. It's optional but recommended by the spec.

jwtHeader = str('{"alg":"RS256","typ":"JWT"}')

  1. You could use pyjwt (example with RSA keys) and avoid hand-coding the token construction
import jwt
token = jwt.encode(claims,key,algorithm='RS256')
  • awesome that worked, thanks so much for your help! @identigral – SeanQ Jul 16 at 2:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.