How to set kid header claim in jwt from RSA private key? - c#

I want to generate a JWT token with "kid" header claim. I have a RSA private key in XML format to sign the JWT token. But in my JWT, I can not find "kid" header claim along with type and alg. How can I do this?
Here is the code to generate JWT token:
public async Task<IActionResult> Generate()
{
var rsa = RSA.Create();
string key = await System.IO.File.ReadAllTextAsync(options.PrivateKeyFilePath);
rsa.FromXmlString(key);
var credentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256);
var jwt = new JwtSecurityToken(
new JwtHeader(credentials),
new JwtPayload(
"webapi",
"webapi",
new List<Claim>(),
DateTime.UtcNow,
DateTime.UtcNow.AddHours(3)
)
);
string token = new JwtSecurityTokenHandler().WriteToken(jwt);
return Ok(new { Token = token });
}
Here is my RSA private key.
<RSAKeyValue>
<Modulus>yRfxNTDYqxjEgow6HHBPBEiK6NrVCyLFpG8dklP7f7kFuKZozHopqnly/24Gf6jt9xYLFIsQhhRcuclzEKNnBcWzKlXg9xRwk0o2JzPCh1Ifn1XQ67FrD8+HlBT9DfxjkvzCkPLxi8UWxgifIGauVeFbhIOkVfS0JrIJyQI33sUmiciBGXnO9CjEUpiBcoY53CRa49aUBoKJFDuHV2zuPWCEHLYXrP8Ns15jRU70V/YYUzU3R3PnWk3ZA/12YqtMAJaXFE33DQE71Ccd6HsXfUJpJAM81O/pDPDsk3b3260eN20nLDT0F2acOYQb/3bVKzqZ97isZYqekkmXdeuy4Q==</Modulus>
<Exponent>AQAB</Exponent>
<P>5iuGQcTqCvpwII6EOr1+F98GviZ/PWtHoDkiP8ZiSVCH8XEYCiuPmuWBtOYlv+hLJ9zWUVPkD5uIatLttT6ZxCi7oP+A6htgTbRyLN4NAibwtfQAKQOtue98HyIE6J17OPu8EVBXUSL9rC98OxcbxqDPLOX0geWoIt8BIE9v5js=</P>
<Q>36kW0+j+wHZyx6weriPO5xBAdYBmrd04rSM2hNEZETHMm30JzSYdfU3HATGYiCwexXGlioRMM6xm84DHkWo3Abqaeou2JRFR7PD3UTnsvYBxFxlTd4RfRcNvdvZHFkN4U1sik0FkYbSit6zGU2agEaegp5Jt0vT+CeDonMrUjZM=</Q>
<DP>INPGUy0FgElVop8Q5tvN1xO8/3O4JAdf8M8VPmlJ7VDqAppxpkmuMpZXGHjWm3dC+M17V6ASX9N78lhhBL+H6L0yfXTTaxA6fPqmahXFXzA0lo7VUwQuS92HI12Tu6VyRJ9KpGGEApNuAJfJLRhPotWelrW5WKlrgIWzwGrz968=</DP>
<DQ>A/1PI+6HBMXYHEmsrmyDF0oJ7E6jBjzo8uWq5kmYid76iFd9okQoyIBnqVTKJLusvNbfHg5oEY/ksjk81hIv8v7yHHd7g0PA01ok/zTqTSMKYWAZRgt9a5Al39hawkHn1ozMnBXRhZCkSmRxkTFGb6ouym5pORcXpPN3Erznd7M=</DQ>
<InverseQ>IOdFLHWNtVoAMGAp1wuHWqXIv0BnLnJSce7h+iwm3e165oiszxYa/k/UrMam8qlbjESBZM43oJwGyXtBFVjdTNxyugw5rF04xgrDtMjqb/ZxK1mdoidL15Ij/NZpbd5HtVZ8nzf38wRvMYIzZSA06/V5cYI2molR6gMcWEaClJw=</InverseQ>
<D>N1dzdmP+/PdP/W2CAJmX5WHheLvgrbPgGKTLyp16NWhB/tMtPDjShqvtzgYFm9RtyPY0Dm9HGN85tZePJyERFTGXYStJQjZJ1P8zcA56lqsvMLZ5TKQDBtLiSQqNqe+vp6AQG7wAZarT3aQ5xrz7dX8TpKBl9ZHmkk+lCcCmh5PVZYaRhYTfJp1vONjKKA1L/ivOxKKmjcQnky/A0Po24d8lI5iBLaCco6dThZqvDdfhbudkFnbTDIsb0K/NEqTlC9/XH59CKSUU+jwNY2B1P9MUodmqdi5sce3OIw9sffPcBaSypLiCEH8IvAFyZCWFuxR6zdSBOyQrfu4KNfcNEQ==</D>
</RSAKeyValue>

The kid can be set with the SecurityKey.KeyId property:
...
var rsaSecurityKey = new RsaSecurityKey(rsa);
rsaSecurityKey.KeyId = "your kid";
var credentials = new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha256);
...
With this, the first part of the generated token is Base64url decoded:
{"alg":"RS256","kid":"your kid","typ":"JWT"}

