dooboolab-community / react-native-iap

In App Purchase module for React Native!
https://react-native-iap.dooboolab.com
MIT License
2.81k stars 641 forks source link

Getting 21002 from Apple when verifying transactionReceipt #2436

Open AaronCCWong opened 1 year ago

AaronCCWong commented 1 year ago

Please use the Discussion board if you want to get some help. Please use issues to report bugs.

Description

Getting { 'status': 21002 } responses when calling /verifyReceipt with transactionReceipt.

Expected Behavior

/verifyReceipt should work.

Environment:

To Reproduce Steps to reproduce the behavior:

The sequence flow I use is as follows:

  1. requestSubscription on button click
  2. purchaseUpdatedListener gets triggered with a purchase object
  3. I call validateReceipt which is a method that sends the following to my web server:
    {
        receipt: purchase.transactionReceipt,
        platform: Platform.OS,
        subscriptionId: purchase.productId,
        token: purchase.purchaseToken
    }
  4. My web server makes a call to /verifyReceipt with the following request body:
    {
    "receipt-data": transactionReceipt,
      "password": SECRET
      "exclude-old-transactions": true,
    }
  5. Apple responds with { "status": 21002 }.

This worked until recently when I upgraded expo, react native and react-native-iap.

midhunevolvier commented 1 year ago

same problem here @andresesfm

andresesfm commented 1 year ago

Check the receipt is properly encoder in base 64

AaronCCWong commented 1 year ago

This is a value that is returned through this library. That is, we get it from the purchase parameter of purchaseUpdateListener. If that returns a string that isn't properly base64 encoded, is there anything we can do on our end to make sure that it is?

nightmre789 commented 1 year ago

@andresesfm Experiencing this same issue. The value in currentPurchase.transactionReceipt is malformed. We are receiving this value from the library itself, so it should be in proper Base64 format.

I am currently using requestSubscription and then using currentPurchase to send a validation request to my apple sandbox /verifyRequest using transactionReceipt. My subscription plans are loaded from Storekit config.

andresesfm commented 1 year ago

Look at ios/RNIapIos.swift:322. It is bein encoded there using base64EncodedString. Maybe play around with removing/changing the options argument

numsu commented 1 year ago

Having the same issue. Value returned by this library and passed on to Apple as-is in the backend.

midhunevolvier commented 1 year ago

Does anyone have the solution? I am stuck.

numsu commented 1 year ago

I decided to change my implementation because of this. Now I am sending the appAccountToken which contains an uuid of the purchase to Apple and verifying that the purchase is successful by verifying that in the S2S payload. Not handling receipts at all.

ToyboxZach commented 1 year ago

This is also happening to me, has anyone gotten a solution? @numsu do you have any details on how you were able to get that information?

numsu commented 1 year ago

This is also happening to me, has anyone gotten a solution? @numsu do you have any details on how you were able to get that information?

  1. Generate an unique identifier on the client or your backend server once the user presses the "Buy" button and store it to your DB
  2. Set the generated identifier to the appAuthToken field with this library
  3. If the user completed the purchase, you will receive a S2S notification from Apple, if you have set it up. The payload will include your appAuthToken. Set the status of the purchase based on this notification
MTPL0005-AbhishekDube commented 1 year ago

I was also facing the issue earlier but it was solved by making some changes to the way I was passing the parameter to the validateReceiptIos. before I was passing it as "RNIap.validateReceiptIos(receiptBody, true)". but now I have made the changes and called it like this "RNIap.validateReceiptIos({receiptBody: receiptBody, isTest: true})" and It started working properly .

Fairbrook commented 1 year ago

This is also happening to me, has anyone gotten a solution? @numsu do you have any details on how you were able to get that information?

1. Generate an unique identifier on the client or your backend server once the user presses the "Buy" button and store it to your DB

2. Set the generated identifier to the appAuthToken field with this library

3. If the user completed the purchase, you will receive a S2S notification from Apple, if you have set it up. The payload will include your appAuthToken. Set the status of the purchase based on this notification

Sorry to bother @numsu but I cannot seem to get Apple Store Server Notifications. The server url never gets called, the setup is alright as i used the test endpoint and the notification arrived properly Do you have any idea what I'm doing wrong?

tony95271 commented 7 months ago

confirm the same issue "react-native-iap": "^12.12.2",

hotaryuzaki commented 6 months ago

confirm the same issue "react-native-iap": "^12.13.0",

hotaryuzaki commented 6 months ago

i think one of the reasons this issue is rising is because the docs are not giving the right suggestions. i solved with this useEffect

  useEffect(() => {
    const subscription = purchaseUpdatedListener((purchase) => {
      // console.log('>>> APP JS useEffect purchaseUpdatedListener', purchase.transactionReceipt);

      const verify = async purchase => {
        const verifyPurchase = await validateReceiptIos({
          receiptBody: { 'receipt-data': purchase.transactionReceipt },
          isTest: true
        });
      }

      verify(purchase);
    });

    return () => {
      subscription.remove();
    };
  }, []);

and another issue is that the name of the functions in the docs is wrong, it took me hours to realize this. validateReceiptIos => in the docs is validateReceiptIOS

and another issue requestPurchaseWithQuantityIOS is undefined which i reported here