I have the following two methods that work both on Mac and on PC. When I deploy it to Azure Web App then it throws a Cryptographic Exception. I validated that the key is correct and accurate. I am a little stumped on what else I could to do fix this.
I am running the app in a windows environment with NET Core 8. Hosted as a WebApi in Azure.
The error message specifically is “The system cannot find the file specified.”
public string GenerateAppleSecret(string TeamId, string keyId, string serviceId, string key)
{
var now = DateTimeOffset.Now.AddDays(-1);
ReadOnlySpan<byte> keyAsSpan = Convert.FromBase64String(key);
var prvKey = ECDsa.Create();
prvKey.ImportPkcs8PrivateKey(keyAsSpan, out var read);
return new JwtBuilder()
.WithAlgorithm(new ES256Algorithm(ECDsa.Create(), prvKey))
.AddHeader("kid", keyId)
.ExpirationTime(now.AddDays(4).UtcDateTime)
.IssuedAt(now.UtcDateTime)
.Issuer(TeamId)
.Audience("https://appleid.apple.com")
.Subject(serviceId)
.Encode();
}
private string CreateWeatherKitAuthToken(string teamId, string keyId, string serviceId, string privateKey)
{
if (string.IsNullOrEmpty(privateKey) || privateKey.Length < 5)
{
throw new ArgumentNullException("Invalid Private Key");
}
byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
// Create a cross-platform ECDsa instance and import the private key
ECDsa ecdsa = ECDsa.Create(); // Cross-platform
ecdsa.ImportPkcs8PrivateKey(privateKeyBytes, out _); // Import PKCS8 formatted key
// Define the header
var header = new JwtHeader(new SigningCredentials(
new ECDsaSecurityKey(ecdsa), SecurityAlgorithms.EcdsaSha256)
);
header["kid"] = keyId; // Apple key identifier (kid)
// Define the current time and expiration time for the token (in seconds since epoch)
var currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var expirationTime = currentTime + 3600; // Token expires in 1 hour
// Define the payload
var payload = new JwtPayload
{
{ "iss", teamId }, // Issuer (Apple Team ID)
{ "iat", currentTime }, // Issued at time
{ "exp", expirationTime }, // Expiration time
{ "sub", serviceId } // Subject (Service ID)
};
// Create the JWT token
var jwtToken = new JwtSecurityToken(header, payload);
// Return the token string
var handler = new JwtSecurityTokenHandler();
return handler.WriteToken(jwtToken);
}
Stack Trace:
System.Security.Cryptography.CryptographicException:
at System.Security.Cryptography.CngKey.Import (System.Security.Cryptography, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a)
at System.Security.Cryptography.CngPkcs8.ImportPkcs8 (System.Security.Cryptography, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a)
at System.Security.Cryptography.CngPkcs8.ImportPkcs8PrivateKey (System.Security.Cryptography, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a)
at System.Security.Cryptography.ECDsaCng.ImportPkcs8PrivateKey (System.Security.Cryptography, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a)
at System.Security.Cryptography.PemKeyHelpers.ImportPem (System.Security.Cryptography, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a)
at WeatherKitApi.GetECDsaPrivateKey (CosplayCorps.Business, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null: D:a1sCosplayCorps.BusinessApiAppleWeatherKitApi.cs:80)
Well I know this took me a while to figure out myself. I found the fix was to set the following variable in my app service in azure.
WEBSITE_LOAD_USER_PROFILE = 1