Creating apple JWT token - c#

Im trying to the Apple App Store Connect API from a .core application.
I currently have
var key = <contents of p8 file>;
var credentials = new SigningCredentials(
new SymmetricSecurityKey(Encoding.ASCII.GetBytes(key)),
SecurityAlgorithms.EcdsaSha256
);
var header = new JwtHeader(credentials);
header.Add("kid", KeyID);
var payload = new JwtPayload
{
{ "aud ", "appstoreconnect-v1"},
{ "exp", exp},
{"iss", issuerID }
};
var secToken = new JwtSecurityToken(header, payload);
var handler = new JwtSecurityTokenHandler();
var tokenString = handler.WriteToken(secToken);
The problem im having is
Unable to create the SignatureProvider.\nAlgorithm: 'System.String', SecurityKey: 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey'\n is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms"

The p8 file tha you downaload from apple is unencrypted. Using openssl commands you can convert it to .pem file unencrypted and encrypted. You can also extract the public key.
Personallly I created the pem file containing the private key and I used this file for creating the client secret and then and therefore the jwt which I verified in https://jwt.io

Ecdsa is an asymmetric algorithm, and you are using a symmetric key within your signing credentials. You should either use an asymmetric key with Ecdsa or use a symmetric algorithm with the SymmetricSecurityKey.

Related

How to use Azure Key Vault Keys to open a SSH channel in .NET?

Here I have used Azure Key Vault to store my keys (Ex: key.pem). What I am doing here is to get a particular key from the vault using ClientSecretCredential and use that key to open an SSH channel from a Web API. Unfortunately, there is a point that I can not figure out. As you can see in the below code snippet, I am passing my key2 to this OpenSSHChannel() method. Then I need to convert that key into a data stream to make a new PrivateKeyFile(). I couldn't find a way to convert this key2 into a data stream. Can anyone have any idea about doing this?
public bool OpenSSHChannel(KeyVaultKey key2, CryptographyClient cryptoClient)
{
// Open SSH connetion using public key authentication
// This key can be obtained from a vault if needed
var pk = new PrivateKeyFile("key2 stream", "passphrase");
var keyFiles = new[] { pk };
// Creating authentication methods for public key authentication
var methods = new List<AuthenticationMethod>();
methods.Add(new PrivateKeyAuthenticationMethod("username", keyFiles));
// Creating the connection using hostname, port, username, and authentication methods
var conn = new ConnectionInfo("server_url", "port", "username", methods.ToArray());

Is there a way in c# where I can sign a Jwt with a key I created on linux using openssl genrsa -out server.key 2048

created the private key with the following command
openssl genrsa -out server.key 2048
In c# console app tried the following:
string keyFile = Path to keyFile
var secret = File.ReadAllText(keyFile);
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(secret));
var creds = new SigningCredentials(key, SecurityAlgorithms.RsaSsaPssSha256);
var token = new JwtSecurityToken(
claims: claims, expires:DateTime.Now.AddDays(1), signingCredentials: creds);
token.Header.Add("kid", "7fab807d-4988-4012-8f10-a77655787450");
var jwt = new JwtSecurityTokenHandler().WriteToken(token);
The WriteToken throws the following error message
System.NotSupportedException
HResult=0x80131515
Message=IDX10634: Unable to create the SignatureProvider.
Algorithm: 'PS256', SecurityKey: '[PII of type 'Microsoft.IdentityModel.Tokens.SymmetricSecurityKey' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'
is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
Source=Microsoft.IdentityModel.Tokens
StackTrace:
at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures, Boolean cacheProvider)
at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm, Boolean cacheProvider)
at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForSigning(SecurityKey key, String algorithm)
at Microsoft.IdentityModel.JsonWebTokens.JwtTokenUtilities.CreateEncodedSignature(String input, SigningCredentials signingCredentials)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(SecurityToken token)
at JwtConsole.Program.CreateSignedJwtToken() in C:\Projects\Jwt\dotnetcore-jwt-manager\JwtConsole\Program.cs:line 244
at JwtConsole.Program.Main(String[] args) in C:\Projects\Jwt\dotnetcore-jwt-manager\JwtConsole\Program.cs:line 34
Please note very in-experienced developer any help greatly appreciated
Thank you
The exception shows you a list of supported algorithms, see link. The chosen algorithm you used is not supported on non-Windows systems.
You should use a different algorithm, preferably one of the ECDSA algorithms.
It is the line with SigningCredentials - replace the SecurityAlgorithms.RsaSsaPssSha256 by a supported algorithm as per link - selected algorithm must be supported in both .NET Framework and .NET Standard 2.0 frameworks. The modified version of your code is below.
string keyFile = Path to keyFile
var secret = File.ReadAllText(keyFile);
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(secret));
var creds = new SigningCredentials(key, SecurityAlgorithms.EcdsaSha256);
var token = new JwtSecurityToken(claims: claims, expires: DateTime.Now.AddDays(1), signingCredentials: creds);
token.Header.Add("kid", "7fab807d-4988-4012-8f10-a77655787450");
var jwt = new JwtSecurityTokenHandler().WriteToken(token);

JWT TOKEN Generate Client_Assertion