Related

Verify JWT token signature with public key in C#

I am not familiar with JWT token and RSA algorithms. I want to generate a JWT token with public and private key by using RSA Algorithm. I need to sign the token with private key and share the public key for other end for them to verify.
I have generated the token by the below code and verified the generated token in JWT.IO site with the public key generated. But it is showing invalid signature.
Kindly assist me on this. Thanks
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
//get the public key
string publicKey = rsa.ToXmlString(false);
string privateKey = rsa.ToXmlString(true);
var privateKeyVal = new RsaSecurityKey(rsa);
byte[] privateKeyBytes = Encoding.UTF8.GetBytes(privateKey);
string privateKeyPem = Convert.ToBase64String(privateKeyBytes);
privateKeyPem = "-----BEGIN PRIVATE KEY-----" + privateKeyPem + "-----END PRIVATE KEY-----";
byte[] publicKeyBytes = Encoding.UTF8.GetBytes(publicKey);
string publicKeyPem = Convert.ToBase64String(publicKeyBytes);
publicKeyPem = "-----BEGIN PUBLIC KEY-----" + publicKeyPem + "-----END PUBLIC KEY-----";
var jwttok = new JwtSecurityToken(
issuer: "iss",
audience: "aud",
claims: new List<Claim> { new Claim("user_id", "123") },
expires: DateTime.Now.AddMinutes(30),
signingCredentials: new SigningCredentials(
privateKeyVal,
SecurityAlgorithms.RsaSha256)
);
string token = new JwtSecurityTokenHandler().WriteToken(jwttok);
}
Token - eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMTIzIiwiZXhwIjoxNjc0ODI5NDQxLCJpc3MiOiJpc3MiLCJhdWQiOiJhdWQifQ.oh5_Yb8F0wpb5NbqhbpqD_sRc1NnEOEXyEbTJ-AE9266s3bXSaezDT0PAZo_VE7MUnonAbmpVezrPcsRIewcfE3hHNKMWPiYhPaseLyXJTZ-0J8JTyAGXi5aSK_5HITQEEDo_DBW2vnxKocrEmNa0JoQBfAo0TfOysqSj6LCYOI

C# Create JWT with Custom Headers and Sign with Private Key

I am trying to figure out how to create a JWT in C# that has custom headers and is signed with a private key. My current attempt is as follows and seems to work except I haven't found a way to include custom headers in it as well.
string publicKey = File.ReadAllText(#"C:\Users\blah\Desktop\Keys\testpublickey.pem");
string privateKey = File.ReadAllText(#"C:\Users\blah\Desktop\Keys\testprivatekey.pem");
var random = new Random();
int num = random.Next(1000000, 500000000);
var exp = DateTime.Now.AddMinutes(10).Ticks;
var claims = new List<Claim>();
claims.Add(new Claim("iss", "919d1ebb-bf3d-4c03-8855-b72b376db9ad"));
claims.Add(new Claim("sub", "919d1ebb-bf3d-4c03-8855-b72b376db9ad"));
claims.Add(new Claim("aud", #"https://api.alt.www.blah.com/auth/oauth/v2/token"));
claims.Add(new Claim("exp", exp.ToString()));
claims.Add(new Claim("jti", num.ToString()));
var token = CreateToken(claims, privateKey);
and CreateToken:
private static string CreateToken(List<Claim> claims, string privateRsaKey)
{
RSAParameters rsaParams;
using (var tr = new StringReader(privateRsaKey))
{
var pemReader = new PemReader(tr);
var privateRsaParams = pemReader.ReadObject() as Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters;
rsaParams = DotNetUtilities.ToRSAParameters(privateRsaParams);
}
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(rsaParams);
Dictionary<string, object> payload = claims.ToDictionary(k => k.Type, v => (object)v.Value);
return Jose.JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256);
}
}
How can I add custom headers to a JWT signed with a private key?
Looks like you can pass extra headers to the method Jose.JWT.Encode as an optional parameter: parameter of type IDictionary<string, object> named: extraHeaders
var extraHeaders = new Dictionary<string, object>
{
////Your custom headers
};
string result = Jose.JWT.Encode(
payload, rsa, Jose.JwsAlgorithm.RS256, extraHeaders: extraHeaders);
Reference: jose-jwt/JWT.cs
You can add custom data via adding claims. They will be added to the token.
claims.Add(new Claim("MyCustomClaimName", "MyCustomClaimValue"));
In this case this data will be moving to the server when you provide the token in your Authorization header for example. So it is not recommended to keep big data there.
If you just need to return some data to the client when he obtains the token - just add extra properties to the response model.

How to generate JWT token signed with RS256 algorithm in C#

I have a RSA Private key with me and I have to generate a JWT token using RS256 algorithm.
I started with the below code which was working for "HmacSha256" algorithm
but when i change it to RS256 it throws errors like " IDX10634: Unable to create the SignatureProvider.Algorithm: 'System.String',SecurityKey:'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey'"
After that I modified the code with RSACryptoServiceProvider() class. But i didnt get a solution.
Please anyone can help with a sample code using RSACryptoServiceProvider class with a private key.
public static string CreateToken()//Dictionary<string, object> payload
{
string key = GetConfiguration["privateKey"].Tostring();
var securityKey =
new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(
Encoding.UTF8.GetBytes(key));
var credentials =
new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, "RS256");
var header = new JwtHeader(credentials);
JwtPayload payload = new JwtPayload();
payload.AddClaim(
new System.Security.Claims.Claim(
"context", "{'user': { 'name': 'username', 'email': 'email' }}",
JsonClaimValueTypes.Json));
payload.AddClaim(new System.Security.Claims.Claim("iss", #"app-key"));
payload.AddClaim(new System.Security.Claims.Claim("aud", "meet.jitsi.com"));
payload.AddClaim(new System.Security.Claims.Claim("sub", "meet.jitsi.com"));
payload.AddClaim(new System.Security.Claims.Claim("room", "TestRoom"));
var secToken = new JwtSecurityToken(header, payload);
var handler = new JwtSecurityTokenHandler();
var tokenString = handler.WriteToken(secToken);
return tokenString;
}

Authentication with JWT Bearer doesn't work the debug says the problem is inside the GetToken() function

I've a code using JWT Bearer to authenticate some tokens as below.
private string GetToken()
{
var issuer = _factory.Configuration.GetValue<string>("JwtSettings:Issuer");
DateTime expiryDate = DateTime.UtcNow.Add(TimeSpan.FromMinutes(1));
var jwtSecurityToken = new JwtSecurityToken(
issuer: issuer,
claims: new List<Claim>()
{
new Claim("a claim", "a claim value")
},
expires: expiryDate,
signingCredentials: new SigningCredentials(
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_factory.Configuration.GetValue<string>
("JwtSettings:Secret"))),
SecurityAlgorithms.RsaSha256Signature
)
);
return new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
}
private HttpClient GetClient()
{
var client = _factory.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false,
});
var token = GetToken();
client.DefaultRequestHeaders.Add(HttpRequestHeader.Authorization.ToString(), $"Bearer {token}");
return client;
}
But it doesn't work and I don't have any idea cuz I'm new to C-sharp and .Net
It gives me the error of couldn't create the signature
Please Help.
In your code, you have specified SecurityAlgorithms.RsaSha256Signature which is asymmetric key algorithm which requires two keys (private and public key)
For code to work, change SecurityAlgorithms.RsaSha256Signature to SecurityAlgorithms.HmacSha256Signature

