1

Anyone can help me with JWT Token Flow returning an error of

{"error":"invalid_client","error_description":"invalid client credentials"}

Why am I getting this error ? I suspect that I uploaded a certificate that is not properly generated, I follow this link for creating certificate. Can anyone give me tip how to make it ?

My code looks like this.

<?php 

define('CONSUMER_KEY', '3MVG9Se4BnchkASkBmpykBj5IaPSqEdI5LlfKSrNF01zm_tCszfiEC1f68oHzNAtxA.x8z6s8RGnWFqDVjq_V');
define('CONSUMER_SECRET', '2850249424022624196');
define('LOGIN_BASE_URL', 'https://cs31.salesforce.com');

//Json Header
$h = array(
    "alg" => "RS256"    
);

$jsonH = json_encode(($h)); 

$header = base64_encode($jsonH); 


//Create JSon Claim/Payload

$exp = strval(time() + (5 * 60));

$c = array(
    "iss" => CONSUMER_KEY, 
    "sub" => "[email protected]",
    "aud" => LOGIN_BASE_URL, 
    "exp" => $exp
);

$jsonC = (json_encode($c)); 

$payload = base64_encode($jsonC);

// LOAD YOUR PRIVATE KEY FROM A FILE - BE CAREFUL TO PROTECT IT USING

$private_key = <<<EOD
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDABnVDmc/WpPii
xfzRHDSRIrSgENyUV3Pr0rB1XPdlWU5PDd0J3W/Y1YI4IAh6oreQFh27Ic3CQHJm
+ZsqB4eftf/dqOOOUuuRBMEvOgfLgLk+HvFl2ZrD8zWFUkYwgY9hpobCw7kIHREv
uU1f5O6g2vkjTo5ggtKdJaUp6U8HktK+HikqMNfCHx4KgEBvzSr9Z8kC2O1PwsNd
Qr4qDU+h+WFnRs8Q/iGREAB+3llwINRme+wd09vgVNz/9KWwE2lAgnySw03XIejy
sefWtzrcHEYNi4Y4bkzOo1J2Rom1cb5OZ95qVh0yTWjNpT2LmU/uatA76OWjxkpf
zW4t+NFJAgMBAAECggEBAKW9bT1Z5xBG9+vWo64BgEW9BNYbd6f6C64B/hhuk4JA
oNyPBLfdDwrCzlCPJYJkK7gLvsGkHaqKYbQLwSd3tFHfjubNPQu8+mIDDpMqrUuy
4TCDGKxmM7TpmMpoBvka+py4VRyKPoyIOitM70HToTvphJw605ztjcfhlDsmivXm
/2c/KDo1qRPqLFn2QteVnKzyxj7m+DX5/srhh26vL+MqVuime4qDCJyClaKLoVmm
j9mwJER75mONNKmZGHKhqvV4VKVQX9pijBhxZPE2nl8H6GL5F7+jE9/omzgyk8R3
jcXCSk0sB5IlSEJK4sZCm8PmcJiZXd9ffyh/E/d4ejkCgYEA4/sWfPcTFSwfCHih
k1jD3P5fxr23HPMxEln+7PVeG+jGhtOqK4p5IzzthUCauR/eHLqdnBeOsUpiPQ3W
emktYOW62e/ZmytA47+rjK5SdJ2UtrT4s3kdqsSpJ5a475MKWezrTDAe+CEoQKT6
qjRA/1V2jsdiUZ+0AhRJCT/bu7cCgYEA16Abc8kLMJ3Js9B5tFTvx1PMxXI/aChs
V43XCVB10qMFkcfuev0pjSlQ9/dOAjUWuuR8GvsJYxrgyJeDwu8XNeoAv7qmZ50t
gJL4wTDwrJ8USxg6y5yN0DuTmevBW6XlcMHUQrj6eFa8v1iK+z7rCZigmcPFSLIy
DzLuvJu52v8CgYAfgLK60elxI4emRAUPt1RZVU0myVBkT7aYMpdnZwB6GtBUESuS
mK/kjqbDowm+SwkGL0NYLmkpVn38sczRXXdHzHblZp9LMc7lqbaq2evK8Xt7Q8aa
BkJzNnmpXspvUII9qt9Yx81/vBUz2ZhJrK7OmaCoWiTb4pWdM/Bjts9GQQKBgQDA
gkpgKlsaMZWWO4edD8Pvswp8MY8YoBZyaMlWoIZA45kiWVy6Y3IIfJ20dRApelpr
y3hd4ki0OZf8nwFdNXcEhIHcq3jLwxGP3CfI27fUdkZ48Q31ITWfdsFFx60e9NMO
w46Nb3b3n4DuWM/klnzjWWfxQE7Po4B7/14T9/iL4wKBgCUNc44sQoM0+OUEA2xP
xdg7tPon3exBpH0KlHM9lJ1AwHP50lTLZzdSHBHk4eYnpB5RUD53EOM4hZaRcdSI
iwTgbOZtx47YJ1SFslQg0Ou002lJDvShi+9oESTSDFMYGIfkVH95/hsyNvoM2dqj
nbiNXMtBJHunrRmszHe8wP/U
-----END PRIVATE KEY-----
EOD;
// This is where openssl_sign will put the signature
$s = "";

