Article

Signing the HTTP Request

Sign the canonical request and send the custom authorization header to the Apple News API.

Overview

When communicating using HTTP protocol, the server validates the identity of the client and provides authorization for specific actions. By signing the HTTP request, the Apple News API authenticates the client and authorizes your news channel. See About the News Security Model.

On this page, you'll learn how to:

  • Create a canonical request.

  • Sign the canonical request.

  • Create a custom authorization header.

  • Send the header and the request to the Apple News API.

Copy This Code

Open any text editor to copy this code. Save the file as read_channel.py.

import base64
import hmac
import requests
import sys
from datetime import datetime
import hashlib 

class PublisherAPI:
    channel_id = ""
    current_action = ""
    key_id = ""
    key_secret = ""
    url = ""

    def send_request(self, method, url, content_type=None):
        date = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
        canonical_request = method + url + date
        canonical_request = canonical_request.encode()
        signature = self.create_signature(canonical_request)
        authorization = "HHMAC; key=%s; signature=%s; date=%s" % (
            self.key_id, signature, date)
        headers = {"Authorization": authorization}
        return requests.request(method, url, headers=headers)

    def create_signature(self, canonical_request):
        key_bytes = base64.b64decode(self.key_secret)
        message = canonical_request
        secret = self.key_secret.encode("utf-8")

        signature = base64.b64encode(
            hmac.new(key_bytes, message,digestmod=hashlib.sha256).digest()).decode("utf-8")
        return signature

    def read_channel(self):
        method = "GET"
        url = self.url + "%s" % self.channel_id
        return self.send_request(method, url)

    def main(self):
        if self.current_action == "readChannel":
            response = self.read_channel()
        else:
            response = {
                "status_code": 400,
                "response": "{\"errors\":[{\"code\":\"UNKNOWN_COMMAND\"}]}"
            }
        return response

if __name__ == '__main__':
    if not len(sys.argv) > 4:
        print ('no or missing arguments')
        exit()

    publisherAPI = PublisherAPI()
    publisherAPI.url = sys.argv[1] + "/channels/"
    publisherAPI.channel_id = sys.argv[2]
    publisherAPI.key_id = sys.argv[3]
    publisherAPI.key_secret = sys.argv[4]
    publisherAPI.current_action = "readChannel"

    response = publisherAPI.main()

    print(response.status_code)
    print(response.text)

Run the Script

Start the command prompt and change to the directory containing read_channel.py. Run this script to make a properly authenticated Read Channel Information request to the Apple News API. This script takes four arguments: API URL (https://news-api.apple.com) Channel ID, Key ID, and the Secret.

python read_channel.py https://news-api.apple.com channel_id key_id key_secret

Result

A successful response is returned. The response includes information about the channel, as shown here. See Channel and ChannelLinks.

{
    "data": {
        "createdAt": "2016-06-13T00:25:43Z",
        "modifiedAt": "2016-06-13T23:30:05Z",
        "id": "42424242-4242-4242-4242-424242424242",
        "type": "channel",
        "shareUrl": "https://apple.news/Taaaaaaaaaaaaaaaaaaaaaa",
        "links": {
            "defaultSection": "https://news-api.apple.com/sections/42424242-4242-4242-4242-424242424242",
            "self": "https://news-api.apple.com/channels/42424242-4242-4242-4242-424242424242"
        },
        "name": "My Channel",
        "website": "http://mychannel.com"
    }
}

How it Works

The canonical request combines the method, the URL, and the current date, as shown here:

date = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
canonical_request = method + url + date

The date is formatted as shown here:

{Year with century as a decimal number}-{Month as a zero-padded decimal number}-{Day of the month as a zero-padded decimal number}T{Hour (24-hour clock) as a zero-padded decimal number}:{Minute as a zero-padded decimal number}:{Second as a zero-padded decimal number}Z

The date format looks like this:

2018-08-10T23:55:11Z

The canonical request looks like this:

GEThttps://news-api.apple.com/channels/{channel-id}2018-08-10T23:57:00Z

A custom authorization header is created by combining the Key ID, the signed canonical request, and the formatted current date, as shown here:

{'HHMAC; key={Key ID}; signature={Signed Canonical Request}; date={Formatted Current Date'}

The header looks like this:

{'Authorization': 'HHMAC; key={Key ID}; signature=1rBvQKZeQ6M3/dVMtv95Dc51V+QViaqUB0bF6exzYtw

Finally, the header and the request are sent to the Apple News API. The request looks like this:

return requests.request(method, url, headers=headers)

See Also

Apple News API Python Tutorial

Making an HTTP Request to the Apple News API

Create the URL, set the method, and send the request.

Publishing an Article

Build a URL and article body for the publish-article request.