Reputation: 481
I'm following the sparse instructions laid out here:https://metamind.readme.io/docs/generate-an-oauth-token-using-your-key
I need to be able to generate a Bearer Token in order to be able to access the Einstein services directly from .net, and specifically .net 4.5.
As the support for RSACryptoServiceProvider.ImportRSAPrivateKey is not available until .net 5, I've converted my pem file (Downloaded from salesforce) to an xml format (Using https://superdry.apphb.com/tools/online-rsa-key-converter) and I'm using that to sign a JWT assertion. I get an encoded assertion, but when I post it to the https://api.einstein.ai/v2/oauth2/token service, I keep getting an "Invalid Token" message.
Here is my code:
Claim[] claims = new[] {
new Claim(JwtRegisteredClaimNames.Sub, this.Username),
new Claim(JwtRegisteredClaimNames.Aud, this.Endpoint.ToString()),
new Claim(JwtRegisteredClaimNames.Exp, ((int)expiryUnixTimeStamp).ToString())
};
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
provider.FromXmlString(this.RsaXmlString);
RsaSecurityKey rsaSecurityKey = new RsaSecurityKey(provider);
SigningCredentials signingCredentials = new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha256);
JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(
new JwtHeader(signingCredentials),
new JwtPayload(claims)
);
string jwtToken = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
I've checked all my parameters. I can use the same pem key and username to successfully create a Bearer Token, using the browser interface, so why does it fail in code?
Upvotes: 0
Views: 418
Reputation: 481
The answer to this issue is to not generate ones JwtPayload from a Claims array. It compiles, but the Claim constructor only takes string values. There is a valueType argument, but that too is a string, the content of which is undocumented. I could find no value for valueType that would enable me to specify the 'exp' value as being an integer. So the problem was that my unixtimestamp was being serialized as a string and this was invalidating the assertion.
Solution: the JwtPayload.Add method, takes an object instead of a string...
JwtPayload jwtPayload = new JwtPayload();
jwtPayload.Add(JwtRegisteredClaimNames.Sub, this.Username);
jwtPayload.Add(JwtRegisteredClaimNames.Aud, this.Endpoint.ToString());
jwtPayload.Add(JwtRegisteredClaimNames.Exp, (int)expiryUnixTimeStamp);
JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(
new JwtHeader(signingCredentials),
new JwtPayload(jwtPayload)
);
Upvotes: 0