// SHA256 in this context is actually RSA with SHA256
$algo = "SHA256";   

// Sign the header and payload
openssl_sign($header.'.'.$payload, $s, $private_key, $algo);

// Base64 encode the result
$secret = base64_encode($s);

$token = $header . '.' . $payload . '.' . $secret;

$token_url =  LOGIN_BASE_URL.'/services/oauth2/token';

$post_fields = array(
    'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    'assertion' => $token
); 

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $token_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
// curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type : application/x-www-form-urlencoded"));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

$token_request_body = curl_exec($ch) 
    or die("Call to get token from code failed: '$token_url' - ".print_r($post_fields, true));

print_r($token_request_body);


?>

I set up my connected apps with digital certificates enabled and import my self - signed certificate.

enter image description here

2 Answers 2

1

It seems like you are not providing the right credentials, I would suggest you to try the method I've described in an other question: https://salesforce.stackexchange.com/a/187819/41442.

One important thing: for security reasons remove the private keys from you question!

0

Thanks for posting the original code snippet and I understand the need to use a JWT flow instead of the other proposed options. I was able to make one small change to what you had and got this working as expected.

The main problem you were facing is how the signature was encoded. Notice that I added a little extra to the base64 encoding for the secret. This properly creates the signature and helps your original example return a valid access token with very limited modifications.

A few things to note

  • I configured my app so that admin approved users were pre-authorized and then assigned only my user profile to have access. This also cuts out the step of having to authorize the app manually.

  • I also removed the CONSUMER_SECRET from the code as this isn't wasn't used anywhere.

Hope this helps any others that may run into this question.

I referenced the following articles to help me figure this out.

URLB64Encode Function

Salesforce OAuth: JWT Bearer Flow

<?php

define('CONSUMER_KEY', 'ENTER_YOUR_KEY_HERE');
define('SUB', 'ENTER_YOUR_USERNAME_HERE');
define('LOGIN_BASE_URL', 'https://login.salesforce.com');

//Json Header
$h = array(
    "alg" => "RS256"
);

$jsonH = json_encode(($h));

$header = base64_encode($jsonH);


//Create JSon Claim/Payload

$exp = strval(time() + (5 * 60));

$c = array(
    "iss" => CONSUMER_KEY,
    "sub" => SUB,
    "aud" => LOGIN_BASE_URL,
    "exp" => $exp
);

$jsonC = (json_encode($c));

$payload = base64_encode($jsonC);

// LOAD YOUR PRIVATE KEY FROM A FILE - BE CAREFUL TO PROTECT IT USING

$private_key = <<<EOD
-----BEGIN RSA PRIVATE KEY-----
ENTER_YOUR_KEY_HERE==
-----END RSA PRIVATE KEY-----
EOD;
// This is where openssl_sign will put the signature
$s = "";

// SHA256 in this context is actually RSA with SHA256
$algo = "SHA256";

// Sign the header and payload
openssl_sign($header.'.'.$payload, $s, $private_key, $algo);

// Base64 encode the result and clean up the charachters that will cause validation issues;
$secret = \str_replace('=', '', \strtr(\base64_encode($s), '+/', '-_'));


$token = $header . '.' . $payload . '.' . $secret;

$token_url =  LOGIN_BASE_URL.'/services/oauth2/token';

$post_fields = array(
    'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    'assertion' => $token
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $token_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
// curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type : application/x-www-form-urlencoded"));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

$token_request_body = curl_exec($ch)
    or die("Call to get token from code failed: '$token_url' - ".print_r($post_fields, true));

print_r($token_request_body);


?>

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .