I have my own private key string, i.e.
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCSAYYgzvGTww....
....
....
.....
3yUMYj9oYzqdrRHP0XgD0cEEvyqPBwLaNsRdFw
I recently had to achieve something similar and came across an error "Invalid Algorithm Specified" when signing my payload, so have solved my specific issue I thought I'd share the code. I think that may be useful to you too.
You can find a full explanatory [ReadME][2], and source code at Karama.Jwt.Public. I happen to be using a different library for generating my JWT, namely JOSE, but I think that this is incidental, and for completeness, there is a project achieving the same end using no third party libraries.
Please let me know how you get on.
I'll list my answer in steps
Install-package Jose-jwt
Using OpenSSL, pack your private key in the form of a PKCS12 file (*.p12), you'll set a password for the file in the process.
openssl pkcs12 -export -nocerts -in ./myKey.key -out my-Key.p12
as listed on the Library's readme, you'll need to generate an RSACryptoServiceProvider
from that file, like this:
var privateKey=new X509Certificate2("my-key.p12", "password", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet).PrivateKey as RSACryptoServiceProvider;
Use the RSACryptoServiceProvider
createdalong with the password set up during the PKCS12 packing to encode your payload like this:
string token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256);
I found some purely Javascript based solution, if it is useful to anyone. You can find the JS Libraries here.
It has resolved my requirement.
The key to this question is using JWT and Bouncy castle libraries for encoding the token and signing it respectively.
First, you need to transform the private key to the form of RSA parameters. Then you need to pass the RSA parameters to the RSA algorithm as the private key. Lastly, you use the JWT library to encode and sign the token.
public string GenerateJWTToken(string rsaPrivateKey)
{
var rsaParams = GetRsaParameters(rsaPrivateKey);
var encoder = GetRS256JWTEncoder(rsaParams);
// create the payload according to your need
var payload = new Dictionary<string, object>
{
{ "iss", ""},
{ "sub", "" },
// and other key-values
};
var token = encoder.Encode(payload, new byte[0]);
return token;
}
private static IJwtEncoder GetRS256JWTEncoder(RSAParameters rsaParams)
{
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(rsaParams);
var algorithm = new RS256Algorithm(csp, csp);
var serializer = new JsonNetSerializer();
var urlEncoder = new JwtBase64UrlEncoder();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
return encoder;
}
private static RSAParameters GetRsaParameters(string rsaPrivateKey)
{
var byteArray = Encoding.ASCII.GetBytes(rsaPrivateKey);
using (var ms = new MemoryStream(byteArray))
{
using (var sr = new StreamReader(ms))
{
// use Bouncy Castle to convert the private key to RSA parameters
var pemReader = new PemReader(sr);
var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
return DotNetUtilities.ToRSAParameters(keyPair.Private as RsaPrivateCrtKeyParameters);
}
}
}
ps: the RSA private key should have the following format:
-----BEGIN RSA PRIVATE KEY-----
{base64 formatted value}
-----END RSA PRIVATE KEY-----