I am newbie in JWT access Token generation. I have Public Key, Private key and ClientID. I need to generate Client_Assertion.
client_assertion: JWT (signed by client ID, public certificate and private key using
RS256 as the signature algorithm).
I have found some Node.JS code but I want to do it using .Net Framework (Not .Net Core)
Node.Js code can be seen on this link
I need to do it in C#. From where to start and how to achieve it?
I used the .NET libraries
System.IdentityModel.Tokens.Jwt
Microsoft.IdentityModel.Tokens
Microsoft.IdentityModel.JsonWebTokens
I'm also assuming that, as you said you have a private key, and that you've loaded that into an RSACryptoServiceProvider
Here's my sample code
First create your claims. This is your JWT payload
var claims = new Claim[]
{
new Claim(MicrosoftJwt.JwtRegisteredClaimNames.Sub, "your subject"),
new Claim(MicrosoftJwt.JwtRegisteredClaimNames.Iat, DateTime.Now.ToEpochSeconds().ToString(), ClaimValueTypes.Integer),
new Claim(MicrosoftJwt.JwtRegisteredClaimNames.Exp, DateTime.Now.AddMinutes(60).ToEpochSeconds().ToString(), ClaimValueTypes.Integer),
};
Then you need to configure your signing credentials using your private key.
// Assuming you already have your key loaded into an RSACryptoServiceProvider
var key = new MicrosoftTokens.RsaSecurityKey(csp)
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.RsaSha256);
Now you can create your token
var jwt = new JwtSecurityToken(
issuer : issuer,
audience : audience,
claims : claims,
signingCredentials: signingCredentials
);
// You can add extra items to your Header if necessary
jwt.Header.Add("kid", deviceId);
You can then write your token to a string
var assertion = new JwtSecurityTokenHandler().WriteToken(jwt);
I think the value of assertion is what you're trying to get

Generate access token to authenticate Azure Active directory App

I am using Azure Active Directory App to authenticate my rest endpoint deployed on Azure.
I was using pfx cert type and below code to generate access token so that my endpoint can be accessed through that access token.
var authority = string.Format(authorityUri, credentialConfigOptions.TenantId);
var authContext = new AuthenticationContext(authority);
X509Certificate2 certificate = default;using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser, OpenFlags.ReadOnly))
{
var certificateCollection = store.Certificates.Find(X509FindType.FindBySubjectName, credentialConfigOptions.CertificateName, false);
if (certificateCollection.Count > 0)
{
certificate = certificateCollection[0];
}
};
var clientAssertionCertificate = new ClientAssertionCertificate(credentialConfigOptions.AppId, certificate);
AuthenticationResult token = await authContext.AcquireTokenAsync(appId, clientAssertionCertificate);
return token?.AccessToken;
Now I have to use PEM cert type instead of pfx cert type so I am getting issues while converting PEM format to X509Certificate2.
How can I generate access token with PEM certificate?
If you use Net 5.0, we can directly create X509Certificate2 with a cert and key with method X509Certificate2.CreateFromPemFile(<certpath>,<keypath>). For more details, please refer to here.
If you use other versions, we can create an X509Certificate2 with cert file then import private key with method CopyWithPrivateKey. At last we create Certificate with code
new X509Certificate2(pubKey.Export(X509ContentType.Pfx)). For more details, please refer to here.

How to sign/encrypt JWT in C# with PEM key?

I need to create custom tokens that need to be signed using a key provided by Google. The key is provided as text, like -----BEGIN PRIVATE KEY-----\nMIIE....
I had this working by using BouncyCastle to read the PEM key and get the RSA keys, but now I need this project to run under Linux so I can't use BouncyCastle as it only works under Windows (it makes uses of RSACryptoServiceProvider).
So, is there a way I can achieve the same result but using only .NET Standard code?
I already tried to convert the PEM file to a PFX file, but I don't have any certificates. Tried to get the certificates from here or here didn't work (OpenSSL says that the certificates don't belong to the key provided).
You can convert your PEM file to p12 file and signed your JWT with that p12
var payload = new Dictionary<string, object>()
{
{ "sub", "mr.x#contoso.com" },
{ "exp", 1300819380 }
};
var privateKey=new X509Certificate2("my-key.p12", "password").GetRSAPrivateKey();
string token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256);
Here is the details link https://github.com/dvsekhvalnov/jose-jwt#rs--and-ps--family
The PemUtils library will do exactly what you need, it decodes the PEM and DER data without the use of RSACryptoServiceProvider. It's available as a NuGet package and in case you have any additional needs, I'm the author of that library, so feel free to open an issue on github.
Something like this should work:
using (var stream = File.OpenRead(path))
using (var reader = new PemReader(stream))
{
var rsaParameters = reader.ReadRsaKey();
var key = new RsaSecurityKey(RSA.Create(rsaParameters));
var signingCredentials = new SigningCredentials(key, SecurityAlgorithms.RsaSha256);
}
Just to expand on the solution, this is the full code, working (this is for firebase auth tokens):
var privateKey = new X509Certificate2("cert.p12", "password");
var credentials = new SigningCredentials(new X509SecurityKey(privateKey), SecurityAlgorithms.RsaSha256);
var claims = new List<Claim>(8)
{
new Claim(JwtRegisteredClaimNames.Sub, "firebase-adminsdk-vifbe#your-service.iam.gserviceaccount.com"),
};
var tokenHandler = new JwtSecurityTokenHandler();
return tokenHandler.CreateEncodedJwt(
"firebase-adminsdk-vifbe#your-service.iam.gserviceaccount.com",
"https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
new ClaimsIdentity(claims),
DateTime.UtcNow.AddSeconds(-60),
DateTime.UtcNow.AddSeconds(10 * 60),
DateTime.UtcNow,
_credentials
);

Categories