error while generating jwt SignatureAlgorithm is not supported

i want to generate jwt token which should be verified by google firebase. below is my code to generate jwt token, it works fine until i change algorithm to "RsaSha256Signature" it then gives me error
"Exception: 'System.InvalidOperationException: Crypto algorithm 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256' not supported in this context.
"
If i dont change it and use it as "HmacSha256Signature" it works fine
var plainTextSecurityKey = "-----BEGIN PRIVATE KEY-----;
var signingKey = new InMemorySymmetricSecurityKey(Encoding.UTF8.GetBytes(plainTextSecurityKey));
var signingCredentials = new SigningCredentials(signingKey,
SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256Digest);
var claimsIdentity = new ClaimsIdentity(new List<Claim>()
{
new Claim(ClaimTypes.NameIdentifier, email),
new Claim(ClaimTypes.Role, role),
}, "Custom");
var securityTokenDescriptor = new SecurityTokenDescriptor()
{
AppliesToAddress = "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
TokenIssuerName = "serviceemail",
Subject = claimsIdentity,
SigningCredentials = signingCredentials,
};
var tokenHandler = new JwtSecurityTokenHandler();
var plainToken = tokenHandler.CreateToken(securityTokenDescriptor);
var signedAndEncodedToken = tokenHandler.WriteToken(plainToken);
var tokenValidationParameters = new TokenValidationParameters()
{
ValidAudiences = new string[]
{
"https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
},
ValidIssuers = new string[]
{
"service email",
"service email"
},
IssuerSigningKey = signingKey
};
SecurityToken validatedToken;
tokenHandler.ValidateToken(signedAndEncodedToken,
tokenValidationParameters, out validatedToken);
return validatedToken.ToString();
Your signingKey is not a RSA key, so you can not use RsaSha256Signature. HmacSha256Signature works because you are creating a HMAC symmetric key with a fixed passphrase
var plainTextSecurityKey = "-----BEGIN PRIVATE KEY-----;
var signingKey = new InMemorySymmetricSecurityKey(Encoding.UTF8.GetBytes(plainTextSecurityKey));
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256Digest);
I am not expert in C#, but probably you need something like this
// NOTE: Replace this with your actual RSA public/private keypair!
var provider = new RSACryptoServiceProvider(2048);
var parameters = provider.ExportParameters(true);
// Build the credentials used to sign the JWT
var signingKey = new RsaSecurityKey(parameters);
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.RsaSha256);
you will need a keystore which contains your private and public key. Note that HMAC is a symmetric algorithm and the key to sign and verify is the same, but RSA needs a keypair

Categories