Salesforce Asked on December 12, 2021
I am trying to use OAuth JWT Token Bearer Flow to connect to the Salesforce REST API from C#.
I have configured a Connected App within Salesforce and uploaded the certificate used to sign the token request. I have enabled all available OAuth scopes.
This is the C# code used to call Salesforce.
public static dynamic GetAccessToken()
{
// certificate
var certificate = new X509Certificate2(@"C:Tempmiketest.pfx");
// header
var header = new { alg = "RS256" };
// claimset
var expiryDate = GetExpiryDate();
var claimset = new
{
iss = "3MVG9Y6d_Btp4xp43PirpOECJJz5VZ7iFn54V1KCtfvFBvS9RMyenB.Hx7cavL.GAkTx4yabyPV0Zk5T2nrvU",
prn = "[email protected]",
aud = "https://login.salesforce.com",
exp = expiryDate
};
var ser = new JavaScriptSerializer();
// encoded header
var headerSerialized = ser.Serialize(header);
var headerBytes = Encoding.UTF8.GetBytes(headerSerialized);
var headerEncoded = Convert.ToBase64String(headerBytes);
// encoded claimset
var claimsetSerialized = ser.Serialize(claimset);
var claimsetBytes = Encoding.UTF8.GetBytes(claimsetSerialized);
var claimsetEncoded = Convert.ToBase64String(claimsetBytes);
// input
var input = headerEncoded + "." + claimsetEncoded;
var inputBytes = Encoding.UTF8.GetBytes(input);
// signiture
var rsa = certificate.PrivateKey as RSACryptoServiceProvider;
var cspParam = new CspParameters
{
KeyContainerName = rsa.CspKeyContainerInfo.KeyContainerName,
KeyNumber = rsa.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2
};
var aescsp = new RSACryptoServiceProvider(cspParam) { PersistKeyInCsp = false };
var signatureBytes = aescsp.SignData(inputBytes, "SHA256");
var signatureEncoded = Convert.ToBase64String(signatureBytes);
// jwt
var jwt = headerEncoded + "." + claimsetEncoded + "." + signatureEncoded;
var client = new WebClient();
client.Encoding = Encoding.UTF8;
var uri = "https://login.salesforce.com/services/oauth2/token";
var content = new NameValueCollection();
content["assertion"] = jwt;
content["grant_type"] = "urn:ietf:params:oauth:grant-type:jwt-bearer";
string response = Encoding.UTF8.GetString(client.UploadValues(uri, "POST", content));
var result = ser.Deserialize<dynamic>(response);
return result;
}
private static int GetExpiryDate()
{
var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var currentUtcTime = DateTime.UtcNow;
var exp = (int)currentUtcTime.AddMinutes(4).Subtract(utc0).TotalSeconds;
return exp;
}
This is the request
POST https://login.salesforce.com/services/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: login.salesforce.com
Content-Length: 729
Expect: 100-continue
Connection: Keep-Alive
assertion=eyJhbGciOiJS.......Z633ERQ%3d%3d&grant_type=urn%3aietf%3aparams%3aoauth%3agrant-type%3ajwt-bearer
And the response
HTTP/1.1 400 Bad Request
Date: Sun, 19 Oct 2014 23:03:25 GMT
Set-Cookie: BrowserId=pBV8Q_i6RfePkxjH67e96Q;Path=/;Domain=.salesforce.com;Expires=Thu, 18- Dec-2014 23:03:25 GMT
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Pragma: no-cache
Cache-Control: no-cache, no-store
Date: Sun, 19 Oct 2014 23:03:25 GMT
Set-Cookie: BrowserId=-RgZomTjQIiwKzVT8ZnibQ;Path=/;Domain=.salesforce.com;Expires=Thu, 18-Dec-2014 23:03:25 GMT
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Pragma: no-cache
Cache-Control: no-cache, no-store
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
{"error_description":"invalid client credentials","error":"invalid_client"}
If anyone has this working for a .Net client, any help or advice would be greatly appreciated.
You are using plain base64 encoding, but JWT uses base64url, where -
and _
are used in place of +
and /
respectively, with no =
padding. You could do something like:
static string ToBase64UrlString(byte[] input) {
return Convert.ToBase64String(input).TrimEnd('=').Replace('+', '-').Replace('/', '_');
}
Answered by metadaddy on December 12, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP