iosfirebasenotificationsin-app-subscriptionserver-to-server

Server-side validation of iOS and Android auto-renewable subscriptions using server-to-server notifications and Firebase Cloud Functions


I have successfully implemented subscription validation for Google Play, but I am struggling to understand the validation flow for iOS auto-renewable subscriptions and would like to ask for your help. Here is how high-level logic for Google Play:

New subscription validation

  1. User purchases subscription in the app.
  2. A SubscriptionRequest is created in my Firestore database, which includes the UserID and the token of the transaction.
  3. A cloud function picks up that SubscriptionRequest and queries the relevant Google API using the token to get the subscription details. This is done using the googleapis Node.js libary.
  4. The latest subscription details are saved in Firestore as a Subscription, including the token (as linkedPurchaseToken) and the UserID.
  5. The expiry date of the subscription is evaluated and, if it is not expired, the User in Firebase is updated and the flag hasActiveSubscription is set accordingly (including Google Play identifier of the subscription, e.g. monthly_sub, or annual_sub, and the platform, in this case android).

Google Play Developer notifications

  1. Notification is received via a Pub/Sub cloud function.
  2. The corresponding subscription details will be fetched using the relevant Google API and the token from the notification.
  3. If no Subscription with that token (as linkedPurchaseToken) exists in the database, we'll try to get find the existing Subscription in our database using the linkedPurchaseToken from the subscription details that were fetched in (2).
  4. If still no Subscription can be found in the database, that obviously means that it's a new subscription, which will be handled exclusively via the New subscription validation process described above. The reason for this is that I am otherwise unable to link my UserID and the subscription.
  5. If a Subscription is found, it is updated with the latest details.
  6. The expiry date of the subscription is evaluated and, if it is not expired, the User in Firebase is updated and the flag hasActiveSubscription is set accordingly. [...]

This has been working exceptionally well and robust for quite some time.

As far as I can see the developerPayload, which could be used to pass on, e.g. the UserID, to determine who the subscription belongs to, is deprecated. (Source)

Do you think there is an easier way of doing this, possibly only using Google Play Developer notifications?

I am receiving a notification at every step a subscription changes and I am simply updating my Subscription and hasActiveSubscription flag based on the expiry date. This is working well because I receive a notification at the moment the subscription expires (notification type SUBSCRIPTION_EXPIRED) and at any point the subscription gets extended, for example. (Source)

Is there anything missing in that validation logic or any potential risk?

These two questions so far are only to ensure I am not missing something essential. Again, from my experience this is working quite well.

All that is left for my app (based on Flutter, by the way) to be released on iOS is to implement the validation logic for iOS.

One thing that has made the google validation logic rather easy, is that there is the googleapis library, which essentially is giving me the model classes for all responses, such as the notifications or the subscription details. I have been unable to find something similar for Apple yet and I am not sure there is.

Is there any (official) library that is providing me with similar features as googleapis for Node.js?

For new subscriptions I am currently querying the verifyReceipt endpoint, which seems to be working well. However, Apple does not seem to say anywhere which fields need to be validated exactly, in order to provide users with access within the app. I am following the same logic, meaning: If I do receive a valid receipt from the endpoint and it is not expired, I grant access.

Is that logic sufficient for new subscriptions or am I missing something?

For Google so far I simply stored the subscription details that I received via querying the api, including the UserID and token. This is done mainly for laziness and because the document structure received is rather simple. The Apple responses are much more complex, so I am quite unsure about what to store (and poorly documented, if you ask me), so I am wondering:

Which details do I actually need, for both Google and Apple, especially if I rely on notifications for updating the subscription?

Regarding updates to the subscriptions, I am wondering how to work with server-to-server notifications from Apple.

When exactly are they being send and can I implement the same logic as described above for Android?

As I can't seem to find a good documentation or tutorial for this part:

Do you possibly know any good tutorials for these notifications?

Thank you very much for your support, Matthias


Solution

  • It has been a while since i asked these questions and while technically the questions have not been answered, I would still like to share my solution with everyone.

    The solution I have gone for is simply implementing RevenueCat, who focus on managing in app subscriptions for you, so that there is no need to worry about all those questions anymore.