0

I am working on posting article using Apple news API.

I created new account and also created new channel.

Below is the code snippet which I am using.

        string channel_id = "{Channel_Id}";
        string api_key_id = "{Key_Id}";
        string api_key_secret = "{Secret}";
        var path = "https://news-api.apple.com/channels/" + channel_id + "/articles";

        var httpWebRequest = (HttpWebRequest)WebRequest.Create(path);
        httpWebRequest.ContentType = "multipart/form-data";
        httpWebRequest.Method = "POST";
        httpWebRequest.Accept = "application/json";
        httpWebRequest.Host = "news-api.apple.com";
        httpWebRequest.UseDefaultCredentials = true;
        httpWebRequest.PreAuthenticate = true;

        httpWebRequest.ProtocolVersion = HttpVersion.Version11;
        httpWebRequest.KeepAlive = true;
        string appleDate = String.Format("{0}Z", DateTime.UtcNow.ToString("s"));
        string credentials = String.Format("{0}:{1}", "Content-Disposition", "form-data; ");
        credentials += String.Format("{0}:{1}", "filename", "article.json; ");
        credentials += String.Format("{0}:{1}", "name", "article.json; ");

        credentials += String.Format("{0}","HHMAC; ");
        credentials += String.Format("{0}={1}", "key", api_key_id + "; ");

        string decodedSecret = base64Decode(api_key_secret);
        string canonical_request = path + "POST" + appleDate ;
        string hash = Class1.HmacSha256Digest(canonical_request, decodedSecret);
        string Encodedhash = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(hash));

        credentials += String.Format("{0}={1}", "signature", Encodedhash + "; ");
        credentials += String.Format("{0}={1}", "date", appleDate + "; ");


        httpWebRequest.Headers.Add("Authorization", credentials);

        using (StreamReader r = new StreamReader(Directory.GetCurrentDirectory() + ("/article.json")))
        {
            string json = r.ReadToEnd();
            dynamic jsonObj = JsonConvert.DeserializeObject(json);

            ASCIIEncoding encoding = new ASCIIEncoding();
            Byte[] bytes = encoding.GetBytes(json);
            Stream newStream = httpWebRequest.GetRequestStream();
            newStream.Write(bytes, 0, bytes.Length);
            newStream.Close();
        }
        var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
        using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
        {
            var result = streamReader.ReadToEnd();
        }

Here is base64Decode function

public static string base64Decode(string data)
        {
            var base64EncodedBytes = System.Convert.FromBase64String(data);
            return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
        }

Here is class to convert Sha256Digest

public static class Class1
    {
        public static string HmacSha256Digest(this string message, string secret)
        {
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] keyBytes = encoding.GetBytes(secret);
            byte[] messageBytes = encoding.GetBytes(message);
            System.Security.Cryptography.HMACSHA256 cryptographer = new System.Security.Cryptography.HMACSHA256(keyBytes);

            byte[] bytes = cryptographer.ComputeHash(messageBytes);

            return BitConverter.ToString(bytes).Replace("-", "").ToLower();
        }
    }

Whenever I am trying to post the API I am getting below error message:

"'The remote server returned an error: (401) Unauthorized".

When I am trying to post the API request using Postman then I am getting below error message:

{
    "errors": [
        {
            "code": "WRONG_SIGNATURE"
        }
    ]
}

Is there anything incorrect to generate Signature ?

I researched few articles but unable to find any solution.

Please guide me to find out the solution on this.

Advay Pandya
  • 101
  • 1
  • 9
  • I have tried the same thing for creating a report and I have followed the following link for the python code. https://developer.apple.com/documentation/apple_news/apple_news_api/about_the_news_security_model But I am getting the exact same error. I would love to know the solution as well. – Rafiul Sabbir Aug 08 '18 at 10:15

1 Answers1

1

I don't have time to go through the entirety of your code and suggest you start with a simpler Channel Data request before attempting to POST json, but a potential couple of bits I noticed:

  1. You use ASCII encoding where you should be using UTF8 throughout.
  2. You strip hyphens from the Base64 but Apple only strips returns and whitespace
  3. The cannonical request should be written: "POST[url][date][contentType]" where url = "https://news-api.apple.com/channels/[channelID]/articles", date is in the format "yyyy-MM-dd'T'HH:mm:ss'Z'" and content-type = "multipart/form-data; boundary=[boundary]" where boundary is any string used to divide the content.

See also my tips on using Python, most importantly ensure you are using the path to a folder containing article.json (not the path to a file). And finally here is my own translation of the Python into Swift.

sketchyTech
  • 5,746
  • 1
  • 33
  • 56