Search code examples
c#.netapple-push-notificationstokenjwt

How to encode JWT for APN tokenization (.NET, C#)


I'm trying to send Push Notifications to APN with tokenization. I tried to use a few libraries like jose-jwt and Microsot Jwt class for creating JWT token, but I can't wrap my head around it.

I get stuck on creating JWT and signing it with private key.

For communicating with certificates, I used PushSharp and it worked just fine. Can anyone help me with a working similar example but with tokens?

edit: following Apple's documentation here: https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1

Sample code: the closest I came to something would look like this, but I don't know how to create CngKey properly

var payload = new Dictionary<string, object>()
            {
                { "iss", issuer },
                { "iat", DateTime.UtcNow }
            };

var headers = new Dictionary<string, object>()
            {
                 { "kid", keyIdentifier}
            };

CngKey key = CngKey.Create(CngAlgorithm.ECDsaP256); //how to create this CngKey

string token = Jose.JWT.Encode(payload, key, JwsAlgorithm.ES256, headers);

Solution

  • Thanks for your answers, had to contact many supports to get this done. Here is what the final result looked like.

    /// <summary>
        /// Method returns ECDSA signed JWT token format, from json header, json payload and privateKey (pure string extracted from *.p8 file - PKCS#8 format)
        /// </summary>
        /// <param name="privateKey">ECDSA256 key</param>
        /// <param name="header">JSON header, i.e. "{\"alg\":\"ES256\" ,\"kid\":\"1234567899"\"}"</param>
        /// <param name="payload">JSON payload, i.e.  {\"iss\":\"MMMMMMMMMM"\",\"iat\":"122222222229"}"</param>
        /// <returns>base64url encoded JWT token</returns>
        public static string SignES256(string privateKey, string header, string payload)
        {
            CngKey key = CngKey.Import(
                Convert.FromBase64String(privateKey), 
                CngKeyBlobFormat.Pkcs8PrivateBlob);
    
            using (ECDsaCng dsa = new ECDsaCng(key))
            {
                dsa.HashAlgorithm = CngAlgorithm.Sha256;
                var unsignedJwtData = 
                    Url.Base64urlEncode(Encoding.UTF8.GetBytes(header)) + "." + Url.Base64urlEncode(Encoding.UTF8.GetBytes(payload));
                var signature = 
                    dsa.SignData(Encoding.UTF8.GetBytes(unsignedJwtData));
                return unsignedJwtData + "." + Url.Base64urlEncode(signature);
            }
        }