Updating a Pass

Passes allow the user to take real-world actions, and they reflect real-world state. When something in the real world changes, such as a delay to a departure, you can update the pass. Another reason to update a pass is when the pass represents multiple real world actions. For example, a season ticket gains access to every game of the season, and is updated before each game.

Overview of the Communication

Updating a pass is a cooperative effort between the user’s device, Apple’s servers, and your servers. At a high level, it consists of the following steps, shown in Figure 4-1:

  1. A pass that supports updates is installed and the user’s device registers with your server to get updates.

  2. Some change triggers an update and your server sends a push notification.

  3. The user’s device receives the notification and it queries your server to get a list of changes.

  4. The user’s device asks your server for the latest version of each pass that has changed.

Figure 4-1  Interaction between the client and your server

The update process uses the following pieces of information:

Information

Source

Purpose

Web service URL

You define in the pass

Tells Passbook how to contact your web server

Pass type identifier

Serial number

You define both in the pass

Together, uniquely identify the pass

Device library identifier

Device defines

Identifies the device and authorizes requests

Authentication token

You define in the pass

Authorizes requests

Push token

Device defines

Allows the server to send push notifications to the device

Update tag

Your server defines

Describes state

Your server implements a specific web service API which allows this communication to happen. This is different from most uses of push notifications where you provide an app that is free to communicate with your server however you prefer. In this case, you only provide a pass, so Passbook needs a standardized way to communicate with your server.

The web service URL tells Passbook how to contact your server during the update process. It must include the protocol, and it can include an optional port number. Passbook requires an HTTPS connection to your server for all communication. During development, you can use the developer settings to allow plain HTTP connections.

Before responding to a request, you server always checks that the request is authorized. There are two shared secrets that are used to authorize requests. For more information about shared secrets, see Security Overview.

The device library identifier is a Passbook-specific shared secret between the user’s device and your web server. It is not related to the device identifier (UDID). The device identifies itself with a different ID to different servers and it may change its ID at any time. Its purpose is to allow efficient communication between the device and your server, not to let your server keep a list of of what passes are currently installed on a device. The device library identifier uniquely identifies a device and indicates that the entity making the request is authorized to make such a request.

The authentication token is a shared secret between the user’s device and your server. It shows that the request for an update to a pass is actually coming from the user who has the pass, and not from a third party.

Your server needs to remember contain information between requests. There are two entities—devices and passes—and one relationship, registrations. Assuming your server stores data in a traditional relational database, it needs to maintain the following tables:

Devices table

A device is identified by its device library identifier; it also has a push token.

Passes table

A pass is identified by pass type ID and serial number. This table includes a last-update tag (such as a time stamp) for when the pass was last updated, and typically includes whatever data you need to generate the actual pass.

Registrations table

A registration is a relationship between a device and a pass. You need to be able to look up information in both directions: to find the passes that a given device has registered for, and to find the devices that have registered for a given pass. Registration is a many-to-many relationship: a single device can register for updates to multiple passes, and a single pass can be registered by multiple devices.

Devices Register for Updates

After installing a pass, the iOS device registers with your server, asking to receive updates. Your server saves the device’s library ID and its push token.

The device sends the following pieces of information:

To handle the device registration, do the following:

  1. Verify that the authentication token is correct. If it doesn’t match, immediately return the HTTP status 401 Unauthorized and disregard the request.

  2. Store the mapping between the device library identifier and the push token in the devices table.

  3. Store the mapping between the pass (by pass type identifier and serial number) and the device library identifier in the registrations table.

When a device removes a registration, it uses the same endpoint and sends the same data. The difference is that the device sends a DELETE request instead of a POST request, and your server removes (or invalidates) data from its tables instead of adding it. When a device removes a registration, you can immediately remove the entry from the registrations table. When there are no entries for a device in the registrations table, you can remove the entry for the device from the devices table.

Your Server Sends a Push Notification When Something Changes

When a pass needs to be updated, your server sends a push notification to inform devices of the change. Send pushes only to the devices that have registered for updates for that pass, and only when the pass has changed. Don’t send unnecessary pushes.

Your server sends the following pieces of information:

To send the push notification, do the following:

  1. Update the passes table with the new pass information and get the pass type identifier and serial number for the pass that changed.

  2. Consult the registrations table and get the list of devices that registered for updates for that pass.

  3. Consult the devices table and get the push token for each device.

  4. Send a push notification with an empty JSON dictionary as its payload to each push token.

You may wonder why your server doesn’t include more information in the push notification. The reason is twofold: push notifications are not guaranteed to be delivered, and multiple push notifications from the same source are coalesced into a single notification. If more information were included it could be lost. The push notification just indicates that some passes with a given pass type identifier changed, so no information is lost if they are coalesced.

You use the same certificate and private key for sending push notifications as for signing passes. For more information about push notifications, see Local and Push Notification Programming Guide.

Devices Ask for Changed Serial Numbers

When a device gets a push notification, it asks your server for the serial numbers of passes that have changed since a specific point in time.

The device sends the following pieces of information:

Authorization tokens are specified by each pass, so there is no appropriate token in this case. The device identifier is sufficient to prove that the request is valid.

Your server determines which passes have changed since that update tag. It returns the serial numbers of those passes, and a new update tag to store.

To send the list of serial numbers, do the following:

  1. Look at the registrations table and determine which passes the device is registered for.

  2. Look at the passes table and determine which passes have changed since the given tag. Don’t include serial numbers of passes that the device didn’t register for. If no update tag is provided, return all the passes that the device is registered for. For example, this happens the very first time a device communicates with your server.

  3. Compare the update tags for each pass that has changed and determine which one is the latest. This is the update tag that will be returned to the device.

  4. Respond with this list of serial numbers and the latest update tag in a JSON payload—for example:

    {
        "serialNumbers" : ["001", "020", "3019"],
        "lastUpdated" : "1351981923"
    }

Update tags are just an opaque piece of data, as far as Passbook is concerned. Your server must be able to compare any two tags to determine which one comes before the other, and the later tag must also be later than every earlier tag.

The tag system is similar to the standard HTTP If-Modified-Since mechanism, but different in an important way. The standard HTTP mechanism is for a single monolithic resource; if the resource has changed, the entire resource is returned. The tag system used here is for a collection of passes; only the passes that have changed are returned, not the entire collection.

Devices Ask for Latest Version of Passes

The device asks your server for the latest version of each updated pass. To prove that the request is valid, the device includes the pass’s authorization token.

The device sends the following pieces of information:

Your server returns the pass data or the HTTP status 304 Not Modified if the pass hasn’t changed. Support the If-Modified-Since caching mechanism on this endpoint.

Devices Display Change Messages

The device compares the latest version of the pass against the version it had before to determine which fields have changed. If the value of a field has changed and the field specifies a change message, the device shows the message to inform the user about the change.

Change messages interrupt the user and must be read immediately. They are typically appropriate only for information that is time sensitive. For example, if the concert tonight has been delayed by an hour and has moved across town, that’s important to know about that right away. However, updating a season ticket for the next game or changing your customer service phone number would not merit a change message.

Best Practices

As you implement your web service, keep the following best practices in mind: