Services • iOS, OS X • 46:46
The App Store, Mac App Store and In-App Purchases support a wide range of business models to generate revenue from your digital products. Whether you offer a paid app or a free app with In-App Purchases, you need to protect yourself by verifying receipts for those purchases. Get all the details on how receipt validation is changing in iOS and hear best practices for combating fraud.
Speaker: James Wilson
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
Thank you. Good afternoon. Hi, my name is James Wilson and I'm the Engineering Manager for the App Store in OS X. It's great to see so many of you here that are interested in getting paid. In this session, we're going to be talking all about how to protect your digital sales using receipts.
There's a huge amount of revenue that is being generated through In-App Purchases. In fact, so much so that just a few days ago, 96% of the top 25, top grossing apps for the iPhone were free apps, and they were using In-App Purchases alone to generate enough revenue to make them top grossing apps.
Now that's huge groundswell of momentum and popularity for the free with In-App Purchase, or Freemium model, combined with the continued popularity of paid, with or without In-App Purchases, means that there is a lot of importance for you, the developer, to protect those digital sales and to secure your revenue, because if your app is easy to be pirated, cracked, stolen, and shared around, there's no money in that for you.
So in this session, I'm going to introduce you to the concept of the receipt, and the receipt is the foundation upon which you can build your business model enforcement logic directly into your app, as well as into your servers that are providing the content out to your users.
We are going to introduce you to the receipt, how it works, what's in it, when you get them, then we're going to actually look down into the code level on both iOS and OS X as to how you actually go about validating these receipts and getting the purchase information out of them. We'll do some -- we'll do a look into some platform specific concerns about how to implement receipt validation, and then finally, we'll look at the test environment that you can use to make sure that you ship code that's bug free.
So the receipt. It's exactly like the receipt that you get when you're shopping at a physical store. Just like when you're at a department store, you're at the checkout, you exchange your cash for goods that you're buying. Not only do you get those goods that you've bought, but you get a receipt, as well.
That little piece of paper that verifies exactly what you paid for in this store, and it's that little piece of paper that that physical store that you're in can use as the basis of their security model to make sure that their goods don't go walking out the door with a five finger discount.
Likewise in the App Store, the receipt is that digital equivalent. The receipt is your trusted and verifiable record of purchase. It's issued by the App Store and contains signatures and certificates and security measures that make sure that it came from Apple and is unaltered, and that it ties directly to your app on a specific device.
Now if you're a paid app, this is really important obviously for implementing copy protection, and if you're a free app with In-App Purchases or a paid app using In-App Purchases, the receipt is what you use to know exactly what the customer paid for so that you can unlock features and content.
So understanding the receipt and knowing how it works, knowing how to validate it and get the purchase information out of it, is how you enable your business model in your apps directly, as well as in servers that you have issuing content and assets out to customers. Using the receipt is how you know exactly what the user has paid for.
Now if you haven't looked into how to do receipt validation before, or maybe you've looked at it but haven't yet implemented it, this session is going to be great for you because we're going to take you through a step-by-step look at exactly how you validate the receipt and get the purchase information out of it.
For my iOS developers who are already doing receipt checking in iOS 6 and earlier, using the methods we had available then, I've got some new APIs for you and also, a change in the receipt format that is going to give you even greater flexibility and a whole lot more power to not only validate purchases on your servers, but to validate the receipts on the device itself.
But now for my OS X developers, I think you'll particularly like this because the receipt format that you know and understand and that we've been using since we debuted on the -- since we debuted the Mac App Store, is now the exact same receipt format that we are using across iOS 7 and OS X.
This gives you a unified, trusted, validated, proof of purchase or purchase record across both platforms to know exactly what the customer has paid for. Not only do we now have the unified receipt model across iOS and OS X, but the receipt now includes two new pieces of information.
If you've opted into the Volume Purchase Program to license your app out to business and education, there's extra information in the receipt now that tells you whether that receipt is allocated to a user or whether it has been revoked from them, but I think the most exciting thing that's in the receipt this year, especially for you guys, if you have a paid app in the store, is that we've included information in the receipt that's going to let you do a transition from being a paid app to being a free app with In-App Purchases without leaving behind all the customers that have already paid for your app.
[Applause] Right. Which is important, right? Because you can see that there's this huge groundswell of momentum towards the Freemium model but you don't want to leave behind people who've already paid for your app. So the receipts, this foundation, this core upon which you build enforcement of your business model, directly into your apps.
When it comes to the finding exactly how you're going to enforce your business model, that's going to be something that's unique to your app. Everyone's app is different, right? You have a different value proposition, different price point, different target market, different customers, different expectations, everything. Everyone's app is unique, and the products that you're selling, be it the app itself or through In-App Purchases, they have different values. That uniqueness needs to translate into how you decide to enforce your business model and protect your revenue, your app and servers. So it's like a recipe. Together we're going to bake a cake that's going to make sure you get paid.
Apple has got some ingredients that we're going to bring to the table, but there's some that you'll need to bring to the table as well, but the great thing is that I'm going to show you that all of these things that you need to work out and work out how you want to approach them, they're all based on standards that are open and very well used and there's lots of examples, third-party libraries ready to go, plus you have the flexibility to write the code yourself if you choose. Because Apple gives you the receipt format specification itself and the receipt is based on open standards, everything in the receipt is based on an open standard that's very well documented, used industry wide, and is used in many, many different ways.
We give you the receipt itself, and we give you instructions on how to do both on-device validation for the receipt, as well as validating the receipt server-to-server, if you have servers out there that need to validate these before issuing content. But it's up to you guys, you the developers, to make some decisions along the way about exactly what security level is important for you, and I'm going to call those out to you as we go through these slides.
[ Pause ]
So let's start with an understanding of the receipts. So a receipt, again, just like the physical receipt you get in the store, is issued when a transaction takes place between the App Store and your app. So when your app is purchased or updated, a receipt is issued. If someone performs an In-App Purchase or there are stores that have completed transactions, a receipt is issued.
If you've opted into the Great Volume Purchase Program, when the license is allocated or when it's revoked from that user, a receipt's issued. There's also some on-demand APIs that you can use within your app to get in your receipt if it appears that the one there is missing or doesn't appear to be valid for your app on this device.
So what's in these things? So within the receipt itself, first and foremost there's certificates and signatures, and this allows you to make sure it came from Apple and hasn't been tampered with. There's information that ties the receipt directly to your app on a specific device, so it hasn't been copied around between people, it hasn't been copied from one app to another app, it's legitimately for your app on a single device, and then once you know that it's trusted and it's for your app on this device, you can get a whole lot of purchase information out of that receipt.
You've got purchase information about the app itself, plus the In-App Purchases that the user has made, and there's also information there, I mentioned as well, about the Volume Purchase Program, but I think the most exciting thing that we've added to the receipt this year is the initial purchase date and initial purchase version.
So for everyone that's got a paid app on the store today, and you want to make the transition to being a free app with In-App Purchases, previously that used to be quite a challenge for you, because if you simply switch to being a free app with In-App Purchases, your customers would have to go and buy all those In-App Purchases again, but they've already paid for it, and they're not going to like that.
So now in the receipt itself we have the date, when the user first purchased your app, and the version that it was at that time. So you can use this to make a really informed, intelligent decision about what features and content to grant this user into, so if your app looks at the receipt and inspects it and sees this user bought my app before I made the switch to being free with In-App Purchases, grant them into what they've paid for, but if they purchased your app after you've made the transition to being free with In-App Purchases, you know then not too unlock features and content until they make the purchase and you verify that transaction with the receipt itself. So understanding the receipt not only allows you to protect your revenue and your digital sales, but it's also really powerful for you to adjust your business model to suit changes in the market.
Now speaking of transitions, I want to talk for a second to iOS developers who are already doing receipt checking for In-App Purchases on iOS 6. For OS X developers and anyone else that's not doing this receipt checking, if you've got a moment, hit the documentation slide and have a look for the receipt validation guide, because that's what we're going to be going through very shortly.
But for iOS developers who are already doing receipt checking on iOS 6 and earlier -- don't panic. Your app as it is today in the store doing receipt checking on iOS 6 will continue to work in iOS 7. iOS 7 is binary compatible with the receipt checking methods that we shipped in iOS 6, but those APIs are deprecated.
So you need to make the jump to using the iOS 7 way of doing receipt validation, not just because the receipts are deprecated, but because now you can actually do the receipt validation entirely on the device itself. You no longer need to have a server just there for the purpose of doing receipt validation for you.
[ Pause ]
[ Applause ]
Thank you. But what if you want to have one binary on the store that works in iOS 6 and 7, and takes advantage of the best possible receipt checking methods on both of those platforms? Well, you can, and the way you do this is you just Weak Link to the iOS 7 APIs, and if I lose any of you when I said Weak Linking, it's not nearly as complicated as it can sound. Weak Linking simply means check that the API exists before you go and use it. This prevents your app crashing on a platform where the method or the API doesn't exist; it prevents you from crashing with an unrecognized selector or an unresolved symbol.
So Weak Linking, first of all, you run -- you call the Response to Selector to see whether a given object will actually respond to this method. In this case I'm calling App Store Receipt URL to ask for the location of the unified receipt. If that returns true, then I know that this device I'm running on supports the new way of doing receipt checking with a unified receipt and I can proceed down that course, but when I go to call App Store Receipt URL, I use Perform Selector.
That way I avoid crashing with unrecognized selector. So this is what we mean when we say Weak Linking, but do this instead of checking the system version. This uses the runtime to know exactly what methods are available and allows you to take advantage of those when they're available. Much better, much more future proof than checking the system version or making arbitrary decisions based on the running version of the OS.
So now we're going to delve into some code, but I'll say this from the outset. Some of the code and the concepts that we're going to look at now might be a bit outside your comfort zone, especially if you're used to dealing with Objective-C and all of its wonderful, developer friendly APIs and App Kit new iKit, because to validate receipts, we're going to delve into some cryptography, and also some doddering coding standards, but let's take it down to the simple fact; the receipt is just a file.
It's stored in the app bundle, we give you an API to get a hold of it, and it's a single file that has purchased data and signatures to check authenticity. Don't let the acronyms and cryptic function names we are about to look at fool you. In essence, all we're doing here is opening a file, reading it into memory, running some functions over it, calling some methods, checking the return codes and comparing values, and that's within the reach of any developer. In fact, what I'm going to take you through is a three-step process, and this is a three-step process to guarantee your revenue, protect the value of your products, and make sure that you retain your customer loyalty. Three steps. This is the WWDC session that pays for itself.
So step one. You verify the signature of the receipt. This makes sure it came from Apple and it hasn't been altered. No one's tried to add in some extra In-App Purchases that they haven't really made. No one's tried to doctor up a receipt that's not really for an app that they purchased. That's step one. Step two is we confirm that the receipt is for your app on a given device. This makes sure that no one's just copied the receipt between devices or has tried to copy a receipt from one app to another in hope that it works.
The third step is that now we trust the receipt and we know it's for our app on this device, we get the purchase information up out of it and we make decisions about what to give the customer, because they're, at that point, we know exactly what they've paid for. So let's start with step one, verifying the signature.
Verifying the signature in simple terms is, step one, locate the file, and we do that with this API here on NSBundle we call App Store Receipt URL and this works in iOS 7 and OS X. That gives us a URL to find the actual receipt file, and the great thing is is that the OS manages this for us on both iOS and OS X. It keeps the receipt file there for you. You don't have to process the receipt yourself anymore like you used to. We read the contents into memory and we verify the signature.
Here's your first decision point as a developer. You need to decide what you're going to use to verify that signature, and the great thing is that if you're at all familiar with cryptography standards and secure exchange of data, the receipt itself is what we refer to as a PKCS #7 container. Like I said, don't let the acronyms fool you. This is doable. It's a PKCS #7 container, which is an open, industry standard, cryptographic scheme for embedding a payload of data around certificates and signature to guarantee its origin and authenticity.
The good thing is that because that is such an open and very widely used standard, you have a huge amount of options available to you in terms of deciding how you verify this signature. At one end of the extreme, there are third party libraries that you can get off the shelf that are freely available, put them in your project, use them, and they will do the certificate validation for you.
But at the other end of the extreme, if the security that you want for protecting your sales requires you to own this code end-to-end yourself, then because this is an open standard with specifications available, you can do that. You could write your own code to validate this signature if you wanted, and of course there's the great middle ground of there being lots of examples and sample code out there that you can use and leverage to suit your needs.
The example that we provide in the documentation is to use Open SSL to verify the signature. Open SSL is an extremely well used cryptographic library. It's used on many different operating systems for millions and millions of secure operations, and if we used Open SSL to do the verification for us, here's what it would look like.
We assume, first of all, you've loaded up the receipt into memory and a copy of Apple's Root CA Certificate and you can find that certificate online, and we've stored these in two root variables here, B receipt and BX 509, X 509 being the standard that's used to encode Apple's Root CA Certificate. The first thing we do is we want to take those raw bytes from the receipt and convert them into a PKCS #7 data structure so that Open SSL can work with it at a code level.
Next, to verify the signature, we need to tell Open SSL who we are actually expecting to have signed this certificate, who we're expecting it to have come from. So we load up Apple's Root CA and we create a certificate store. We add that certificate in. With our certificate in hand, and our PKCS #7 data structure ready to go, we simply call PKCS #7 Verify. We check the result.
If result's one, the receipt is valid. That's it. And the great thing is that calling PKCS #7 Verify also actually returns back to you that payload of data that's inside the receipt, the actual purchase information that you want to get a hold of to make decisions about what the users purchased.
So right now, we have a receipt that we know came from Apple for an App Store Purchased app, and we know that it's authentic and hasn't been altered. The next thing we need to do is confirm that it is definitely for our app on this device, and to do that we need to actually inspect these raw bytes of data that we took out from the receipt payload itself.
Now that payload of data, we arrange that in a series of attributes that have a Type and a value. We encode these using a standard called ASN.1. ASN.1 again, I know I sound like I'm repeating myself, but again, is a very widely used open and industry-standard, and it's been round for a long, long time, and that's great because that means that there is a wealth of options available for you for how to read that doddering ASN.1 format.
ASN.1 is the abstract syntax notation. It allows us to write in a textual form like this, a description of how we've laid out the actual bytes contained within the receipt, and what this body of text here tells you is that we have arranged those bytes in the receipt as a sequence of attributes.
In a cocoa sense, it would be kind of like having NSArray full of NSObject sub-classes that we've created that have a type property and a value property. That's essentially what we've defined here with this block of ASN.1, and here's your second decision point as a developer. You need to decide what you're going to use to read that ASN.1 encoded data at the code level.
Now documentation that we've had on the developer site since we debuted the Mac App Store has included an example of using a third-party tool called ASN1c. ASN1c is a third-party tool that allows you to essentially take this textual representation of the data and ASN1c creates for you a bunch of boilerplate code that you can copy straight into your project, build it, and it gives you some functions and data structures that you can use to actually work with these attributes that are in the receipt, the actual purchase information you want.
Another option you could use is Open SSL. It can also open read ASN.1 coded data, and again, it's this wide range of options you've got available, from the extreme of taking a library that already exist to the extreme of writing it yourself, and all the middle ground of finding examples and making informed decisions about exactly how you want to do this yourself.
Just remember it's a risk and reward calculation for you. At this end of the spectrum of taking a third-party library and using it, the reward is obviously rapid development time. You can get this up and running really quickly. The risk is when you take someone else's library and use it, you get their bugs, as well.
The middle ground of finding some examples to guide you, of finding some samples that are out there and using some of that code, may be a good middle ground if that's the level of security you want, and at the other end of the extreme, if your products are so high value that you absolutely have to own this yourself end-to-end, the ASN.1 specifications are available for you, you could write your own parser if you want.
Here's how it would look if we used ASN1c. The first one I'm trying to call there, BRD Coder, takes in my receipt bytes itself, the actual payload of data we got, and it gives me a data structure back that I can use to set up a full loop and iterate over each of these attributes in the receipt.
Whether you use ASN1c, Open SSL, or roll your own, you're generally going to end up in some sort of full loop to iterate over these attributes in the receipt, just like with an NSArray, you'd use 4 ID Object NArray and have that loop ready to iterate over these things.
So getting back to validating that the receipts for our app on this device. There's four attributes that we are particularly interested in here. Let's go with the first part of this equation, that the receipt is for your app on this device. To know it's for your app, you want to look at attributes Type 2 and 3, so in that full loop, when I'm looping over the attributes, checking the actual attribute type, we'd look for Type 2 and we'd know that that's the bundle identifier.
We'd look for Type 3 and know that it's the bundle version. We can take these and compare these to the running app. If they match, the receipt's for your app and this version of your app. You might not want to check it against the info paylist, though. That's all too easy for someone to edit the info paylist and have it match the receipt that they want you to validate, so you might want to hardcode these values into your app.
The second part of the equation is we now know it's for your app, but is it for your app on this device only? Now the way we do that is we need three pieces of information. Firstly, we need the unique identifier for the device that it's running on. If you're on an iOS device, that's your identifier for vendor that you find from UI device.
If you're on OS X, that's the machine's globally unique identifier, or GUID, and there's a sample code available on the documentation site that shows you exactly how to derive that GUID. So that's the first bit of information. A sequence of bytes that uniquely identifies this device that you're running on.
The second piece of information we need is your bundle identifier, because it's for your app. So we take these bytes and memory that uniquely identified the device, concatenate on the string of bytes that represent your app, the bundle identifier. Then we take these attribute Type 4, the opaque value. It's just a series of bytes.
Append those series of bytes onto this long string of bytes that you're forming in memory, device identifier, bundle identifier, opaque value. When you've got this long string of bytes, you create an SHA-1 hash of those, which gives you a 20 byte hash of this long string of bytes. Creating a hash is easy. You can use common crypto; you could use Open SSL, whatever you want to do.
If you compare that hash to the value here in attribute Type 5 and it matches, you've successfully confirmed it's for your app on this device. Now how does that work? How does that convoluted set of steps there actually confirm that it's for your app on this device? Well, the reason is -- well the way it works, is that at the time of the transaction, the result in this receipt being issued by the store, we did the exact same calculation.
When an In-App Purchase was made, for example, we took the identifier of the device making the purchase, the bundle identifier of the app making the purchase, [inaudible] opaque value, hashed it, put it in the receipt as attribute Type 5, and then signed it and shipped the receipt to you. So if your calculation of runtime matches our calculation of the time of purchase, it's for your app on this device.
But now we can get into the really interesting end of this which is what did they actually pay for? When you're iterating over those attributes within the receipt and you've got those Type 2, three, four, and five attributes out, if you're offering In-App Purchases, you're also going to see one or more Type 17 attributes.
Now the Type 17 attribute, the value of that is actually a nested set of attributes that tells you about an In-App Purchase that has been made, so which of these Type 17 attributes contains an attribute -- a nested attribute in there, these Type 17 01, 02, 03, 04, that tell you the quantity and the product identifier of what was purchased? And again we give you the ASN.1 textual representation of how we've encoded this data so you've got the same options available. You could use Open SSL to read this, ASN.1 to generate code to read it, write your own, whatever suits the value of your products and the level of security you want.
So let's recap some of the key technologies we've just talked about. Firstly, it's a PKCS #7 container. I guarantee if you Google for that, you'll be amazed at the wealth of information that's out there to find out how to read those, verify them, and validate the signature. This is not something unique to the App Store receipt. It's done in millions of different ways.
You could get Open SSL to do it if you wanted to, you could roll your own, or use any other option that's available to you. It's up to you. You decide the complexity. And the actual data itself is encoded using ASN.1, and again the same applies. Lots of options available to decide how to read that data.
Now those of you that are really in the know might be thinking to yourself this guy doesn't know what he's talking about. Open SSL doesn't exist on iOS, and if I link to it on OS X, I get a billion and one compile errors. You got me, but there's a good reason for that, because if you're using a dynamically linked library on the device that you're running on to verify your signature and get your purchase information, imagine how easy it would be for someone with less honorable intents to swap that library out with one that said everything is good.
So make sure all the code that you are using to validate your receipts and get this purchase information is linked statically into your binary you're submitting. That way you are certain that the code that's going to confirm this, protect your revenues, protect your digital sales, is the code you intended and hasn't been messed with.
Now everything we talked about there is about validating the receipt on the device itself, which is great now that you can do that in iOS 7 with the unified receipt format. A lot of you are going to have servers out there that issue these -- these, you know, Game Levels, assets, contents, periodicals, whatever it might be, and you don't want those servers to just be handing those assets out to anyone that asks for them right? Your servers need to be able to validate that these purchases are real and authentic and that the user really has paid for it to make sure you get paid for it.
So Apple provides you with a server-to-server online validation service. Here's how this works. Your app on the device gets the receipt. Your app sends the receipt up to Apple -- sorry, up to, your app sends the receipt up to your server, and it would usually do that as part of the request for a piece of content or an asset, so for example, if they've just bought Game Level 5, your app would just make a request to your servers and say "Hey, give me Game Level 5," and it would include the receipt in that request.
Then your server can take that receipt and send it to Apple's validation service. We crack open the receipt, confirm that the receipt is authentic and unaltered, and we return back to you a JSON code, coded block of data, that describes the purchase that was made, and because that's returned in JSON, it's really easy for your service to pause it, no matter what platform you're running on, but this is only to be used for your server to talk to our server to validate the receipt. It's not to be used for your app to talk directly to the validation service. So if you're doing that today, you really need to stop, because you can now validate the receipt on the device in itself.
And another thing that's important to note about the online validation service is it can only do two of those three steps that we just looked at. It can validate that the receipt is authentic and unaltered, and it can return back to you the purchase information, but it doesn't confirm that the receipt was intended for your app on a given device. You still want to do that at the device level.
So now let's look at some platform specific implementation details about how we validate the receipts. Let's start with iOS 7. On iOS, when your app 4 first launches, you want to validate the receipt as soon as possible, and I mean way before you get to application did finish launching, in fact way before you get anywhere near UI application or the main run loop. Do this in the main function. Do this before anything else. Check that the receipt exists and validate it. Now if it doesn't exist or it appears to be invalid on that device, and that can happen, refresh it using Store Kit.
Store Kit now has the SK Receipt Refresh Request, which you can use to get yourself a new receipt to do your receipt validation, but you don't always need the latest and most up-to-date receipt. Use what's there first, because as soon as you start one of these SK Receipt Refresh Requests, the first thing the user is going to see is an authentication prompt to sign into the App Store, and it's not acceptable to do that on every launch, so only do it if the receipt is missing or appears to be invalid, and this will require a network connection.
So just keep that in mind when you're working out how stringent to be, and how secure your business model enforcement is, that if the device doesn't have a network connection, it won't be able to get a receipt. Now OS X is a little different. On OS X, for an App Store purchased app, the receipt will always be there.
The only time you wouldn't see a receipt on OS X is when you're developing the app and you run it and you need to get a receipt to test with, and the receipt should always be there, but if it appears to be invalid, as in it's perhaps not for this device, which could happen if apps are migrated from one machine to another, then your app exists with a Code 173.
This special Exit Code tells OS X in the App Store that you believe your receipt's invalid and you want a new one. Again, the first thing that your user is going to see here is a prompt to sign into the App Store, even if they're already signed in, so definitely don't do this on every launch, only do it if the receipt appears to be invalid, and again, network connection will be required.
Now for everyone doing In-App Purchases, whether it's on iOS or OS X, because now OS X supports subscription In-App Purchases as well, there are some differences in the type of In-App Purchases that are offered insofar as how they're represented in the receipt, especially over the lifecycle of the receipt.
Consumables and non-renewing subscriptions. They're a one-off purchase, right? So if you've got a racing car game, you might offer the user to purchase 500 gallons of gas through an In-App Purchase. You would expect that that 500 gallons of gas is used once, only on that device, and once it's done, it's gone.
You can't restore transactions and get 500 gallons of gas back each time, nor would you expect to have 500 gallons of gas on your iPad and then magically another 500 on your iPhone and whatever other devices you might have. So these are one-time purchases. Once they're used, they go on.
Likewise in the receipt, you'll only ever see a record of a consumable or a non-renewing subscription once, and you'll only see it in the receipt that's issued at the time of that transaction, at the time they make that purchase. It won't be present in receipts that are issued in the future, so if the user then makes another purchase, that consumable that they bought before won't be in there. If they restore transactions, that consumable, it won't be in there, so you get one chance to see it, one chance to validate it, and then set whatever state you need.
Now non-consumables and auto-renewable subscriptions are the exact opposite because these are permanent purchases that are designed to persist across devices, so if I bought Game Level 5, but I then get a new iPhone, and I restore my transactions or I restore transactions on another device, I expect that Game Level 5 is there ready for me to play.
Likewise, with auto-renewable subscriptions. If I subscribe on one device, I want to be able to use that subscription on others. So these non-consumables and auto-renewable subscriptions are always in the receipt, and they can be restored using the Store Kit API to restore completed transactions. So keep that in mind when you're deciding how you persist state based on In-App Purchases that have been made. Consumables, non-renewing subscriptions, only in there once. One shot. Non-consumables and auto-renewable subscriptions, always in the receipt.
But what happens if, even after you've requested a new receipt, it still appears to be invalid? Your app launched, you did the receipt checking, it didn't look right, you requested a new one, checked it again, it still didn't look right. This doesn't mean necessarily that something evil is happening.
There might be reasons why this is happening, and you should make sure that whatever user experience you implement here, particularly on iOS, is tasteful and suits the value of your products, and I say iOS in particular because on iOS, apps can't quit. There's no way to quit your app. It keeps running.
So if the receipt appears to be invalid and you've determined that this user is not eligible to use your app, or the In-App Purchases that they think they have based on the receipt, then it's up to you to design that user experience. You might decide to make the app read only, block parts of the UI, whatever you want to do, but please make sure it's tasteful and make sure it respects the value of your products and what your users would expect. Now OS X is different because in the model of OS X, apps can quit and they do, and that's exactly what we want you to do if the receipt's invalid. Every time. Always Exit 173.
The App Store will handle showing the UI for you depending on various conditions of why that receipt may still be invalid. For example, if the receipt just plain appears to be invalid or perhaps it looks as though it might have been forged, we'll present UI telling the user please go and re-download this app from the purchases page, which if they have really bought it, should get them a new copy with a new receipt. Or if you've opted into the Volume Purchase Program and they had a license but it's been revoked and they're expired, we tell them that, too, and encourage them to go and buy their own copy, but on OS X, let us drive the UI, always just Exit 173.
[ Pause ]
Now let's talk about the test environment. As powerful as this is to protecting your revenue, making sure you get paid, that your app's not being ripped off, retain those loyal customers that are happy that they've paid for what they're getting, it's really powerful. The receipt's the foundation upon which you do that, but a bug in this part of your code could have some really bad consequences. A bug in this part of your code could potentially give away assets and content that maybe the user hasn't paid for, but even worse, a bug in this part of your code could lock customers out of things they really actually have paid for.
We all know exactly how they're going to tell you about that. So Apple gives you the test environment. The test environment is like a replica of the App Store that you can use to make transactions, get receipts, use In-App Purchases, without actually exchanging any money. The test environment allows you to test your code in this area for receipt validation, as well as In-App Purchases, really thoroughly.
You can see how your app has with no receipt, with a receipt, when it's invalid, when it's refreshes, all those sorts of code parts, and there's also APIs in Store Kit that allow you to get a Volume Purchase Program license in various states of valid, revoked, expired, so you can really thoroughly test this, and please do, because it's crucial that when a user pays money for your content and your app, that they get it, and that a bug doesn't prevent them, so the test environment is exactly what you use to verify that this works before you submit your code. So how in iOS? Run the device from Xcode; use the Shake It API to get yourself a receipt. Make sure your app is development signed, though. That's how the iOS App Store knows to route your request to the test environment.
OS X developers. A little bit different. Build your app in Xcode, run it from find to first. Why? Because if you Exit 173 while you're debugging an Xcode, Xcode doesn't care. So you've got to run your app from Finder to get that initial receipt, because when you Exit 173 after being launched from Finder, the App Store in OS X sees it, we get you a new receipt, but make sure you're development signed because that's how, again, the App Store in OS X knows to route that request to the test environment, and just in case you missed the very deliberate repetition on those last two slides, your app must be signed with your development certificate to use the test environment. It's the only way the OS knows to route your request for a receipt and also to do In-App Purchases to the test environment, and not the production store.
Also another common gotcha with this is, sign-out of the App Store with your production account, because that production account that you use, your Apple ID that you use to buy songs and movies and apps, that won't work in a test environment. The test environment only works with test environment accounts that you set up for your app only.
Now one last word, and that's on the app submission review process that we all know and love. When you're developing your app, you're using your development certificate, building and compiling and code signing with that certificate, and that allows you to use the test environment. When you submit your app to the store to get it sold, you're assigning that with your distribution certificate, your production certificate, which allows the app to then work with the production store to make sure that you get paid when you app is purchased and when In-App Purchases are made, but app review is a little different and it's a really important distinction, especially when you go to implement receipt validation. The app reviewers are actually testing your production site, ready to go into the store binary, but against the test environment, so your production signed out will see test environment receipts.
So don't invalidate them, just because you think I'm production signed and I should never be seeing the test environment. That means the reviewers won't be able to test your app, won't be able to confirm your receipt validation works and your In-App Purchases work, and it's an express to the rejection queue.
In summary, to make sure that your digital sales are protected, that your revenue is secured, and the value of your product is maintained and that your products can't be stolen, cracked, and pirated, verify and inspect the receipts. Now on iOS 7, just like on OS X, you can do this on device and you can do it server-to-server as well, for servers that are issuing content. But choose a model that suits you.
Remember that long gamut of options that you've got available, from the third-party libraries that are ready to go, to rolling your own with some help from examples and samples, to looking at the technical specs and writing your own code from scratch, the point you arrive at on that spectrum should speak to the value of your products and the level of security you want in your receipt model enforcement.
Also, don't forget that it's important to choose a way of doing the receipt validation that's a little bit unique, because if everyone chose the exact same way to do receipt validation, then it would be all too easy for those evil folks with the less honorable intentions to go and find those really common code segments and work around them. So make sure you do things a little bit special, a little bit unique to your app, but no matter how you do it, use the test environment, and to use that you've got to be development signed, using your test environment accounts.
Now for more information, you can contact our excellent evangelist Paul Marcus. We have documentation that we're updating for iOS and OS X available online and that's the receipt validation programming guide, and of course there's the very active Apple developer forum as well, where you're welcome to ask all manner of questions about receipt validations, Store Kit, In-App Purchases, whatever you need. Thank you.
[ Applause ]
[ Silence ]