react-native-iap: iOS Receipt Validation Returns Status 21002
Please use the Discussion board if you want to get some help. Please use issues to report bugs.
Description
On app startup, I want to check if the auto-renewing subscription is still active or not. I’m using the below code:
const isSubscriptionActive = async () => {
if (Platform.OS === 'ios') {
const availablePurchases = await RNIap.getAvailablePurchases();
const sortedAvailablePurchases = availablePurchases.sort(
(a, b) => b.transactionDate - a.transactionDate
);
const latestAvailableReceipt = sortedAvailablePurchases[0].transactionReceipt;
const isTestEnvironment = __DEV__;
const decodedReceipt = await RNIap.validateReceiptIos(
{
'receipt-data': btoa(latestAvailableReceipt),
password: 'MY_SHARED_SECRET',
},
isTestEnvironment
);
console.log("decodedReceipt: ", decodedReceipt);
const { latest_receipt_info: latestReceiptInfo } = decodedReceipt;
console.log("latestReceiptInfo: ", latestReceiptInfo);
const isSubValid = !!latestReceiptInfo.find(receipt => {
const expirationInMilliseconds = Number(receipt.expires_date_ms);
const nowInMilliseconds = Date.now();
return expirationInMilliseconds > nowInMilliseconds;
});
return isSubValid;
}
}
However, the decodedReceipt returns {"status": 21002}
Expected Behavior
Should return the Receipt Info
Screenshots
Environment:
- react-native-iap: 10.1.0
- react-native: 0.67.3
- Platforms (iOS, Android, emulator, simulator, device): iOS - iPhone 12
To Reproduce Steps to reproduce the behavior:
- Make a call to
RNIap.initConnection() - Make a call to
RNIap.getAvailablePurchases()as shown inisSubscriptionActivemethod - You’ll notice the following output in console:
decodedReceipt: {"status": 21002}
latestReceiptInfo: undefined
[Optional] Additional Context
I’m using TypeScript.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 52
PS: I got this fixed. I was testing this for sandbox account and I forgot to pass isTest true.
@liyamahendra you can check apple documentation and based on different status code you can perform actions accordingly you have to do it in app
In order to validate a receipt, it must be purchased through a build in TestFlight.
Any receipts purchased with a build outside TestFlight return a 21002 (either real device or simulator)
@andresesfm check this link Apple Developer Documentation that is not even an issue of the plugin developer have to apply simple checks and he is good to go just read this documentation learn about different status code based on receipt i think this issue need to be closed
@andresesfm can you provide more details did you are successfully be able to subscribe or purchase item through in app purchase if yes than validation thing is not package things actually you have to accept that validation thing is not package does the only just call the apple api and apple servers responed according to your data validations have to be manage by the developers
@iambinodstha you cannot validate receipt without token actually token is base64 string that contains all information related to user package in test the package is only for 5 minutes after that it cycle restarts again
@alihassan143 @andresesfm thanks for the info. I have handled receipt validation in my backend. but the problem now is receipt expires within few hours after I subscribe to the 1 month package.
Here is the JavaScript Code to check Receipt is Expired or not:
If I used enabled storekit 2, how can I validate subscription without purchase token and receipt?
Well, I used the same secret to decode the receipt in the tool above - so I don’t believe its the wrong one.
Hi @andresesfm thank you for looking into this again. I installed the module from cloning your fork and checking the base_64_encoding_options branch.
Test the app but it still returns
{"status": 21002}.Fixed here following the suggestion from SO: https://github.com/dooboolab/react-native-iap/pull/1977